Update from https://crrev.com/304121

Includes DEPS updates and port of
https://codereview.chromium.org/665223004 to accomodate skia API change
on android.

Review URL: https://codereview.chromium.org/723343002
diff --git a/DEPS b/DEPS
index 6eadb5b..58fb063 100644
--- a/DEPS
+++ b/DEPS
@@ -22,27 +22,27 @@
   'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d',
   'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95',
   'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
-  'skia_revision': '7a10fb6bead0f63623307a7ff71b1dd323534a7f',
+  'skia_revision': 'bc97c9378bf8b89cc17280a2a04a5c3a9405e6ab',
   # 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': '11b7b24c91c903ee08b2b6b94f0bbb17b966dd92', # from svn revision 25090
+  'v8_revision': '43ced1bd1528ea8b4d9299d2c8f7c6a81921457b',
   # 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": "657cd684a615da648df6a851a916f11bb6f9a70e",
+  "angle_revision": "560eef1627abdef65f71021b906e57dc609f47fa",
   # 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': '51ca1f25a2ecea34069cb3ff35394dc53b6fd657',
+  'buildtools_revision': 'c27f95bd1d9baaef70c879dea375090dd1496147',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '173f919d0ec99a1a973c9d3a82b474f761d5bce1',
+  'pdfium_revision': '4dc95e74e1acc75f4eab08bc771874cd2a9c3a9b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '03a739d8d2cdc2560531a7446ead0f705409670a',
+  'boringssl_revision': '2f3ba910a2bdb9e7d19e712a827cdc80c8d8c777',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lss
   # and whatever else without interference from each other.
@@ -50,7 +50,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nss
   # and whatever else without interference from each other.
-  'nss_revision': '87b96db4268293187d7cf741907a6d5d1d8080e0',
+  'nss_revision': '258342ecf9c65105189092ef6339dc4e7779a7ae',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -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' + '@' + '740badd5e3e44434a9a47b5d16749daac1e8ea80', # from svn revision 176
+    Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'a24a0e647bb718b3540db89864cf586b12331e82', # from svn revision 182
 
   'src/v8':
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
@@ -126,7 +126,7 @@
    'https://boringssl.googlesource.com/boringssl.git' + '@' +  Var('boringssl_revision'),
 
   'src/tools/gyp':
-    Var('chromium_git') + '/external/gyp.git' + '@' + '487c0b6ae8b44932e45347211bca0e8387718436', # from svn revision 1998
+    Var('chromium_git') + '/external/gyp.git' + '@' + 'b13d8f243da15ded051e87e663c4f2c2fcc5804c', # from svn revision 1994
 }
 
 
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
index 510c3d3..d9ff4c5 100644
--- a/base/allocator/BUILD.gn
+++ b/base/allocator/BUILD.gn
@@ -37,7 +37,7 @@
   }
 }
 
-if (!is_android) {
+if (use_allocator == "tcmalloc") {
   # tcmalloc currently won't compile on Android.
   source_set("tcmalloc") {
     tcmalloc_dir = "//third_party/tcmalloc/chromium"
diff --git a/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
index 10f8d55..fd3dc5a 100644
--- a/base/android/java/src/org/chromium/base/SystemMessageHandler.java
+++ b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
@@ -5,12 +5,9 @@
 package org.chromium.base;
 
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
-import android.os.MessageQueue;
 import android.util.Log;
 
-import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
@@ -25,23 +22,31 @@
     private long mMessagePumpDelegateNative = 0;
     private long mDelayedScheduledTimeTicks = 0;
 
-    // The following members are used to detect and trace the presence of sync
-    // barriers in Android's MessageQueue. Note that this detection is
-    // experimental, temporary and intended only for diagnostic purposes.
-    private MessageQueue mMessageQueue;
-    private Field mMessageQueueMessageField;
-    private Field mMessageTargetField;
-    private boolean mQueueHasSyncBarrier;
-    private long mSyncBarrierTraceId;
+    // Reflected API for marking a message as asynchronous. This is a workaround
+    // to provide fair Chromium task dispatch when served by the Android UI
+    // thread's Looper, avoiding stalls when the Looper has a sync barrier.
+    // Note: Use of this API is experimental and likely to evolve in the future.
+    private Method mMessageMethodSetAsynchronous;
 
     private SystemMessageHandler(long messagePumpDelegateNative) {
         mMessagePumpDelegateNative = messagePumpDelegateNative;
-        tryEnableSyncBarrierDetection();
+
+        try {
+            Class<?> messageClass = Class.forName("android.os.Message");
+            mMessageMethodSetAsynchronous = messageClass.getMethod(
+                    "setAsynchronous", new Class[]{boolean.class});
+        } catch (ClassNotFoundException e) {
+            Log.e(TAG, "Failed to find android.os.Message class:" + e);
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "Failed to load Message.setAsynchronous method:" + e);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Exception while loading Message.setAsynchronous method: " + e);
+        }
+
     }
 
     @Override
     public void handleMessage(Message msg) {
-        updateWhetherQueueHasBlockingSyncBarrier();
         if (msg.what == DELAYED_SCHEDULED_WORK) {
             mDelayedScheduledTimeTicks = 0;
         }
@@ -51,9 +56,7 @@
     @SuppressWarnings("unused")
     @CalledByNative
     private void scheduleWork() {
-        updateWhetherQueueHasBlockingSyncBarrier();
-        if (mQueueHasSyncBarrier) TraceEvent.instant("SystemMessageHandler:immediateWorkBlocked");
-        sendEmptyMessage(SCHEDULED_WORK);
+        sendMessage(obtainAsyncMessage(SCHEDULED_WORK));
     }
 
     @SuppressWarnings("unused")
@@ -63,97 +66,39 @@
             removeMessages(DELAYED_SCHEDULED_WORK);
         }
         mDelayedScheduledTimeTicks = delayedTimeTicks;
-        updateWhetherQueueHasBlockingSyncBarrier();
-        if (mQueueHasSyncBarrier) TraceEvent.instant("SystemMessageHandler:delayedWorkBlocked");
-        sendEmptyMessageDelayed(DELAYED_SCHEDULED_WORK, millis);
+        sendMessageDelayed(obtainAsyncMessage(DELAYED_SCHEDULED_WORK), millis);
     }
 
     @SuppressWarnings("unused")
     @CalledByNative
     private void removeAllPendingMessages() {
-        updateWhetherQueueHasBlockingSyncBarrier();
         removeMessages(SCHEDULED_WORK);
         removeMessages(DELAYED_SCHEDULED_WORK);
     }
 
-    private void updateWhetherQueueHasBlockingSyncBarrier() {
-        if (mMessageQueue == null) return;
-        // As barrier detection is only used for tracing, early out when tracing
-        // is disabled to avoid any potential performance penalties.
-        if (!TraceEvent.enabled()) {
-            mQueueHasSyncBarrier = false;
-            return;
+    private Message obtainAsyncMessage(int what) {
+        Message msg = Message.obtain();
+        msg.what = what;
+        if (mMessageMethodSetAsynchronous != null) {
+            // If invocation fails, assume this is indicative of future
+            // failures, and avoid log spam by nulling the reflected method.
+            try {
+                mMessageMethodSetAsynchronous.invoke(msg, true);
+            } catch (IllegalAccessException e) {
+                Log.e(TAG, "Illegal access to asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Illegal argument for asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            } catch (InvocationTargetException e) {
+                Log.e(TAG, "Invocation exception during asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Runtime exception during asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            }
         }
-        Message queueHead = (Message) getField(mMessageQueue, mMessageQueueMessageField);
-        setqueueHasSyncBarrier(isSyncBarrierMessage(queueHead));
-    }
-
-    private boolean isSyncBarrierMessage(Message message) {
-        if (message == null) return false;
-        // Sync barrier messages have null targets.
-        return getField(message, mMessageTargetField) == null;
-    }
-
-    private void tryEnableSyncBarrierDetection() {
-        assert mMessageQueue == null;
-
-        boolean success = false;
-        try {
-            Method getQueueMethod = Looper.class.getMethod("getQueue", new Class[]{});
-            mMessageQueue = (MessageQueue) getQueueMethod.invoke(getLooper());
-
-            mMessageQueueMessageField = mMessageQueue.getClass().getDeclaredField("mMessages");
-            mMessageQueueMessageField.setAccessible(true);
-
-            mMessageTargetField = Message.class.getDeclaredField("target");
-            mMessageTargetField.setAccessible(true);
-
-            mSyncBarrierTraceId = hashCode();
-
-            success = true;
-        } catch (NoSuchMethodException e) {
-            Log.e(TAG, "Failed to load method: " + e);
-        } catch (NoSuchFieldException e) {
-            Log.e(TAG, "Failed to load field: " + e);
-        } catch (InvocationTargetException e) {
-            Log.e(TAG, "Failed invocation: " + e);
-        } catch (IllegalAccessException e) {
-            Log.e(TAG, "Illegal access to reflected invocation: " + e);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Illegal argument to reflected invocation: " + e);
-        } catch (RuntimeException e) {
-            Log.e(TAG, e.toString());
-        } finally {
-            if (!success) disableSyncBarrierDetection();
-        }
-    }
-
-    private void disableSyncBarrierDetection() {
-        Log.e(TAG, "Unexpected error with sync barrier detection, disabling.");
-        mMessageQueue = null;
-        mMessageQueueMessageField = null;
-        mMessageTargetField = null;
-        setqueueHasSyncBarrier(false);
-    }
-
-    private void setqueueHasSyncBarrier(boolean queueHasSyncBarrier) {
-        if (queueHasSyncBarrier == mQueueHasSyncBarrier) return;
-        mQueueHasSyncBarrier = queueHasSyncBarrier;
-        if (mQueueHasSyncBarrier) {
-            TraceEvent.startAsync("SyncBarrier", mSyncBarrierTraceId);
-        } else {
-            TraceEvent.finishAsync("SyncBarrier", mSyncBarrierTraceId);
-        }
-    }
-
-    private Object getField(Object object, Field field) {
-        try {
-            return field.get(object);
-        } catch (IllegalAccessException e) {
-            Log.e(TAG, "Failed field access: " + e);
-            disableSyncBarrierDetection();
-        }
-        return null;
+        return msg;
     }
 
     @CalledByNative
diff --git a/base/android/linker/linker_jni.cc b/base/android/linker/linker_jni.cc
index b3ed651..1a11639 100644
--- a/base/android/linker/linker_jni.cc
+++ b/base/android/linker/linker_jni.cc
@@ -664,7 +664,7 @@
            __FUNCTION__, library_name_c_str, apkfile_name_c_str);
   jboolean mappable = crazy_linker_check_library_is_mappable_in_zip_file(
       apkfile_name_c_str, library_name_c_str) == CRAZY_STATUS_SUCCESS;
-  LOG_INFO("%s: %s\n", __FUNCTION__, aligned ? "Aligned" : "NOT aligned");
+  LOG_INFO("%s: %s\n", __FUNCTION__, mappable ? "Mappable" : "NOT mappable");
 
   return mappable;
 }
diff --git a/base/base64.h b/base/base64.h
index 43d8f76..def9b67 100644
--- a/base/base64.h
+++ b/base/base64.h
@@ -12,11 +12,12 @@
 
 namespace base {
 
-// Encodes the input string in base64.
+// Encodes the input string in base64. The encoding can be done in-place.
 BASE_EXPORT void Base64Encode(const StringPiece& input, std::string* output);
 
 // Decodes the base64 input string.  Returns true if successful and false
-// otherwise.  The output string is only modified if successful.
+// otherwise. The output string is only modified if successful. The decoding can
+// be done in-place.
 BASE_EXPORT bool Base64Decode(const StringPiece& input, std::string* output);
 
 }  // namespace base
diff --git a/base/base64_unittest.cc b/base/base64_unittest.cc
index 9b23194..91651f4 100644
--- a/base/base64_unittest.cc
+++ b/base/base64_unittest.cc
@@ -24,4 +24,17 @@
   EXPECT_EQ(kText, decoded);
 }
 
+TEST(Base64Test, InPlace) {
+  const std::string kText = "hello world";
+  const std::string kBase64Text = "aGVsbG8gd29ybGQ=";
+  std::string text(kText);
+
+  Base64Encode(text, &text);
+  EXPECT_EQ(kBase64Text, text);
+
+  bool ok = Base64Decode(text, &text);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(text, kText);
+}
+
 }  // namespace base
diff --git a/base/files/file.h b/base/files/file.h
index 4110d51..7b6366c 100644
--- a/base/files/file.h
+++ b/base/files/file.h
@@ -19,6 +19,7 @@
 #include "base/base_export.h"
 #include "base/basictypes.h"
 #include "base/files/scoped_file.h"
+#include "base/gtest_prod_util.h"
 #include "base/move.h"
 #include "base/time/time.h"
 
@@ -26,6 +27,8 @@
 #include "base/win/scoped_handle.h"
 #endif
 
+FORWARD_DECLARE_TEST(FileTest, MemoryCorruption);
+
 namespace base {
 
 class FilePath;
@@ -296,12 +299,59 @@
   static std::string ErrorToString(Error error);
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
+
+#if defined(OS_POSIX)
+  // Encloses a single ScopedFD, saving a cheap tamper resistent memory checksum
+  // alongside it. This checksum is validated at every access, allowing early
+  // detection of memory corruption.
+
+  // TODO(gavinp): This is in place temporarily to help us debug
+  // https://crbug.com/424562 , which can't be reproduced in valgrind. Remove
+  // this code after we have fixed this issue.
+  class MemoryCheckingScopedFD {
+   public:
+    MemoryCheckingScopedFD();
+    MemoryCheckingScopedFD(int fd);
+    ~MemoryCheckingScopedFD();
+
+    bool is_valid() const { Check(); return file_.is_valid(); }
+    int get() const { Check(); return file_.get(); }
+
+    void reset() { Check(); file_.reset(); UpdateChecksum(); }
+    void reset(int fd) { Check(); file_.reset(fd); UpdateChecksum(); }
+    int release() {
+      Check();
+      int fd = file_.release();
+      UpdateChecksum();
+      return fd;
+    }
+
+   private:
+    FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
+
+    // Computes the checksum for the current value of |file_|. Returns via an
+    // out parameter to guard against implicit conversions of unsigned integral
+    // types.
+    void ComputeMemoryChecksum(unsigned int* out_checksum) const;
+
+    // Confirms that the current |file_| and |file_memory_checksum_| agree,
+    // failing a CHECK if they do not.
+    void Check() const;
+
+    void UpdateChecksum();
+
+    ScopedFD file_;
+    unsigned int file_memory_checksum_;
+  };
+#endif
+
   void SetPlatformFile(PlatformFile file);
 
 #if defined(OS_WIN)
   win::ScopedHandle file_;
 #elif defined(OS_POSIX)
-  ScopedFD file_;
+  MemoryCheckingScopedFD file_;
 #endif
 
   Error error_details_;
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index 43684b5..3d229e4 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -483,6 +483,49 @@
   }
 }
 
+File::MemoryCheckingScopedFD::MemoryCheckingScopedFD() {
+  UpdateChecksum();
+}
+
+File::MemoryCheckingScopedFD::MemoryCheckingScopedFD(int fd) : file_(fd) {
+  UpdateChecksum();
+}
+
+File::MemoryCheckingScopedFD::~MemoryCheckingScopedFD() {}
+
+// static
+void File::MemoryCheckingScopedFD::ComputeMemoryChecksum(
+    unsigned int* out_checksum) const {
+  // Use a single iteration of a linear congruentional generator (lcg) to
+  // provide a cheap checksum unlikely to be accidentally matched by a random
+  // memory corruption.
+
+  // By choosing constants that satisfy the Hull-Duebell Theorem on lcg cycle
+  // length, we insure that each distinct fd value maps to a distinct checksum,
+  // which maximises the utility of our checksum.
+
+  // This code uses "unsigned int" throughout for its defined modular semantics,
+  // which implicitly gives us a divisor that is a power of two.
+
+  const unsigned int kMultiplier = 13035 * 4 + 1;
+  COMPILE_ASSERT(((kMultiplier - 1) & 3) == 0, pred_must_be_multiple_of_four);
+  const unsigned int kIncrement = 1595649551;
+  COMPILE_ASSERT(kIncrement & 1, must_be_coprime_to_powers_of_two);
+
+  *out_checksum =
+      static_cast<unsigned int>(file_.get()) * kMultiplier + kIncrement;
+}
+
+void File::MemoryCheckingScopedFD::Check() const {
+  unsigned int computed_checksum;
+  ComputeMemoryChecksum(&computed_checksum);
+  CHECK_EQ(file_memory_checksum_, computed_checksum) << "corrupted fd memory";
+}
+
+void File::MemoryCheckingScopedFD::UpdateChecksum() {
+  ComputeMemoryChecksum(&file_memory_checksum_);
+}
+
 void File::SetPlatformFile(PlatformFile file) {
   DCHECK(!file_.is_valid());
   file_.reset(file);
diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc
index 6616f6a..3bc2db6 100644
--- a/base/files/file_unittest.cc
+++ b/base/files/file_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -466,3 +467,71 @@
   EXPECT_EQ(0, info.size);
 }
 #endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX) && defined(GTEST_HAS_DEATH_TEST)
+TEST(FileTest, MemoryCorruption) {
+  {
+    // Test that changing the checksum value is detected.
+    base::File file;
+    EXPECT_NE(file.file_.file_memory_checksum_,
+              implicit_cast<unsigned int>(file.GetPlatformFile()));
+    file.file_.file_memory_checksum_ = file.GetPlatformFile();
+    EXPECT_DEATH(file.IsValid(), "");
+
+    file.file_.UpdateChecksum();  // Do not crash on File::~File().
+  }
+
+  {
+    // Test that changing the file descriptor value is detected.
+    base::File file;
+    file.file_.file_.reset(17);
+    EXPECT_DEATH(file.IsValid(), "");
+
+    // Do not crash on File::~File().
+    ignore_result(file.file_.file_.release());
+    file.file_.UpdateChecksum();
+  }
+
+  {
+    // Test that GetPlatformFile() checks for corruption.
+    base::File file;
+    file.file_.file_memory_checksum_ = file.GetPlatformFile();
+    EXPECT_DEATH(file.GetPlatformFile(), "");
+
+    file.file_.UpdateChecksum();  // Do not crash on File::~File().
+  }
+
+  {
+    // Test that the base::File destructor checks for corruption.
+    scoped_ptr<base::File> file(new File());
+    file->file_.file_memory_checksum_ = file->GetPlatformFile();
+    EXPECT_DEATH(file.reset(), "");
+
+    // Do not crash on this thread's destructor call.
+    file->file_.UpdateChecksum();
+  }
+
+  {
+    // Test that the base::File constructor checks for corruption.
+    base::File file;
+    file.file_.file_memory_checksum_ = file.GetPlatformFile();
+    EXPECT_DEATH(File f(file.Pass()), "");
+
+    file.file_.UpdateChecksum();  // Do not crash on File::~File().
+  }
+
+  {
+    // Test that doing IO checks for corruption.
+    base::File file;
+    file.file_.file_.reset(17);  // A fake open FD value.
+
+    EXPECT_DEATH(file.Seek(File::FROM_BEGIN, 0), "");
+    EXPECT_DEATH(file.Read(0, NULL, 0), "");
+    EXPECT_DEATH(file.ReadAtCurrentPos(NULL, 0), "");
+    EXPECT_DEATH(file.Write(0, NULL, 0), "");
+
+    ignore_result(file.file_.file_.release());
+    file.file_.UpdateChecksum();
+  }
+}
+#endif  // defined(OS_POSIX)
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index b8c0eeb..0bf41a5 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -28,8 +28,6 @@
 #include <glib.h>  // for g_get_home_dir()
 #endif
 
-#include <fstream>
-
 #include "base/basictypes.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
@@ -428,7 +426,7 @@
 bool SetPosixFilePermissions(const FilePath& path,
                              int mode) {
   ThreadRestrictions::AssertIOAllowed();
-  DCHECK((mode & ~FILE_PERMISSION_MASK) == 0);
+  DCHECK_EQ(mode & ~FILE_PERMISSION_MASK, 0);
 
   // Calls stat() so that we can preserve the higher bits like S_ISGID.
   stat_wrapper_t stat_buf;
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index ad5a9d5..e17d450 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.cc
@@ -31,7 +31,7 @@
     "Dictionary keys must be quoted.";
 
 JSONReader::JSONReader()
-    : parser_(new internal::JSONParser(JSON_PARSE_RFC)) {
+    : JSONReader(JSON_PARSE_RFC) {
 }
 
 JSONReader::JSONReader(int options)
diff --git a/base/mac/bind_objc_block.h b/base/mac/bind_objc_block.h
index 9deb2d2..c31f26e 100644
--- a/base/mac/bind_objc_block.h
+++ b/base/mac/bind_objc_block.h
@@ -21,51 +21,32 @@
 //     BindBlock(^(const std::string& arg0, const std::string& arg1) {
 //         ...
 //     });
+//
+// These variadic templates will accommodate any number of arguments, however
+// the underlying templates in bind_internal.h and callback.h are limited to
+// seven total arguments, and the bound block itself is used as one of these
+// arguments, so functionally the templates are limited to binding blocks with
+// zero through six arguments.
 
 namespace base {
 
 namespace internal {
 
-// Helper functions to run the block contained in the parameter.
-template<typename R>
-R RunBlock(base::mac::ScopedBlock<R(^)()> block) {
-  R(^extracted_block)() = block.get();
-  return extracted_block();
-}
-
-template<typename R, typename A1>
-R RunBlock(base::mac::ScopedBlock<R(^)(A1)> block, A1 a) {
-  R(^extracted_block)(A1) = block.get();
-  return extracted_block(a);
-}
-
-template<typename R, typename A1, typename A2>
-R RunBlock(base::mac::ScopedBlock<R(^)(A1, A2)> block, A1 a, A2 b) {
-  R(^extracted_block)(A1, A2) = block.get();
-  return extracted_block(a, b);
+// Helper function to run the block contained in the parameter.
+template<typename R, typename... Args>
+R RunBlock(base::mac::ScopedBlock<R(^)(Args...)> block, Args... args) {
+  R(^extracted_block)(Args...) = block.get();
+  return extracted_block(args...);
 }
 
 }  // namespace internal
 
-// Construct a callback with no argument from an objective-C block.
-template<typename R>
-base::Callback<R(void)> BindBlock(R(^block)()) {
-  return base::Bind(&base::internal::RunBlock<R>,
-                    base::mac::ScopedBlock<R(^)()>(Block_copy(block)));
-}
-
-// Construct a callback with one argument from an objective-C block.
-template<typename R, typename A1>
-base::Callback<R(A1)> BindBlock(R(^block)(A1)) {
-  return base::Bind(&base::internal::RunBlock<R, A1>,
-                    base::mac::ScopedBlock<R(^)(A1)>(Block_copy(block)));
-}
-
-// Construct a callback with two arguments from an objective-C block.
-template<typename R, typename A1, typename A2>
-base::Callback<R(A1, A2)> BindBlock(R(^block)(A1, A2)) {
-  return base::Bind(&base::internal::RunBlock<R, A1, A2>,
-                    base::mac::ScopedBlock<R(^)(A1, A2)>(Block_copy(block)));
+// Construct a callback from an objective-C block with up to six arguments (see
+// note above).
+template<typename R, typename... Args>
+base::Callback<R(Args...)> BindBlock(R(^block)(Args...)) {
+  return base::Bind(&base::internal::RunBlock<R, Args...>,
+                    base::mac::ScopedBlock<R(^)(Args...)>(Block_copy(block)));
 }
 
 }  // namespace base
diff --git a/base/mac/bind_objc_block_unittest.mm b/base/mac/bind_objc_block_unittest.mm
index c72fd4a..5d15eba 100644
--- a/base/mac/bind_objc_block_unittest.mm
+++ b/base/mac/bind_objc_block_unittest.mm
@@ -64,4 +64,36 @@
   EXPECT_EQ(result, "fortytwo");
 }
 
+TEST(BindObjcBlockTest, TestThreeArguments) {
+  std::string result;
+  std::string* ptr = &result;
+  base::Callback<void(const std::string&,
+                      const std::string&,
+                      const std::string&)> c =
+      base::BindBlock(^(const std::string& a,
+                        const std::string& b,
+                        const std::string& c) {
+          *ptr = a + b + c;
+      });
+  c.Run("six", "times", "nine");
+  EXPECT_EQ(result, "sixtimesnine");
+}
+
+TEST(BindObjcBlockTest, TestSixArguments) {
+  std::string result1;
+  std::string* ptr = &result1;
+  int result2;
+  int* ptr2 = &result2;
+  base::Callback<void(int, int, const std::string&, const std::string&,
+                      int, const std::string&)> c =
+      base::BindBlock(^(int a, int b, const std::string& c,
+                        const std::string& d, int e, const std::string& f) {
+          *ptr = c + d + f;
+          *ptr2 = a + b + e;
+      });
+  c.Run(1, 2, "infinite", "improbability", 3, "drive");
+  EXPECT_EQ(result1, "infiniteimprobabilitydrive");
+  EXPECT_EQ(result2, 6);
+}
+
 }  // namespace
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
index 3f169a7..ca7cfbf 100644
--- a/base/memory/scoped_ptr_unittest.cc
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -669,7 +669,9 @@
 TEST(ScopedPtrTest, SelfResetWithCustomDeleterOptOut) {
   // A custom deleter should be able to opt out of self-reset abort behavior.
   struct NoOpDeleter {
+#if !defined(NDEBUG)
     typedef void AllowSelfReset;
+#endif
     inline void operator()(int*) {}
   };
   scoped_ptr<int> owner(new int);
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 01402d0..2f4a03c 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -106,9 +106,11 @@
 typedef MessagePumpLibevent MessagePumpForIO;
 #endif
 
+#if !defined(OS_NACL_SFI)
 MessagePumpForIO* ToPumpIO(MessagePump* pump) {
   return static_cast<MessagePumpForIO*>(pump);
 }
+#endif  // !defined(OS_NACL_SFI)
 
 }  // namespace
 
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 5ed9d9e..43e7462 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -286,7 +286,7 @@
             base::HistogramBase::kUmaTargetedHistogramFlag))
 
 // The samples should always be strictly less than |boundary_value|.  For more
-// details, see the comment for the |HISTOGRAM_ENUMERATION| macro, above.
+// details, see the comment for the |LOCAL_HISTOGRAM_ENUMERATION| macro, above.
 #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
     HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
         base::HistogramBase::kUmaTargetedHistogramFlag)
diff --git a/base/observer_list.h b/base/observer_list.h
index c77ec15..ef45269 100644
--- a/base/observer_list.h
+++ b/base/observer_list.h
@@ -100,7 +100,8 @@
   // Remove an observer from the list if it is in the list.
   void RemoveObserver(ObserverType* obs);
 
-  bool HasObserver(ObserverType* observer) const;
+  // Determine whether a particular observer is in the list.
+  bool HasObserver(const ObserverType* observer) const;
 
   void Clear();
 
@@ -176,7 +177,8 @@
 }
 
 template <class ObserverType>
-bool ObserverListBase<ObserverType>::HasObserver(ObserverType* observer) const {
+bool ObserverListBase<ObserverType>::HasObserver(
+    const ObserverType* observer) const {
   for (size_t i = 0; i < observers_.size(); ++i) {
     if (observers_[i] == observer)
       return true;
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
index 11f59be..65ef934 100644
--- a/base/observer_list_unittest.cc
+++ b/base/observer_list_unittest.cc
@@ -182,6 +182,9 @@
   observer_list.AddObserver(&a);
   observer_list.AddObserver(&b);
 
+  EXPECT_TRUE(observer_list.HasObserver(&a));
+  EXPECT_FALSE(observer_list.HasObserver(&c));
+
   FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
 
   observer_list.AddObserver(&evil);
diff --git a/base/profiler/scoped_profile.cc b/base/profiler/scoped_profile.cc
index 8b0ae59..4f8bc2d 100644
--- a/base/profiler/scoped_profile.cc
+++ b/base/profiler/scoped_profile.cc
@@ -11,15 +11,6 @@
 namespace tracked_objects {
 
 
-ScopedProfile::ScopedProfile(const Location& location)
-    : birth_(ThreadData::TallyABirthIfActive(location)) {
-  if (!birth_)
-    return;
-
-  ThreadData::PrepareForStartOfRun(birth_);
-  stopwatch_.Start();
-}
-
 ScopedProfile::ScopedProfile(const Location& location, Mode mode)
     : birth_(NULL) {
   if (mode == DISABLED)
diff --git a/base/profiler/scoped_profile.h b/base/profiler/scoped_profile.h
index 6a76486..c1e2830 100644
--- a/base/profiler/scoped_profile.h
+++ b/base/profiler/scoped_profile.h
@@ -25,10 +25,10 @@
 // Defines the containing scope as a profiled region. This allows developers to
 // profile their code and see results on their about:profiler page, as well as
 // on the UMA dashboard.
-#define TRACK_RUN_IN_THIS_SCOPED_REGION(dispatch_function_name)                \
-    ::tracked_objects::ScopedProfile LINE_BASED_VARIABLE_NAME_FOR_PROFILING(   \
-        FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name))
-
+#define TRACK_RUN_IN_THIS_SCOPED_REGION(dispatch_function_name)            \
+  ::tracked_objects::ScopedProfile LINE_BASED_VARIABLE_NAME_FOR_PROFILING( \
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name),           \
+      ::tracked_objects::ScopedProfile::ENABLED)
 
 namespace tracked_objects {
 class Births;
@@ -42,8 +42,6 @@
     ENABLED    // Create and tally a task.
   };
 
-  // TODO(vadimt): Remove this constructor.
-  explicit ScopedProfile(const Location& location);
   ScopedProfile(const Location& location, Mode mode);
   ~ScopedProfile();
 
diff --git a/base/profiler/scoped_tracker.cc b/base/profiler/scoped_tracker.cc
index 1d4f0bf..26b17c0 100644
--- a/base/profiler/scoped_tracker.cc
+++ b/base/profiler/scoped_tracker.cc
@@ -15,7 +15,7 @@
 // Executes |callback|, augmenting it with provided |location|.
 void ExecuteAndTrackCallback(const Location& location,
                              const base::Closure& callback) {
-  ScopedProfile tracking_profile(location);
+  ScopedProfile tracking_profile(location, ScopedProfile::ENABLED);
   callback.Run();
 }
 
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index 44846a1..a49e777 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -479,15 +479,6 @@
       fflush(stdout);
       force_single_process = true;
     }
-
-    if (RunningOnValgrind()) {
-      fprintf(stdout,
-              "Valgrind detected, switching to single process mode.\n"
-              "Pass --test-launcher-debug-launcher to valgrind the launcher "
-              "itself.\n");
-      fflush(stdout);
-      force_single_process = true;
-    }
   }
 
   if (CommandLine::ForCurrentProcess()->HasSwitch(kGTestHelpFlag) ||
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
index d9e2bd9..d97a3f4 100644
--- a/base/threading/platform_thread_linux.cc
+++ b/base/threading/platform_thread_linux.cc
@@ -27,6 +27,7 @@
 
 namespace {
 
+#if !defined(OS_NACL)
 int ThreadNiceValue(ThreadPriority priority) {
   switch (priority) {
     case kThreadPriority_RealtimeAudio:
@@ -42,6 +43,7 @@
       return 0;
   }
 }
+#endif  // !defined(OS_NACL)
 
 }  // namespace
 
diff --git a/base/time/time.h b/base/time/time.h
index 641f465..9cb007e 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -232,6 +232,10 @@
   static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
                                              kMicrosecondsPerSecond;
 
+  // The representation of Jan 1, 1970 UTC in microseconds since the
+  // platform-dependent epoch.
+  static const int64 kTimeTToMicrosecondsOffset;
+
 #if !defined(OS_WIN)
   // On Mac & Linux, this value is the delta from the Windows epoch of 1601 to
   // the Posix delta of 1970. This is used for migrating between the old
@@ -492,10 +496,6 @@
                                  bool is_local,
                                  Time* parsed_time);
 
-  // The representation of Jan 1, 1970 UTC in microseconds since the
-  // platform-dependent epoch.
-  static const int64 kTimeTToMicrosecondsOffset;
-
   // Time in microseconds in UTC.
   int64 us_;
 };
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index c69fada..5e30762 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -116,7 +116,7 @@
 
 void DeathData::RecordDeath(const int32 queue_duration,
                             const int32 run_duration,
-                            int32 random_number) {
+                            const uint32 random_number) {
   // We'll just clamp at INT_MAX, but we should note this in the UI as such.
   if (count_ < INT_MAX)
     ++count_;
@@ -307,7 +307,7 @@
   (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_,
                                                  sizeof(random_number_));
   MSAN_UNPOISON(&random_number_, sizeof(random_number_));
-  random_number_ += static_cast<int32>(this - static_cast<ThreadData*>(0));
+  random_number_ += static_cast<uint32>(this - static_cast<ThreadData*>(0));
   random_number_ ^= (Now() - TrackedTime()).InMilliseconds();
 
   DCHECK(!next_);
@@ -453,10 +453,10 @@
   int32 run_duration = stopwatch.RunDurationMs();
 
   // Stir in some randomness, plus add constant in case durations are zero.
-  const int32 kSomePrimeNumber = 2147483647;
+  const uint32 kSomePrimeNumber = 2147483647;
   random_number_ += queue_duration + run_duration + kSomePrimeNumber;
   // An address is going to have some randomness to it as well ;-).
-  random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0));
+  random_number_ ^= static_cast<uint32>(&birth - reinterpret_cast<Births*>(0));
 
   // We don't have queue durations without OS timer. OS timer is automatically
   // used for task-post-timing, so the use of an alternate timer implies all
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 50bea47..723fb91 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -273,7 +273,7 @@
   // |duration|, and has had a queueing delay of |queue_duration|.
   void RecordDeath(const int32 queue_duration,
                    const int32 run_duration,
-                   int random_number);
+                   const uint32 random_number);
 
   // Metrics accessors, used only for serialization and in tests.
   int count() const;
@@ -685,7 +685,7 @@
   // representative sample in each DeathData instance.  We can't start off with
   // much randomness (because we can't call RandInt() on all our threads), so
   // we stir in more and more as we go.
-  int32 random_number_;
+  uint32 random_number_;
 
   // Record of what the incarnation_counter_ was when this instance was created.
   // If the incarnation_counter_ has changed, then we avoid pushing into the
diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc
index d8d12be..711c52f 100644
--- a/base/win/scoped_comptr_unittest.cc
+++ b/base/win/scoped_comptr_unittest.cc
@@ -41,8 +41,8 @@
   EXPECT_TRUE(SUCCEEDED(unk.CreateInstance(CLSID_ShellLink)));
   ScopedComPtr<IUnknown> unk2;
   unk2.Attach(unk.Detach());
-  EXPECT_TRUE(unk == NULL);
-  EXPECT_TRUE(unk2 != NULL);
+  EXPECT_TRUE(unk.get() == NULL);
+  EXPECT_TRUE(unk2.get() != NULL);
 
   ScopedComPtr<IMalloc> mem_alloc;
   EXPECT_TRUE(SUCCEEDED(CoGetMalloc(1, mem_alloc.Receive())));
@@ -55,26 +55,26 @@
 
   // test ScopedComPtr& constructor
   ScopedComPtr<IMalloc> copy1(mem_alloc);
-  EXPECT_TRUE(copy1.IsSameObject(mem_alloc));
-  EXPECT_FALSE(copy1.IsSameObject(unk2));  // unk2 is valid but different
-  EXPECT_FALSE(copy1.IsSameObject(unk));  // unk is NULL
+  EXPECT_TRUE(copy1.IsSameObject(mem_alloc.get()));
+  EXPECT_FALSE(copy1.IsSameObject(unk2.get()));  // unk2 is valid but different
+  EXPECT_FALSE(copy1.IsSameObject(unk.get()));  // unk is NULL
 
   IMalloc* naked_copy = copy1.Detach();
   copy1 = naked_copy;  // Test the =(T*) operator.
   naked_copy->Release();
 
   copy1.Release();
-  EXPECT_FALSE(copy1.IsSameObject(unk2));  // unk2 is valid, copy1 is not
+  EXPECT_FALSE(copy1.IsSameObject(unk2.get()));  // unk2 is valid, copy1 is not
 
   // test Interface* constructor
-  ScopedComPtr<IMalloc> copy2(static_cast<IMalloc*>(mem_alloc));
-  EXPECT_TRUE(copy2.IsSameObject(mem_alloc));
+  ScopedComPtr<IMalloc> copy2(static_cast<IMalloc*>(mem_alloc.get()));
+  EXPECT_TRUE(copy2.IsSameObject(mem_alloc.get()));
 
-  EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc)));
-  EXPECT_TRUE(unk != NULL);
+  EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc.get())));
+  EXPECT_TRUE(unk.get() != NULL);
   unk.Release();
-  EXPECT_TRUE(unk == NULL);
-  EXPECT_TRUE(unk.IsSameObject(copy1));  // both are NULL
+  EXPECT_TRUE(unk.get() == NULL);
+  EXPECT_TRUE(unk.IsSameObject(copy1.get()));  // both are NULL
 }
 
 TEST(ScopedComPtrTest, ScopedComPtrVector) {
@@ -98,7 +98,7 @@
     bleh.push_back(p2);
     EXPECT_EQ(p->adds, 4);
     EXPECT_EQ(p->releases, 1);
-    EXPECT_EQ(bleh[0], p.get());
+    EXPECT_EQ(bleh[0].get(), p.get());
     bleh.pop_back();
     EXPECT_EQ(p->adds, 4);
     EXPECT_EQ(p->releases, 2);
diff --git a/build/all.gyp b/build/all.gyp
index 22f0d26..d47fc79 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -42,13 +42,13 @@
             # NOTE: This list of targets is present because
             # mojo_base.gyp:mojo_base cannot be built on iOS, as
             # javascript-related targets cause v8 to be built.
-            '../mojo/edk/mojo_edk.gyp:mojo_public_bindings_unittests',
-            '../mojo/edk/mojo_edk.gyp:mojo_public_environment_unittests',
-            '../mojo/edk/mojo_edk.gyp:mojo_public_system_perftests',
-            '../mojo/edk/mojo_edk.gyp:mojo_public_system_unittests',
-            '../mojo/edk/mojo_edk.gyp:mojo_public_utility_unittests',
+            '../mojo/edk/mojo_edk_tests.gyp:mojo_public_bindings_unittests',
+            '../mojo/edk/mojo_edk_tests.gyp:mojo_public_environment_unittests',
+            '../mojo/edk/mojo_edk_tests.gyp:mojo_public_system_perftests',
+            '../mojo/edk/mojo_edk_tests.gyp:mojo_public_system_unittests',
+            '../mojo/edk/mojo_edk_tests.gyp:mojo_public_utility_unittests',
             '../mojo/edk/mojo_edk.gyp:mojo_system_impl',
-            '../mojo/edk/mojo_edk.gyp:mojo_system_unittests',
+            '../mojo/edk/mojo_edk_tests.gyp:mojo_system_unittests',
             '../mojo/mojo_base.gyp:mojo_common_lib',
             '../mojo/mojo_base.gyp:mojo_common_unittests',
             '../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
@@ -276,6 +276,11 @@
             '../athena/main/athena_main.gyp:*',
           ],
         }],
+        ['envoy==1', {
+          'dependencies': [
+            '../envoy/envoy.gyp:*',
+          ],
+        }],
       ],
     }, # target_name: All
     {
@@ -354,6 +359,7 @@
         ['OS=="win"', {
           'dependencies': [
             '../chrome/chrome.gyp:app_installer',
+            '../chrome/chrome.gyp:app_installer_unittests',
             '../chrome/chrome.gyp:crash_service',
             '../chrome/chrome.gyp:installer_util_unittests',
             # ../chrome/test/mini_installer requires mini_installer.
@@ -844,9 +850,10 @@
             '../ui/gfx/gfx_tests.gyp:gfx_unittests_apk',
           ],
           'conditions': [
-            ['"<(libpeer_target_type)"=="static_library"', {
+            ['enable_webrtc==1 and "<(libpeer_target_type)"=="static_library"', {
               'dependencies': [
                 '../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
+                '../components/devtools_bridge.gyp:devtools_bridge_tests2_apk',
               ],
             }],
           ],
@@ -1180,6 +1187,7 @@
               'dependencies': [
                 '../base/base.gyp:base_unittests',
                 '../chrome/chrome.gyp:app_installer',
+                '../chrome/chrome.gyp:app_installer_unittests',
                 '../chrome/chrome.gyp:browser_tests',
                 '../chrome/chrome.gyp:sync_integration_tests',
                 '../chrome/chrome.gyp:crash_service',
diff --git a/build/android/findbugs_filter/findbugs_known_bugs.txt b/build/android/findbugs_filter/findbugs_known_bugs.txt
index f641e15..ee27544 100644
--- a/build/android/findbugs_filter/findbugs_known_bugs.txt
+++ b/build/android/findbugs_filter/findbugs_known_bugs.txt
@@ -24,3 +24,4 @@
 M V EI: org.chromium.content_public.browser.LoadUrlParams.getPostData() may expose internal representation by returning LoadUrlParams.mPostData  At LoadUrlParams.java
 M D NP: Read of unwritten public or protected field data in org.chromium.components.devtools_bridge.SessionDependencyFactory$DataChannelObserverAdapter.onMessage(DataChannel$Buffer)  At SessionDependencyFactory.java
 M D NP: Read of unwritten public or protected field mandatory in org.chromium.components.devtools_bridge.SessionDependencyFactory.createPeerConnection(RTCConfiguration, AbstractPeerConnection$Observer)  At SessionDependencyFactory.java
+M V EI2: org.chromium.net.ChromiumUrlRequest.setUploadData(String, byte[]) may expose internal representation by storing an externally mutable object into ChromiumUrlRequest.mUploadData  At ChromiumUrlRequest.java
diff --git a/build/android/gyp/java_cpp_enum.py b/build/android/gyp/java_cpp_enum.py
index 8ae5f36..b10e7c5 100755
--- a/build/android/gyp/java_cpp_enum.py
+++ b/build/android/gyp/java_cpp_enum.py
@@ -13,14 +13,21 @@
 
 from util import build_utils
 
+# List of C++ types that are compatible with the Java code generated by this
+# script.
+ENUM_FIXED_TYPE_WHITELIST = ['char', 'unsigned char',
+  'short', 'unsigned short',
+  'int', 'int8_t', 'int16_t', 'int32_t', 'uint8_t', 'uint16_t']
+
 class EnumDefinition(object):
   def __init__(self, original_enum_name=None, class_name_override=None,
-               enum_package=None, entries=None):
+               enum_package=None, entries=None, fixed_type=None):
     self.original_enum_name = original_enum_name
     self.class_name_override = class_name_override
     self.enum_package = enum_package
     self.entries = collections.OrderedDict(entries or [])
     self.prefix_to_strip = None
+    self.fixed_type = fixed_type
 
   def AppendEntry(self, key, value):
     if key in self.entries:
@@ -40,6 +47,9 @@
     assert self.class_name
     assert self.enum_package
     assert self.entries
+    if self.fixed_type and self.fixed_type not in ENUM_FIXED_TYPE_WHITELIST:
+      raise Exception('Fixed type %s for enum %s not whitelisted.' %
+          (self.fixed_type, self.class_name))
 
   def _AssignEntryIndices(self):
     # Enums, if given no value, are given the value of the previous enum + 1.
@@ -110,12 +120,17 @@
 class HeaderParser(object):
   single_line_comment_re = re.compile(r'\s*//')
   multi_line_comment_start_re = re.compile(r'\s*/\*')
-  enum_start_re = re.compile(r'^\s*enum\s+(\w+)\s+{\s*$')
   enum_line_re = re.compile(r'^\s*(\w+)(\s*\=\s*([^,\n]+))?,?')
   enum_end_re = re.compile(r'^\s*}\s*;\.*$')
   generator_directive_re = re.compile(
       r'^\s*//\s+GENERATED_JAVA_(\w+)\s*:\s*([\.\w]+)$')
 
+  optional_class_or_struct_re = r'(class|struct)?'
+  enum_name_re = r'(\w+)'
+  optional_fixed_type_re = r'(\:\s*(\w+\s*\w+?))?'
+  enum_start_re = re.compile(r'^\s*enum\s+' + optional_class_or_struct_re +
+      '\s*' + enum_name_re + '\s*' + optional_fixed_type_re + '\s*{\s*$')
+
   def __init__(self, lines):
     self._lines = lines
     self._enum_definitions = []
@@ -162,7 +177,8 @@
       if self._generator_directives.empty:
         return
       self._current_definition = EnumDefinition(
-          original_enum_name=enum_start.groups()[0])
+          original_enum_name=enum_start.groups()[1],
+          fixed_type=enum_start.groups()[3])
       self._in_enum = True
     elif generator_directive:
       directive_name = generator_directive.groups()[0]
diff --git a/build/android/gyp/java_cpp_enum_tests.py b/build/android/gyp/java_cpp_enum_tests.py
index bb8150d..3aa386e 100755
--- a/build/android/gyp/java_cpp_enum_tests.py
+++ b/build/android/gyp/java_cpp_enum_tests.py
@@ -14,7 +14,8 @@
 import sys
 import unittest
 
-from java_cpp_enum import EnumDefinition, GenerateOutput, HeaderParser
+from java_cpp_enum import EnumDefinition, GenerateOutput, GetScriptName
+from java_cpp_enum import HeaderParser
 
 sys.path.append(os.path.join(os.path.dirname(__file__), "gyp"))
 from util import build_utils
@@ -31,7 +32,7 @@
 // found in the LICENSE file.
 
 // This file is autogenerated by
-//     build/android/gyp/java_cpp_enum_tests.py
+//     %s
 // From
 //     path/to/file
 
@@ -42,7 +43,7 @@
   public static final int E2 = 2 << 2;
 }
 """
-    self.assertEqual(expected, output)
+    self.assertEqual(expected % GetScriptName(), output)
 
   def testParseSimpleEnum(self):
     test_data = """
@@ -150,6 +151,78 @@
     with self.assertRaises(Exception):
       HeaderParser(test_data).ParseDefinitions()
 
+  def testParseEnumClass(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum class Foo {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(1, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('Foo', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual(collections.OrderedDict([('A', 0)]),
+                     definition.entries)
+
+  def testParseEnumStruct(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum struct Foo {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(1, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('Foo', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual(collections.OrderedDict([('A', 0)]),
+                     definition.entries)
+
+  def testParseFixedTypeEnum(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum Foo : int {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(1, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('Foo', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual('int', definition.fixed_type)
+    self.assertEqual(collections.OrderedDict([('A', 0)]),
+                     definition.entries)
+
+  def testParseFixedTypeEnumClass(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum class Foo: unsigned short {
+        FOO_A,
+      };
+    """.split('\n')
+    definitions = HeaderParser(test_data).ParseDefinitions()
+    self.assertEqual(1, len(definitions))
+    definition = definitions[0]
+    self.assertEqual('Foo', definition.class_name)
+    self.assertEqual('test.namespace', definition.enum_package)
+    self.assertEqual('unsigned short', definition.fixed_type)
+    self.assertEqual(collections.OrderedDict([('A', 0)]),
+                     definition.entries)
+
+  def testParseUnknownFixedTypeRaises(self):
+    test_data = """
+      // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+      enum class Foo: foo_type {
+        FOO_A,
+      };
+    """.split('\n')
+    with self.assertRaises(Exception):
+      HeaderParser(test_data).ParseDefinitions()
+
   def testEnumValueAssignmentNoneDefined(self):
     definition = EnumDefinition(original_enum_name='c', enum_package='p')
     definition.AppendEntry('A', None)
diff --git a/build/android/gyp/package_resources.py b/build/android/gyp/package_resources.py
index 6444ed9..9b6ec68 100755
--- a/build/android/gyp/package_resources.py
+++ b/build/android/gyp/package_resources.py
@@ -37,6 +37,11 @@
   parser.add_option('--android-manifest', help='AndroidManifest.xml path')
   parser.add_option('--version-code', help='Version code for apk.')
   parser.add_option('--version-name', help='Version name for apk.')
+  parser.add_option(
+      '--shared-resources',
+      action='store_true',
+      help='Make a resource package that can be loaded by a different'
+      'application at runtime to access the package\'s resources.')
   parser.add_option('--resource-zips',
                     help='zip files containing resources to be packaged')
   parser.add_option('--asset-dir',
@@ -132,6 +137,8 @@
     if options.no_compress:
       for ext in options.no_compress.split(','):
         package_command += ['-0', ext]
+    if options.shared_resources:
+      package_command.append('--shared-lib')
 
     if os.path.exists(options.asset_dir):
       package_command += ['-A', options.asset_dir]
diff --git a/build/android/gyp/process_resources.py b/build/android/gyp/process_resources.py
index 6bf71f3..45b0947 100755
--- a/build/android/gyp/process_resources.py
+++ b/build/android/gyp/process_resources.py
@@ -38,6 +38,11 @@
 
   parser.add_option('--android-manifest', help='AndroidManifest.xml path')
   parser.add_option('--custom-package', help='Java package for R.java')
+  parser.add_option(
+      '--shared-resources',
+      action='store_true',
+      help='Make a resource package that can be loaded by a different'
+      'application at runtime to access the package\'s resources.')
 
   parser.add_option('--resource-dirs',
                     help='Directories containing resources of this target.')
@@ -236,6 +241,8 @@
       package_command += ['--custom-package', options.custom_package]
     if options.proguard_file:
       package_command += ['-G', options.proguard_file]
+    if options.shared_resources:
+      package_command.append('--shared-lib')
     build_utils.CheckOutput(package_command, print_stderr=False)
 
     if options.extra_res_packages:
diff --git a/build/android/pylib/base/base_test_result.py b/build/android/pylib/base/base_test_result.py
index 1f45214..f9e61a9 100644
--- a/build/android/pylib/base/base_test_result.py
+++ b/build/android/pylib/base/base_test_result.py
@@ -23,18 +23,20 @@
 class BaseTestResult(object):
   """Base class for a single test result."""
 
-  def __init__(self, name, test_type, log=''):
+  def __init__(self, name, test_type, duration=0, log=''):
     """Construct a BaseTestResult.
 
     Args:
       name: Name of the test which defines uniqueness.
       test_type: Type of the test result as defined in ResultType.
+      duration: Time it took for the test to run in milliseconds.
       log: An optional string listing any errors.
     """
     assert name
     assert test_type in ResultType.GetTypes()
     self._name = name
     self._test_type = test_type
+    self._duration = duration
     self._log = log
 
   def __str__(self):
@@ -66,6 +68,10 @@
     """Get the test result type."""
     return self._test_type
 
+  def GetDuration(self):
+    """Get the test duration."""
+    return self._duration
+
   def GetLog(self):
     """Get the test log."""
     return self._log
diff --git a/build/android/pylib/base/base_test_runner.py b/build/android/pylib/base/base_test_runner.py
index 1f76149..6e51b43 100644
--- a/build/android/pylib/base/base_test_runner.py
+++ b/build/android/pylib/base/base_test_runner.py
@@ -9,10 +9,8 @@
 # model.
 
 import logging
-import time
 
 from pylib import ports
-from pylib.chrome_test_server_spawner import SpawningServer
 from pylib.device import device_utils
 from pylib.forwarder import Forwarder
 from pylib.valgrind_tools import CreateTool
@@ -42,7 +40,6 @@
     self._forwarder_device_port = 8000
     self.forwarder_base_url = ('http://localhost:%d' %
         self._forwarder_device_port)
-    self._spawning_server = None
     # We will allocate port for test server spawner when calling method
     # LaunchChromeTestServerSpawner and allocate port for test server when
     # starting it in TestServerThread.
@@ -146,45 +143,4 @@
     if self._http_server:
       self._UnmapPorts([(self._forwarder_device_port, self._http_server.port)])
       self._http_server.ShutdownHttpServer()
-    if self._spawning_server:
-      self._spawning_server.Stop()
 
-  def CleanupSpawningServerState(self):
-    """Tells the spawning server to clean up any state.
-
-    If the spawning server is reused for multiple tests, this should be called
-    after each test to prevent tests affecting each other.
-    """
-    if self._spawning_server:
-      self._spawning_server.CleanupState()
-
-  def LaunchChromeTestServerSpawner(self):
-    """Launches test server spawner."""
-    server_ready = False
-    error_msgs = []
-    # TODO(pliard): deflake this function. The for loop should be removed as
-    # well as IsHttpServerConnectable(). spawning_server.Start() should also
-    # block until the server is ready.
-    # Try 3 times to launch test spawner server.
-    for _ in xrange(0, 3):
-      self.test_server_spawner_port = ports.AllocateTestServerPort()
-      self._ForwardPorts(
-          [(self.test_server_spawner_port, self.test_server_spawner_port)])
-      self._spawning_server = SpawningServer(self.test_server_spawner_port,
-                                             self.device,
-                                             self.tool)
-      self._spawning_server.Start()
-      server_ready, error_msg = ports.IsHttpServerConnectable(
-          '127.0.0.1', self.test_server_spawner_port, path='/ping',
-          expected_read='ready')
-      if server_ready:
-        break
-      else:
-        error_msgs.append(error_msg)
-      self._spawning_server.Stop()
-      # Wait for 2 seconds then restart.
-      time.sleep(2)
-    if not server_ready:
-      logging.error(';'.join(error_msgs))
-      raise Exception('Can not start the test spawner server.')
-    self._PushTestServerPortInfoToDevice()
diff --git a/build/android/pylib/base/test_collection.py b/build/android/pylib/base/test_collection.py
new file mode 100644
index 0000000..e914652
--- /dev/null
+++ b/build/android/pylib/base/test_collection.py
@@ -0,0 +1,80 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import threading
+
+class TestCollection(object):
+  """A threadsafe collection of tests.
+
+  Args:
+    tests: List of tests to put in the collection.
+  """
+
+  def __init__(self, tests=None):
+    if not tests:
+      tests = []
+    self._lock = threading.Lock()
+    self._tests = []
+    self._tests_in_progress = 0
+    # Used to signal that an item is available or all items have been handled.
+    self._item_available_or_all_done = threading.Event()
+    for t in tests:
+      self.add(t)
+
+  def _pop(self):
+    """Pop a test from the collection.
+
+    Waits until a test is available or all tests have been handled.
+
+    Returns:
+      A test or None if all tests have been handled.
+    """
+    while True:
+      # Wait for a test to be available or all tests to have been handled.
+      self._item_available_or_all_done.wait()
+      with self._lock:
+        # Check which of the two conditions triggered the signal.
+        if self._tests_in_progress == 0:
+          return None
+        try:
+          return self._tests.pop(0)
+        except IndexError:
+          # Another thread beat us to the available test, wait again.
+          self._item_available_or_all_done.clear()
+
+  def add(self, test):
+    """Add an test to the collection.
+
+    Args:
+      test: A test to add.
+    """
+    with self._lock:
+      self._tests.append(test)
+      self._item_available_or_all_done.set()
+      self._tests_in_progress += 1
+
+  def test_completed(self):
+    """Indicate that a test has been fully handled."""
+    with self._lock:
+      self._tests_in_progress -= 1
+      if self._tests_in_progress == 0:
+        # All tests have been handled, signal all waiting threads.
+        self._item_available_or_all_done.set()
+
+  def __iter__(self):
+    """Iterate through tests in the collection until all have been handled."""
+    while True:
+      r = self._pop()
+      if r is None:
+        break
+      yield r
+
+  def __len__(self):
+    """Return the number of tests currently in the collection."""
+    return len(self._tests)
+
+  def test_names(self):
+    """Return a list of the names of the tests currently in the collection."""
+    with self._lock:
+      return list(t.test for t in self._tests)
diff --git a/build/android/pylib/base/test_dispatcher.py b/build/android/pylib/base/test_dispatcher.py
index 7b00ccd..929c408 100644
--- a/build/android/pylib/base/test_dispatcher.py
+++ b/build/android/pylib/base/test_dispatcher.py
@@ -24,6 +24,7 @@
 from pylib import android_commands
 from pylib import constants
 from pylib.base import base_test_result
+from pylib.base import test_collection
 from pylib.device import device_errors
 from pylib.utils import reraiser_thread
 from pylib.utils import watchdog_timer
@@ -65,92 +66,16 @@
     self.tries = tries
 
 
-class _TestCollection(object):
-  """A threadsafe collection of tests.
-
-  Args:
-    tests: List of tests to put in the collection.
-  """
-
-  def __init__(self, tests=None):
-    if not tests:
-      tests = []
-    self._lock = threading.Lock()
-    self._tests = []
-    self._tests_in_progress = 0
-    # Used to signal that an item is available or all items have been handled.
-    self._item_available_or_all_done = threading.Event()
-    for t in tests:
-      self.add(t)
-
-  def _pop(self):
-    """Pop a test from the collection.
-
-    Waits until a test is available or all tests have been handled.
-
-    Returns:
-      A test or None if all tests have been handled.
-    """
-    while True:
-      # Wait for a test to be available or all tests to have been handled.
-      self._item_available_or_all_done.wait()
-      with self._lock:
-        # Check which of the two conditions triggered the signal.
-        if self._tests_in_progress == 0:
-          return None
-        try:
-          return self._tests.pop(0)
-        except IndexError:
-          # Another thread beat us to the available test, wait again.
-          self._item_available_or_all_done.clear()
-
-  def add(self, test):
-    """Add an test to the collection.
-
-    Args:
-      test: A test to add.
-    """
-    with self._lock:
-      self._tests.append(test)
-      self._item_available_or_all_done.set()
-      self._tests_in_progress += 1
-
-  def test_completed(self):
-    """Indicate that a test has been fully handled."""
-    with self._lock:
-      self._tests_in_progress -= 1
-      if self._tests_in_progress == 0:
-        # All tests have been handled, signal all waiting threads.
-        self._item_available_or_all_done.set()
-
-  def __iter__(self):
-    """Iterate through tests in the collection until all have been handled."""
-    while True:
-      r = self._pop()
-      if r is None:
-        break
-      yield r
-
-  def __len__(self):
-    """Return the number of tests currently in the collection."""
-    return len(self._tests)
-
-  def test_names(self):
-    """Return a list of the names of the tests currently in the collection."""
-    with self._lock:
-      return list(t.test for t in self._tests)
-
-
-def _RunTestsFromQueue(runner, test_collection, out_results, watcher,
+def _RunTestsFromQueue(runner, collection, out_results, watcher,
                        num_retries, tag_results_with_device=False):
-  """Runs tests from the test_collection until empty using the given runner.
+  """Runs tests from the collection until empty using the given runner.
 
   Adds TestRunResults objects to the out_results list and may add tests to the
   out_retry list.
 
   Args:
     runner: A TestRunner object used to run the tests.
-    test_collection: A _TestCollection from which to get _Test objects to run.
+    collection: A TestCollection from which to get _Test objects to run.
     out_results: A list to add TestRunResults to.
     watcher: A watchdog_timer.WatchdogTimer object, used as a shared timeout.
     num_retries: Number of retries for a test.
@@ -174,7 +99,7 @@
       new_test_run_results.AddResult(test_result)
     return new_test_run_results
 
-  for test in test_collection:
+  for test in collection:
     watcher.Reset()
     try:
       if runner.device_serial not in android_commands.GetAttachedDevices():
@@ -192,18 +117,18 @@
         pass_results.AddResults(result.GetPass())
         out_results.append(pass_results)
         logging.warning('Will retry test, try #%s.' % test.tries)
-        test_collection.add(_Test(test=retry, tries=test.tries))
+        collection.add(_Test(test=retry, tries=test.tries))
       else:
         # All tests passed or retry limit reached. Either way, record results.
         out_results.append(result)
     except:
       # An unhandleable exception, ensure tests get run by another device and
       # reraise this exception on the main thread.
-      test_collection.add(test)
+      collection.add(test)
       raise
     finally:
       # Retries count as separate tasks so always mark the popped test as done.
-      test_collection.test_completed()
+      collection.test_completed()
 
 
 def _SetUp(runner_factory, device, out_runners, threadsafe_counter):
@@ -238,7 +163,7 @@
 
   Args:
     runners: A list of TestRunner objects.
-    test_collection_factory: A callable to generate a _TestCollection object for
+    test_collection_factory: A callable to generate a TestCollection object for
         each test runner.
     num_retries: Number of retries for a test.
     timeout: Watchdog timeout in seconds.
@@ -384,16 +309,17 @@
 
   tests_expanded = ApplyMaxPerRun(tests, max_per_run)
   if shard:
-    # Generate a shared _TestCollection object for all test runners, so they
+    # Generate a shared TestCollection object for all test runners, so they
     # draw from a common pool of tests.
-    shared_test_collection = _TestCollection([_Test(t) for t in tests_expanded])
+    shared_test_collection = test_collection.TestCollection(
+        [_Test(t) for t in tests_expanded])
     test_collection_factory = lambda: shared_test_collection
     tag_results_with_device = False
     log_string = 'sharded across devices'
   else:
-    # Generate a unique _TestCollection object for each test runner, but use
+    # Generate a unique TestCollection object for each test runner, but use
     # the same set of tests.
-    test_collection_factory = lambda: _TestCollection(
+    test_collection_factory = lambda: test_collection.TestCollection(
         [_Test(t) for t in tests_expanded])
     tag_results_with_device = True
     log_string = 'replicated on each device'
diff --git a/build/android/pylib/base/test_dispatcher_unittest.py b/build/android/pylib/base/test_dispatcher_unittest.py
index d349f32..b57cca9 100644
--- a/build/android/pylib/base/test_dispatcher_unittest.py
+++ b/build/android/pylib/base/test_dispatcher_unittest.py
@@ -18,6 +18,7 @@
 android_commands.GetAttachedDevices = lambda: ['0', '1']
 from pylib import constants
 from pylib.base import base_test_result
+from pylib.base import test_collection
 from pylib.base import test_dispatcher
 from pylib.utils import watchdog_timer
 
@@ -83,7 +84,7 @@
   @staticmethod
   def _RunTests(mock_runner, tests):
     results = []
-    tests = test_dispatcher._TestCollection(
+    tests = test_collection.TestCollection(
         [test_dispatcher._Test(t) for t in tests])
     test_dispatcher._RunTestsFromQueue(mock_runner, tests, results,
                                        watchdog_timer.WatchdogTimer(None), 2)
@@ -129,7 +130,7 @@
   """Tests test_dispatcher._RunAllTests and test_dispatcher._CreateRunners."""
   def setUp(self):
     self.tests = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
-    shared_test_collection = test_dispatcher._TestCollection(
+    shared_test_collection = test_collection.TestCollection(
         [test_dispatcher._Test(t) for t in self.tests])
     self.test_collection_factory = lambda: shared_test_collection
 
diff --git a/build/android/pylib/base/test_server.py b/build/android/pylib/base/test_server.py
new file mode 100644
index 0000000..085a51e
--- /dev/null
+++ b/build/android/pylib/base/test_server.py
@@ -0,0 +1,19 @@
+# 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.
+
+class TestServer(object):
+  """Base class for any server that needs to be set up for the tests."""
+
+  def __init__(self, *args, **kwargs):
+    pass
+
+  def SetUp(self):
+    raise NotImplementedError
+
+  def Reset(self):
+    raise NotImplementedError
+
+  def TearDown(self):
+    raise NotImplementedError
+
diff --git a/build/android/pylib/constants.py b/build/android/pylib/constants.py
index cef098f..29da601 100644
--- a/build/android/pylib/constants.py
+++ b/build/android/pylib/constants.py
@@ -189,13 +189,12 @@
       'pylib.device.device_utils_test',
     ]
   },
-# TODO(mkosiba) Enable after fixing these tests.
-# 'gyp_py_unittests': {
-#   'path': os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'android', 'gyp'),
-#   'test_modules': [
-#     'java_cpp_enum_tests'
-#   ]
-# },
+  'gyp_py_unittests': {
+    'path': os.path.join(DIR_SOURCE_ROOT, 'build', 'android', 'gyp'),
+    'test_modules': [
+      'java_cpp_enum_tests',
+    ]
+  },
 }
 
 LOCAL_MACHINE_TESTS = ['junit', 'python']
@@ -217,6 +216,10 @@
   os.environ['CHROMIUM_OUT_DIR'] = build_directory
 
 
+def SetOutputDirectort(output_directory):
+  os.environ['CHROMIUM_OUTPUT_DIR'] = output_directory
+
+
 def GetOutDirectory(build_type=None):
   """Returns the out directory where the output binaries are built.
 
@@ -224,6 +227,10 @@
     build_type: Build type, generally 'Debug' or 'Release'. Defaults to the
       globally set build type environment variable BUILDTYPE.
   """
+  if 'CHROMIUM_OUTPUT_DIR' in os.environ:
+    return os.path.abspath(os.path.join(
+        DIR_SOURCE_ROOT, os.environ.get('CHROMIUM_OUTPUT_DIR')))
+
   return os.path.abspath(os.path.join(
       DIR_SOURCE_ROOT, os.environ.get('CHROMIUM_OUT_DIR', 'out'),
       GetBuildType() if build_type is None else build_type))
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index 97f387a..e7a8418 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -152,14 +152,14 @@
     self._DeviceAdbCmd(['pull', remote, local], timeout, retries)
     _VerifyLocalFileExists(local)
 
-  def Shell(self, command, expect_rc=None, timeout=_DEFAULT_TIMEOUT,
+  def Shell(self, command, expect_rc=0, timeout=_DEFAULT_TIMEOUT,
             retries=_DEFAULT_RETRIES):
     """Runs a shell command on the device.
 
     Args:
       command: The shell command to run.
-      expect_rc: (optional) If set checks that the command's return code matches
-        this value.
+      expect_rc: (optional) Check that the command's return code matches this
+        value. Default is 0. If set to None the test is skipped.
       timeout: (optional) Timeout per try in seconds.
       retries: (optional) Number of retries to attempt.
 
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index f4bce41..f6bebce 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -215,9 +215,6 @@
       CommandTimeoutError on timeout.
       DeviceUnreachableError on missing device.
     """
-    return self._GetExternalStoragePathImpl()
-
-  def _GetExternalStoragePathImpl(self):
     if 'external_storage' in self._cache:
       return self._cache['external_storage']
 
@@ -285,7 +282,8 @@
       return self.GetProp('sys.boot_completed') == '1'
 
     def wifi_enabled():
-      return 'Wi-Fi is enabled' in self.RunShellCommand(['dumpsys', 'wifi'])
+      return 'Wi-Fi is enabled' in self.RunShellCommand(['dumpsys', 'wifi'],
+                                                        check_return=False)
 
     self.adb.WaitForDevice()
     timeout_retry.WaitFor(sd_card_ready)
@@ -442,7 +440,7 @@
       timeout = self._default_timeout
 
     try:
-      output = self.adb.Shell(cmd, expect_rc=0)
+      output = self.adb.Shell(cmd)
     except device_errors.AdbShellCommandFailedError as e:
       if check_return:
         raise
@@ -531,6 +529,22 @@
         raise device_errors.CommandFailedError(l, device=str(self))
 
   @decorators.WithTimeoutAndRetriesFromInstance()
+  def StartInstrumentation(self, component, finish=True, raw=False,
+                           extras=None, timeout=None, retries=None):
+    if extras is None:
+      extras = {}
+
+    cmd = ['am', 'instrument']
+    if finish:
+      cmd.append('-w')
+    if raw:
+      cmd.append('-r')
+    for k, v in extras.iteritems():
+      cmd.extend(['-e', k, v])
+    cmd.append(component)
+    return self.RunShellCommand(cmd, check_return=True)
+
+  @decorators.WithTimeoutAndRetriesFromInstance()
   def BroadcastIntent(self, intent, timeout=None, retries=None):
     """Send a broadcast intent.
 
@@ -768,7 +782,7 @@
       zip_proc.start()
       zip_proc.join()
 
-      zip_on_device = '%s/tmp.zip' % self._GetExternalStoragePathImpl()
+      zip_on_device = '%s/tmp.zip' % self.GetExternalStoragePath()
       try:
         self.adb.Push(zip_file.name, zip_on_device)
         self.RunShellCommand(
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index fa4ffaa..65547d4 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -26,6 +26,7 @@
 from pylib.device import device_errors
 from pylib.device import device_utils
 from pylib.device import intent
+from pylib.utils import mock_calls
 
 # RunCommand from third_party/android_testrunner/run_command.py is mocked
 # below, so its path needs to be in sys.path.
@@ -218,82 +219,7 @@
         '0123456789abcdef', default_timeout=1, default_retries=0)
 
 
-class Args:
-  def __init__(self, *args, **kwargs):
-    self.args = args
-    self.kwargs = kwargs
-
-  def __eq__(self, other):
-    return (self.args, self.kwargs) == (other.args, other.kwargs)
-
-  def __repr__(self):
-    return '%s(%s)' % (type(self).__name__, str(self))
-
-  def __str__(self):
-    toks = (['%r' % v for v in self.args] +
-            ['%s=%r' % (k, self.kwargs[k]) for k in sorted(self.kwargs)])
-    return ', '.join(toks)
-
-
-class MockCallSequence(object):
-  def __init__(self, test_case, obj, method, calls):
-    def assert_and_return(*args, **kwargs):
-      received_args = Args(*args, **kwargs)
-      test_case.assertTrue(
-          self._calls,
-          msg=('Unexpected call\n'
-               '  received: %s(%s)\n' % (self._method, received_args)))
-      expected_args, return_value = self._calls.pop(0)
-      test_case.assertTrue(
-          received_args == expected_args,
-          msg=('Call does not match expected args\n'
-               '  received: %s(%s)\n'
-               '  expected: %s(%s)\n'
-               % (self._method, received_args,
-                  self._method, expected_args)))
-      if isinstance(return_value, Exception):
-        raise return_value
-      else:
-        return return_value
-
-    self._calls = list(calls)
-    self._test_case = test_case
-    self._method = method
-    self._patched = mock.patch.object(obj, self._method,
-                                      side_effect=assert_and_return)
-
-  def __enter__(self):
-    return self._patched.__enter__()
-
-  def __exit__(self, exc_type, exc_val, exc_tb):
-    self._patched.__exit__(exc_type, exc_val, exc_tb)
-    if exc_type is None:
-      missing = ''.join('  expected: %s(%s)\n'
-                        % (self._method, expected_args)
-                        for expected_args, _ in self._calls)
-      self._test_case.assertTrue(
-          not missing,
-          msg=('Expected calls not found\n' + missing))
-
-
-class _ShellError:
-  def __init__(self, output=None, return_code=1):
-    if output is None:
-      self.output = 'Permission denied\r\n'
-    else:
-      self.output = output
-    self.return_code = return_code
-
-
-class _CmdTimeout:
-  def __init__(self, msg=None):
-    if msg is None:
-      self.msg = 'Operation timed out'
-    else:
-      self.msg = msg
-
-
-class DeviceUtilsNewImplTest(unittest.TestCase):
+class DeviceUtilsNewImplTest(mock_calls.TestCase):
 
   def setUp(self):
     test_serial = '0123456789abcdef'
@@ -302,66 +228,52 @@
     self.adb.GetDeviceSerial.return_value = test_serial
     self.device = device_utils.DeviceUtils(
         self.adb, default_timeout=10, default_retries=0)
+    self.watchMethodCalls(self.call.adb)
 
-  def assertShellCallSequence(self, calls):
-    '''Assert that we expect a sequence of calls to adb.Shell.
+  def ShellError(self, output=None, exit_code=1):
+    def action(cmd, *args, **kwargs):
+      raise device_errors.AdbShellCommandFailedError(
+          cmd, exit_code, output, str(self.device))
+    if output is None:
+      output = 'Permission denied\n'
+    return action
 
-    Args:
-      calls: a sequence of (cmd, return_value) pairs, where |cmd| is the
-        expected shell command to run on the device (with any quoting already
-        applied), and |return_value| is either a string to give as mock output
-        or a _ShellError object to raise an AdbShellCommandFailedError.
-    '''
-    def mk_expected_call(cmd, return_value):
-      expected_args = Args(cmd, expect_rc=0)
-      if isinstance(return_value, _ShellError):
-        return_value = device_errors.AdbShellCommandFailedError(cmd,
-            return_value.return_code, return_value.output, str(self.device))
-      elif isinstance(return_value, _CmdTimeout):
-        return_value = device_errors.CommandTimeoutError(return_value.msg,
-                                                         str(self.device))
-      return (expected_args, return_value)
+  def TimeoutError(self, msg=None):
+    if msg is None:
+      msg = 'Operation timed out'
+    return mock.Mock(side_effect=device_errors.CommandTimeoutError(
+        msg, str(self.device)))
 
-    expected_calls = (mk_expected_call(a, r) for a, r in calls)
-    return MockCallSequence(self, self.adb, 'Shell', expected_calls)
-
-  def assertShellCall(self, cmd, return_value=''):
-    return self.assertShellCallSequence([(cmd, return_value)])
-
-
-class DeviceUtilsHybridImplTest(DeviceUtilsOldImplTest):
-
-  def setUp(self):
-    super(DeviceUtilsHybridImplTest, self).setUp()
-    self.device.adb = self.adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
+  def CommandError(self, msg=None):
+    if msg is None:
+      msg = 'Command failed'
+    return mock.Mock(side_effect=device_errors.CommandFailedError(
+        msg, str(self.device)))
 
 
 class DeviceUtilsIsOnlineTest(DeviceUtilsNewImplTest):
 
   def testIsOnline_true(self):
-    self.adb.GetState = mock.Mock(return_value='device')
-    self.assertTrue(self.device.IsOnline())
-    self.adb.GetState.assert_called_once_with()
+    with self.assertCall(self.call.adb.GetState(), 'device'):
+      self.assertTrue(self.device.IsOnline())
 
   def testIsOnline_false(self):
-    self.adb.GetState = mock.Mock(return_value='offline')
-    self.assertFalse(self.device.IsOnline())
-    self.adb.GetState.assert_called_once_with()
+    with self.assertCall(self.call.adb.GetState(), 'offline'):
+      self.assertFalse(self.device.IsOnline())
 
   def testIsOnline_error(self):
-    self.adb.GetState = mock.Mock(
-     side_effect=device_errors.CommandFailedError('falied'))
-    self.assertFalse(self.device.IsOnline())
-    self.adb.GetState.assert_called_once_with()
+    with self.assertCall(self.call.adb.GetState(), self.CommandError()):
+      self.assertFalse(self.device.IsOnline())
+
 
 class DeviceUtilsHasRootTest(DeviceUtilsNewImplTest):
 
   def testHasRoot_true(self):
-    with self.assertShellCall('ls /root', 'foo\r\n'):
+    with self.assertCall(self.call.adb.Shell('ls /root'), 'foo\n'):
       self.assertTrue(self.device.HasRoot())
 
   def testHasRoot_false(self):
-    with self.assertShellCall('ls /root', _ShellError()):
+    with self.assertCall(self.call.adb.Shell('ls /root'), self.ShellError()):
       self.assertFalse(self.device.HasRoot())
 
 
@@ -395,25 +307,26 @@
 class DeviceUtilsIsUserBuildTest(DeviceUtilsNewImplTest):
 
   def testIsUserBuild_yes(self):
-    with self.assertShellCall('getprop ro.build.type', 'user\r\n'):
+    with self.assertCall(
+        self.call.device.GetProp('ro.build.type', cache=True), 'user'):
       self.assertTrue(self.device.IsUserBuild())
 
   def testIsUserBuild_no(self):
-    with self.assertShellCall('getprop ro.build.type', 'userdebug\r\n'):
+    with self.assertCall(
+        self.call.device.GetProp('ro.build.type', cache=True), 'userdebug'):
       self.assertFalse(self.device.IsUserBuild())
 
 
 class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsNewImplTest):
 
   def testGetExternalStoragePath_succeeds(self):
-    fakeStoragePath = '/fake/storage/path'
-    with self.assertShellCall('echo $EXTERNAL_STORAGE',
-                              '%s\r\n' % fakeStoragePath):
-      self.assertEquals(fakeStoragePath,
+    with self.assertCall(
+        self.call.adb.Shell('echo $EXTERNAL_STORAGE'), '/fake/storage/path\n'):
+      self.assertEquals('/fake/storage/path',
                         self.device.GetExternalStoragePath())
 
   def testGetExternalStoragePath_fails(self):
-    with self.assertShellCall('echo $EXTERNAL_STORAGE', '\r\n'):
+    with self.assertCall(self.call.adb.Shell('echo $EXTERNAL_STORAGE'), '\n'):
       with self.assertRaises(device_errors.CommandFailedError):
         self.device.GetExternalStoragePath()
 
@@ -421,148 +334,150 @@
 class DeviceUtilsGetApplicationPathTest(DeviceUtilsNewImplTest):
 
   def testGetApplicationPath_exists(self):
-    with self.assertShellCall('pm path android',
-                              'package:/path/to/android.apk\n'):
+    with self.assertCall(self.call.adb.Shell('pm path android'),
+                         'package:/path/to/android.apk\n'):
       self.assertEquals('/path/to/android.apk',
                         self.device.GetApplicationPath('android'))
 
   def testGetApplicationPath_notExists(self):
-    with self.assertShellCall('pm path not.installed.app',
-                              ''):
+    with self.assertCall(self.call.adb.Shell('pm path not.installed.app'), ''):
       self.assertEquals(None,
                         self.device.GetApplicationPath('not.installed.app'))
 
   def testGetApplicationPath_fails(self):
-    with self.assertShellCall('pm path android',
-                              'ERROR. Is package manager running?\n'):
+    with self.assertCall(self.call.adb.Shell('pm path android'),
+        self.CommandError('ERROR. Is package manager running?\n')):
       with self.assertRaises(device_errors.CommandFailedError):
         self.device.GetApplicationPath('android')
 
 
+@mock.patch('time.sleep', mock.Mock())
 class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsNewImplTest):
 
   def testWaitUntilFullyBooted_succeedsNoWifi(self):
-    with self.assertShellCallSequence([
-        # sc_card_ready
-        ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
-        ('test -d /fake/storage/path', ''),
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
         # pm_ready
-        ('pm path android', 'package:this.is.a.test.package\r\n'),
+        (self.call.device.GetApplicationPath('android'),
+         'package:/some/fake/path'),
         # boot_completed
-        ('getprop sys.boot_completed', '1\r\n')]):
+        (self.call.device.GetProp('sys.boot_completed'), '1')):
       self.device.WaitUntilFullyBooted(wifi=False)
-      self.adb.WaitForDevice.assert_called_once_with()
 
   def testWaitUntilFullyBooted_succeedsWithWifi(self):
-    with self.assertShellCallSequence([
-        # sc_card_ready
-        ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
-        ('test -d /fake/storage/path', ''),
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
         # pm_ready
-        ('pm path android', 'package:this.is.a.test.package\r\n'),
+        (self.call.device.GetApplicationPath('android'),
+         'package:/some/fake/path'),
         # boot_completed
-        ('getprop sys.boot_completed', '1\r\n'),
+        (self.call.device.GetProp('sys.boot_completed'), '1'),
         # wifi_enabled
-        ('dumpsys wifi', 'stuff\r\nWi-Fi is enabled\r\nmore stuff\r\n')]):
+        (self.call.adb.Shell('dumpsys wifi'),
+         'stuff\nWi-Fi is enabled\nmore stuff\n')):
       self.device.WaitUntilFullyBooted(wifi=True)
-      self.adb.WaitForDevice.assert_called_once_with()
 
   def testWaitUntilFullyBooted_sdCardReadyFails_noPath(self):
-    with self.assertShellCallSequence([
-        # sc_card_ready
-        ('echo $EXTERNAL_STORAGE', '\r\n')]):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), self.CommandError())):
       with self.assertRaises(device_errors.CommandFailedError):
         self.device.WaitUntilFullyBooted(wifi=False)
 
-  def testWaitUntilFullyBooted_sdCardReadyFails_emptyPath(self):
-    with mock.patch('time.sleep'):
-      with self.assertShellCallSequence([
-          # sc_card_ready
-          ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
-          ('test -d /fake/storage/path', _ShellError()),
-          # sc_card_ready
-          ('test -d /fake/storage/path', _ShellError()),
-          # sc_card_ready
-          ('test -d /fake/storage/path', _CmdTimeout())]):
-        with self.assertRaises(device_errors.CommandTimeoutError):
-          self.device.WaitUntilFullyBooted(wifi=False)
+  def testWaitUntilFullyBooted_sdCardReadyFails_notExists(self):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'),
+         self.TimeoutError())):
+      with self.assertRaises(device_errors.CommandTimeoutError):
+        self.device.WaitUntilFullyBooted(wifi=False)
 
   def testWaitUntilFullyBooted_devicePmFails(self):
-    with mock.patch('time.sleep'):
-      with self.assertShellCallSequence([
-          # sc_card_ready
-          ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
-          ('test -d /fake/storage/path', ''),
-          # pm_ready
-          ('pm path android', 'Error. Is package manager running?\r\n'),
-          # pm_ready
-          ('pm path android', 'Error. Is package manager running?\r\n'),
-          # pm_ready
-          ('pm path android', _CmdTimeout())]):
-        with self.assertRaises(device_errors.CommandTimeoutError):
-          self.device.WaitUntilFullyBooted(wifi=False)
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'), self.CommandError()),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'), self.CommandError()),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'), self.TimeoutError())):
+      with self.assertRaises(device_errors.CommandTimeoutError):
+        self.device.WaitUntilFullyBooted(wifi=False)
 
   def testWaitUntilFullyBooted_bootFails(self):
-    with mock.patch('time.sleep'):
-      with self.assertShellCallSequence([
-          # sc_card_ready
-          ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
-          ('test -d /fake/storage/path', ''),
-          # pm_ready
-          ('pm path android', 'package:this.is.a.test.package\r\n'),
-          # boot_completed
-          ('getprop sys.boot_completed', '0\r\n'),
-          # boot_completed
-          ('getprop sys.boot_completed', '0\r\n'),
-          # boot_completed
-          ('getprop sys.boot_completed', _CmdTimeout())]):
-        with self.assertRaises(device_errors.CommandTimeoutError):
-          self.device.WaitUntilFullyBooted(wifi=False)
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'),
+         'package:/some/fake/path'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), '0'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), '0'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), self.TimeoutError())):
+      with self.assertRaises(device_errors.CommandTimeoutError):
+        self.device.WaitUntilFullyBooted(wifi=False)
 
   def testWaitUntilFullyBooted_wifiFails(self):
-    with mock.patch('time.sleep'):
-      with self.assertShellCallSequence([
-          # sc_card_ready
-          ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
-          ('test -d /fake/storage/path', ''),
-          # pm_ready
-          ('pm path android', 'package:this.is.a.test.package\r\n'),
-          # boot_completed
-          ('getprop sys.boot_completed', '1\r\n'),
-          # wifi_enabled
-          ('dumpsys wifi', 'stuff\r\nmore stuff\r\n'),
-          # wifi_enabled
-          ('dumpsys wifi', 'stuff\r\nmore stuff\r\n'),
-          # wifi_enabled
-          ('dumpsys wifi', _CmdTimeout())]):
-        with self.assertRaises(device_errors.CommandTimeoutError):
-          self.device.WaitUntilFullyBooted(wifi=True)
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'),
+         'package:/some/fake/path'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), '1'),
+        # wifi_enabled
+        (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
+        # wifi_enabled
+        (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
+        # wifi_enabled
+        (self.call.adb.Shell('dumpsys wifi'), self.TimeoutError())):
+      with self.assertRaises(device_errors.CommandTimeoutError):
+        self.device.WaitUntilFullyBooted(wifi=True)
 
 
+@mock.patch('time.sleep', mock.Mock())
 class DeviceUtilsRebootTest(DeviceUtilsNewImplTest):
 
   def testReboot_nonBlocking(self):
-    self.adb.Reboot = mock.Mock()
-    self.device.IsOnline = mock.Mock(return_value=False)
-    self.device.Reboot(block=False)
-    self.adb.Reboot.assert_called_once_with()
-    self.device.IsOnline.assert_called_once_with()
+    with self.assertCalls(
+        self.call.adb.Reboot(),
+        (self.call.device.IsOnline(), True),
+        (self.call.device.IsOnline(), False)):
+      self.device.Reboot(block=False)
 
   def testReboot_blocking(self):
-    self.adb.Reboot = mock.Mock()
-    self.device.IsOnline = mock.Mock(return_value=False)
-    with self.assertShellCallSequence([
-        # sc_card_ready
-        ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
-        ('test -d /fake/storage/path', ''),
-        # pm_ready
-        ('pm path android', 'package:this.is.a.test.package\r\n'),
-        # boot_completed
-        ('getprop sys.boot_completed', '1\r\n')]):
+    with self.assertCalls(
+        self.call.adb.Reboot(),
+        (self.call.device.IsOnline(), True),
+        (self.call.device.IsOnline(), False),
+        self.call.device.WaitUntilFullyBooted()):
       self.device.Reboot(block=True)
-      self.adb.Reboot.assert_called_once_with()
-      self.device.IsOnline.assert_called_once_with()
-      self.adb.WaitForDevice.assert_called_once_with()
 
 
 class DeviceUtilsInstallTest(DeviceUtilsOldImplTest):
@@ -656,24 +571,31 @@
 
 
 class DeviceUtilsRunShellCommandTest(DeviceUtilsNewImplTest):
+
+  def setUp(self):
+    super(DeviceUtilsRunShellCommandTest, self).setUp()
+    self.device.NeedsSU = mock.Mock(return_value=False)
+
   def testRunShellCommand_commandAsList(self):
-    with self.assertShellCall('pm list packages'):
+    with self.assertCall(self.call.adb.Shell('pm list packages'), ''):
       self.device.RunShellCommand(['pm', 'list', 'packages'])
 
   def testRunShellCommand_commandAsListQuoted(self):
-    with self.assertShellCall("echo 'hello world' '$10'"):
+    with self.assertCall(self.call.adb.Shell("echo 'hello world' '$10'"), ''):
       self.device.RunShellCommand(['echo', 'hello world', '$10'])
 
   def testRunShellCommand_commandAsString(self):
-    with self.assertShellCall('echo "$VAR"'):
+    with self.assertCall(self.call.adb.Shell('echo "$VAR"'), ''):
       self.device.RunShellCommand('echo "$VAR"')
 
   def testNewRunShellImpl_withEnv(self):
-    with self.assertShellCall('VAR=some_string echo "$VAR"'):
+    with self.assertCall(
+        self.call.adb.Shell('VAR=some_string echo "$VAR"'), ''):
       self.device.RunShellCommand('echo "$VAR"', env={'VAR': 'some_string'})
 
   def testNewRunShellImpl_withEnvQuoted(self):
-    with self.assertShellCall('PATH="$PATH:/other/path" run_this'):
+    with self.assertCall(
+        self.call.adb.Shell('PATH="$PATH:/other/path" run_this'), ''):
       self.device.RunShellCommand('run_this', env={'PATH': '$PATH:/other/path'})
 
   def testNewRunShellImpl_withEnv_failure(self):
@@ -681,132 +603,129 @@
       self.device.RunShellCommand('some_cmd', env={'INVALID NAME': 'value'})
 
   def testNewRunShellImpl_withCwd(self):
-    with self.assertShellCall('cd /some/test/path && ls'):
+    with self.assertCall(self.call.adb.Shell('cd /some/test/path && ls'), ''):
       self.device.RunShellCommand('ls', cwd='/some/test/path')
 
   def testNewRunShellImpl_withCwdQuoted(self):
-    with self.assertShellCall("cd '/some test/path with/spaces' && ls"):
+    with self.assertCall(
+        self.call.adb.Shell("cd '/some test/path with/spaces' && ls"), ''):
       self.device.RunShellCommand('ls', cwd='/some test/path with/spaces')
 
   def testRunShellCommand_withSu(self):
-    with self.assertShellCallSequence([
-        ('su -c ls /root && ! ls /root', ''),
-        ('su -c setprop service.adb.root 0', '')]):
-      self.device.RunShellCommand('setprop service.adb.root 0', as_root=True)
-
-  def testRunShellCommand_withRoot(self):
-    with self.assertShellCallSequence([
-        ('su -c ls /root && ! ls /root', _ShellError()),
-        ('setprop service.adb.root 0', '')]):
+    with self.assertCalls(
+        (self.call.device.NeedsSU(), True),
+        (self.call.adb.Shell('su -c setprop service.adb.root 0'), '')):
       self.device.RunShellCommand('setprop service.adb.root 0', as_root=True)
 
   def testRunShellCommand_manyLines(self):
     cmd = 'ls /some/path'
-    with self.assertShellCall(cmd, 'file1\r\nfile2\r\nfile3\r\n'):
+    with self.assertCall(self.call.adb.Shell(cmd), 'file1\nfile2\nfile3\n'):
       self.assertEquals(['file1', 'file2', 'file3'],
                         self.device.RunShellCommand(cmd))
 
   def testRunShellCommand_singleLine_success(self):
     cmd = 'echo $VALUE'
-    with self.assertShellCall(cmd, 'some value\r\n'):
+    with self.assertCall(self.call.adb.Shell(cmd), 'some value\n'):
       self.assertEquals('some value',
                         self.device.RunShellCommand(cmd, single_line=True))
 
   def testRunShellCommand_singleLine_successEmptyLine(self):
     cmd = 'echo $VALUE'
-    with self.assertShellCall(cmd, '\r\n'):
+    with self.assertCall(self.call.adb.Shell(cmd), '\n'):
       self.assertEquals('',
                         self.device.RunShellCommand(cmd, single_line=True))
 
   def testRunShellCommand_singleLine_successWithoutEndLine(self):
     cmd = 'echo -n $VALUE'
-    with self.assertShellCall(cmd, 'some value'):
+    with self.assertCall(self.call.adb.Shell(cmd), 'some value'):
       self.assertEquals('some value',
                         self.device.RunShellCommand(cmd, single_line=True))
 
   def testRunShellCommand_singleLine_successNoOutput(self):
     cmd = 'echo -n $VALUE'
-    with self.assertShellCall(cmd, ''):
+    with self.assertCall(self.call.adb.Shell(cmd), ''):
       self.assertEquals('',
                         self.device.RunShellCommand(cmd, single_line=True))
 
   def testRunShellCommand_singleLine_failTooManyLines(self):
     cmd = 'echo $VALUE'
-    with self.assertShellCall(cmd, 'some value\r\nanother value\r\n'):
+    with self.assertCall(self.call.adb.Shell(cmd),
+                         'some value\nanother value\n'):
       with self.assertRaises(device_errors.CommandFailedError):
         self.device.RunShellCommand(cmd, single_line=True)
 
   def testRunShellCommand_checkReturn_success(self):
     cmd = 'echo $ANDROID_DATA'
-    output = '/data\r\n'
-    with self.assertShellCall(cmd, output):
+    output = '/data\n'
+    with self.assertCall(self.call.adb.Shell(cmd), output):
       self.assertEquals([output.rstrip()],
                         self.device.RunShellCommand(cmd, check_return=True))
 
   def testRunShellCommand_checkReturn_failure(self):
     cmd = 'ls /root'
-    output = 'opendir failed, Permission denied\r\n'
-    with self.assertShellCall(cmd, _ShellError(output)):
+    output = 'opendir failed, Permission denied\n'
+    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
       with self.assertRaises(device_errors.AdbShellCommandFailedError):
         self.device.RunShellCommand(cmd, check_return=True)
 
   def testRunShellCommand_checkReturn_disabled(self):
     cmd = 'ls /root'
-    output = 'opendir failed, Permission denied\r\n'
-    with self.assertShellCall(cmd, _ShellError(output)):
+    output = 'opendir failed, Permission denied\n'
+    with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
       self.assertEquals([output.rstrip()],
                         self.device.RunShellCommand(cmd, check_return=False))
 
 
+@mock.patch('time.sleep', mock.Mock())
 class DeviceUtilsKillAllTest(DeviceUtilsNewImplTest):
 
   def testKillAll_noMatchingProcesses(self):
-    output = 'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n'
-    with self.assertShellCallSequence([('ps', output)]):
+    with self.assertCall(self.call.adb.Shell('ps'),
+        'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n'):
       with self.assertRaises(device_errors.CommandFailedError):
         self.device.KillAll('test_process')
 
   def testKillAll_nonblocking(self):
-    with self.assertShellCallSequence([
-        ('ps', 'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n'
-               'u0_a1  1234  174   123456 54321 ffffffff 456789ab '
-               'this.is.a.test.process\r\n'),
-        ('kill -9 1234', '')]):
+    with self.assertCalls(
+        (self.call.adb.Shell('ps'),
+         'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n'
+         'u0_a1  1234  174   123456 54321 ffffffff 456789ab some.process\n'),
+        (self.call.adb.Shell('kill -9 1234'), '')):
       self.assertEquals(1,
-          self.device.KillAll('this.is.a.test.process', blocking=False))
+          self.device.KillAll('some.process', blocking=False))
 
   def testKillAll_blocking(self):
-    with mock.patch('time.sleep'):
-      with self.assertShellCallSequence([
-        ('ps', 'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n'
-               'u0_a1  1234  174   123456 54321 ffffffff 456789ab '
-               'this.is.a.test.process\r\n'),
-        ('kill -9 1234', ''),
-        ('ps', 'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n'
-               'u0_a1  1234  174   123456 54321 ffffffff 456789ab '
-               'this.is.a.test.process\r\n'),
-        ('ps', 'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n')]):
-        self.assertEquals(1,
-            self.device.KillAll('this.is.a.test.process', blocking=True))
+    with self.assertCalls(
+        (self.call.adb.Shell('ps'),
+         'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n'
+         'u0_a1  1234  174   123456 54321 ffffffff 456789ab some.process\n'),
+        (self.call.adb.Shell('kill -9 1234'), ''),
+        (self.call.adb.Shell('ps'),
+         'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n'
+         'u0_a1  1234  174   123456 54321 ffffffff 456789ab some.process\n'),
+        (self.call.adb.Shell('ps'),
+         'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n')):
+      self.assertEquals(1,
+          self.device.KillAll('some.process', blocking=True))
 
   def testKillAll_root(self):
-    with self.assertShellCallSequence([
-        ('ps', 'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n'
-               'u0_a1  1234  174   123456 54321 ffffffff 456789ab '
-               'this.is.a.test.process\r\n'),
-        ('su -c ls /root && ! ls /root', ''),
-        ('su -c kill -9 1234', '')]):
+    with self.assertCalls(
+        (self.call.adb.Shell('ps'),
+         'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n'
+         'u0_a1  1234  174   123456 54321 ffffffff 456789ab some.process\n'),
+        (self.call.device.NeedsSU(), True),
+        (self.call.adb.Shell('su -c kill -9 1234'), '')):
       self.assertEquals(1,
-          self.device.KillAll('this.is.a.test.process', as_root=True))
+          self.device.KillAll('some.process', as_root=True))
 
   def testKillAll_sigterm(self):
-    with self.assertShellCallSequence([
-        ('ps', 'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n'
-               'u0_a1  1234  174   123456 54321 ffffffff 456789ab '
-               'this.is.a.test.process\r\n'),
-        ('kill -15 1234', '')]):
+    with self.assertCalls(
+        (self.call.adb.Shell('ps'),
+         'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n'
+         'u0_a1  1234  174   123456 54321 ffffffff 456789ab some.process\n'),
+        (self.call.adb.Shell('kill -15 1234'), '')):
       self.assertEquals(1,
-          self.device.KillAll('this.is.a.test.process', signum=signal.SIGTERM))
+          self.device.KillAll('some.process', signum=signal.SIGTERM))
 
 
 class DeviceUtilsStartActivityTest(DeviceUtilsOldImplTest):
@@ -974,6 +893,48 @@
       self.device.StartActivity(test_intent)
 
 
+class DeviceUtilsStartInstrumentationTest(DeviceUtilsNewImplTest):
+
+  def testStartInstrumentation_nothing(self):
+    with self.assertCalls(
+        self.call.device.RunShellCommand(
+            ['am', 'instrument', 'test.package/.TestInstrumentation'],
+            check_return=True)):
+      self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=False, raw=False, extras=None)
+
+  def testStartInstrumentation_finish(self):
+    with self.assertCalls(
+        (self.call.device.RunShellCommand(
+            ['am', 'instrument', '-w', 'test.package/.TestInstrumentation'],
+            check_return=True),
+         ['OK (1 test)'])):
+      output = self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=True, raw=False, extras=None)
+      self.assertEquals(['OK (1 test)'], output)
+
+  def testStartInstrumentation_raw(self):
+    with self.assertCalls(
+        self.call.device.RunShellCommand(
+            ['am', 'instrument', '-r', 'test.package/.TestInstrumentation'],
+            check_return=True)):
+      self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=False, raw=True, extras=None)
+
+  def testStartInstrumentation_extras(self):
+    with self.assertCalls(
+        self.call.device.RunShellCommand(
+            ['am', 'instrument', '-e', 'foo', 'Foo', '-e', 'bar', 'Bar',
+             'test.package/.TestInstrumentation'],
+            check_return=True)):
+      self.device.StartInstrumentation(
+          'test.package/.TestInstrumentation',
+          finish=False, raw=False, extras={'foo': 'Foo', 'bar': 'Bar'})
+
+
 class DeviceUtilsBroadcastIntentTest(DeviceUtilsOldImplTest):
 
   def testBroadcastIntent_noExtras(self):
@@ -1056,93 +1017,61 @@
 
   def testPushChangedFilesIndividually_empty(self):
     test_files = []
-    self.device._PushChangedFilesIndividually(test_files)
-    self.assertEqual(0, self.adb.Push.call_count)
+    with self.assertCalls():
+      self.device._PushChangedFilesIndividually(test_files)
 
   def testPushChangedFilesIndividually_single(self):
     test_files = [('/test/host/path', '/test/device/path')]
-    self.device._PushChangedFilesIndividually(test_files)
-    self.adb.Push.assert_called_once_with(
-        '/test/host/path', '/test/device/path')
+    with self.assertCalls(self.call.adb.Push(*test_files[0])):
+      self.device._PushChangedFilesIndividually(test_files)
 
   def testPushChangedFilesIndividually_multiple(self):
     test_files = [
         ('/test/host/path/file1', '/test/device/path/file1'),
         ('/test/host/path/file2', '/test/device/path/file2')]
-    self.device._PushChangedFilesIndividually(test_files)
-    self.assertEqual(2, self.adb.Push.call_count)
-    self.adb.Push.assert_any_call(
-        '/test/host/path/file1', '/test/device/path/file1')
-    self.adb.Push.assert_any_call(
-        '/test/host/path/file2', '/test/device/path/file2')
+    with self.assertCalls(
+        self.call.adb.Push(*test_files[0]),
+        self.call.adb.Push(*test_files[1])):
+      self.device._PushChangedFilesIndividually(test_files)
 
 
-@mock.patch('pylib.device.commands.install_commands.Installed', new=None)
-@mock.patch('pylib.device.commands.install_commands.InstallCommands', new=None)
-class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsHybridImplTest):
-
-  def setUp(self):
-    super(DeviceUtilsPushChangedFilesZippedTest, self).setUp()
+class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsNewImplTest):
 
   def testPushChangedFilesZipped_empty(self):
     test_files = []
-    self.device._PushChangedFilesZipped(test_files)
-    self.assertEqual(0, self.adb.Push.call_count)
+    with self.assertCalls():
+      self.device._PushChangedFilesZipped(test_files)
+
+  def _testPushChangedFilesZipped_spec(self, test_files):
+    mock_zip_temp = mock.mock_open()
+    mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
+    with self.assertCalls(
+        (mock.call.tempfile.NamedTemporaryFile(suffix='.zip'), mock_zip_temp),
+        (mock.call.multiprocessing.Process(
+            target=device_utils.DeviceUtils._CreateDeviceZip,
+            args=('/test/temp/file/tmp.zip', test_files)), mock.Mock()),
+        (self.call.device.GetExternalStoragePath(),
+         '/test/device/external_dir'),
+        self.call.adb.Push(
+            '/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip'),
+        self.call.device.RunShellCommand(
+            ['unzip', '/test/device/external_dir/tmp.zip'],
+            as_root=True,
+            env={'PATH': '$PATH:/data/local/tmp/bin'},
+            check_return=True),
+        (self.call.device.IsOnline(), True),
+        self.call.device.RunShellCommand(
+            ['rm', '/test/device/external_dir/tmp.zip'], check_return=True)):
+      self.device._PushChangedFilesZipped(test_files)
 
   def testPushChangedFilesZipped_single(self):
-    test_files = [('/test/host/path/file1', '/test/device/path/file1')]
-
-    self.device._GetExternalStoragePathImpl = mock.Mock(
-        return_value='/test/device/external_dir')
-    self.device.IsOnline = mock.Mock(return_value=True)
-    self.device.RunShellCommand = mock.Mock()
-    mock_zip_temp = mock.mock_open()
-    mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
-    with mock.patch('multiprocessing.Process') as mock_zip_proc, (
-         mock.patch('tempfile.NamedTemporaryFile', mock_zip_temp)):
-      self.device._PushChangedFilesZipped(test_files)
-
-    mock_zip_proc.assert_called_once_with(
-        target=device_utils.DeviceUtils._CreateDeviceZip,
-        args=('/test/temp/file/tmp.zip', test_files))
-    self.adb.Push.assert_called_once_with(
-        '/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip')
-    self.assertEqual(2, self.device.RunShellCommand.call_count)
-    self.device.RunShellCommand.assert_any_call(
-        ['unzip', '/test/device/external_dir/tmp.zip'],
-        as_root=True,
-        env={'PATH': '$PATH:/data/local/tmp/bin'},
-        check_return=True)
-    self.device.RunShellCommand.assert_any_call(
-        ['rm', '/test/device/external_dir/tmp.zip'], check_return=True)
+    self._testPushChangedFilesZipped_spec(
+        [('/test/host/path/file1', '/test/device/path/file1')])
 
   def testPushChangedFilesZipped_multiple(self):
-    test_files = [('/test/host/path/file1', '/test/device/path/file1'),
-                  ('/test/host/path/file2', '/test/device/path/file2')]
-
-    self.device._GetExternalStoragePathImpl = mock.Mock(
-        return_value='/test/device/external_dir')
-    self.device.IsOnline = mock.Mock(return_value=True)
-    self.device.RunShellCommand = mock.Mock()
-    mock_zip_temp = mock.mock_open()
-    mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
-    with mock.patch('multiprocessing.Process') as mock_zip_proc, (
-         mock.patch('tempfile.NamedTemporaryFile', mock_zip_temp)):
-      self.device._PushChangedFilesZipped(test_files)
-
-    mock_zip_proc.assert_called_once_with(
-        target=device_utils.DeviceUtils._CreateDeviceZip,
-        args=('/test/temp/file/tmp.zip', test_files))
-    self.adb.Push.assert_called_once_with(
-        '/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip')
-    self.assertEqual(2, self.device.RunShellCommand.call_count)
-    self.device.RunShellCommand.assert_any_call(
-        ['unzip', '/test/device/external_dir/tmp.zip'],
-        as_root=True,
-        env={'PATH': '$PATH:/data/local/tmp/bin'},
-        check_return=True)
-    self.device.RunShellCommand.assert_any_call(
-        ['rm', '/test/device/external_dir/tmp.zip'], check_return=True)
+    self._testPushChangedFilesZipped_spec(
+        [('/test/host/path/file1', '/test/device/path/file1'),
+         ('/test/host/path/file2', '/test/device/path/file2')])
 
 
 class DeviceUtilsFileExistsTest(DeviceUtilsOldImplTest):
@@ -1370,23 +1299,27 @@
       self.device.WriteFile('/test/file/no.permissions.to.write',
                             'new test file contents', as_root=True)
 
+
 class DeviceUtilsWriteTextFileTest(DeviceUtilsNewImplTest):
 
   def testWriteTextFileTest_basic(self):
-    with self.assertShellCall('echo some.string > /test/file/to.write'):
+    with self.assertCall(
+        self.call.adb.Shell('echo some.string > /test/file/to.write'), ''):
       self.device.WriteTextFile('/test/file/to.write', 'some.string')
 
   def testWriteTextFileTest_quoted(self):
-    with self.assertShellCall(
-        "echo 'some other string' > '/test/file/to write'"):
+    with self.assertCall(
+        self.call.adb.Shell("echo 'some other string' > '/test/file/to write'"),
+        ''):
       self.device.WriteTextFile('/test/file/to write', 'some other string')
 
-  def testWriteTextFileTest_asRoot(self):
-    with self.assertShellCallSequence([
-        ('su -c ls /root && ! ls /root', ''),
-        ('su -c echo string > /test/file', '')]):
+  def testWriteTextFileTest_withSU(self):
+    with self.assertCalls(
+        (self.call.device.NeedsSU(), True),
+        (self.call.adb.Shell('su -c echo string > /test/file'), '')):
       self.device.WriteTextFile('/test/file', 'string', as_root=True)
 
+
 class DeviceUtilsLsTest(DeviceUtilsOldImplTest):
 
   def testLs_nothing(self):
@@ -1512,29 +1445,29 @@
 class DeviceUtilsGetPropTest(DeviceUtilsNewImplTest):
 
   def testGetProp_exists(self):
-    with self.assertShellCall('getprop this.is.a.test.property',
-                              'test_property_value\r\n'):
-      self.assertEqual('test_property_value',
-                       self.device.GetProp('this.is.a.test.property'))
+    with self.assertCall(
+        self.call.adb.Shell('getprop test.property'), 'property_value\n'):
+      self.assertEqual('property_value',
+                       self.device.GetProp('test.property'))
 
   def testGetProp_doesNotExist(self):
-    with self.assertShellCall('getprop this.property.does.not.exist',
-                              '\r\n'):
-      self.assertEqual('', self.device.GetProp('this.property.does.not.exist'))
+    with self.assertCall(
+        self.call.adb.Shell('getprop property.does.not.exist'), '\n'):
+      self.assertEqual('', self.device.GetProp('property.does.not.exist'))
 
   def testGetProp_cachedRoProp(self):
-    with self.assertShellCall('getprop ro.build.type',
-                              'userdebug\r\n'):
+    with self.assertCall(
+        self.call.adb.Shell('getprop ro.build.type'), 'userdebug\n'):
       self.assertEqual('userdebug',
                        self.device.GetProp('ro.build.type', cache=True))
       self.assertEqual('userdebug',
                        self.device.GetProp('ro.build.type', cache=True))
 
   def testGetProp_retryAndCache(self):
-    with self.assertShellCallSequence([
-        ('getprop ro.build.type', _ShellError()),
-        ('getprop ro.build.type', _ShellError()),
-        ('getprop ro.build.type', 'userdebug\r\n')]):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.type'), self.ShellError()),
+        (self.call.adb.Shell('getprop ro.build.type'), self.ShellError()),
+        (self.call.adb.Shell('getprop ro.build.type'), 'userdebug\n')):
       self.assertEqual('userdebug',
                        self.device.GetProp('ro.build.type',
                                            cache=True, retries=3))
@@ -1546,46 +1479,55 @@
 class DeviceUtilsSetPropTest(DeviceUtilsNewImplTest):
 
   def testSetProp(self):
-    with self.assertShellCall(
-      "setprop this.is.a.test.property 'test property value'"):
-      self.device.SetProp('this.is.a.test.property', 'test property value')
+    with self.assertCall(
+        self.call.adb.Shell("setprop test.property 'test value'"), ''):
+      self.device.SetProp('test.property', 'test value')
+
+  def testSetProp_check_succeeds(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('setprop test.property new_value'), ''),
+        (self.call.adb.Shell('getprop test.property'), 'new_value')):
+      self.device.SetProp('test.property', 'new_value', check=True)
+
+  def testSetProp_check_fails(self):
+    with self.assertCalls(
+        (self.call.adb.Shell('setprop test.property new_value'), ''),
+        (self.call.adb.Shell('getprop test.property'), 'old_value')):
+      with self.assertRaises(device_errors.CommandFailedError):
+        self.device.SetProp('test.property', 'new_value', check=True)
 
 
 class DeviceUtilsGetPidsTest(DeviceUtilsNewImplTest):
 
   def testGetPids_noMatches(self):
-    with self.assertShellCall(
-        'ps',
-        'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n'
-        'user  1000    100   1024 1024   ffffffff 00000000 no.match\r\n'):
+    with self.assertCall(self.call.adb.Shell('ps'),
+        'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n'
+        'user  1000    100   1024 1024   ffffffff 00000000 no.match\n'):
       self.assertEqual({}, self.device.GetPids('does.not.match'))
 
   def testGetPids_oneMatch(self):
-    with self.assertShellCall(
-        'ps',
-        'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n'
-        'user  1000    100   1024 1024   ffffffff 00000000 not.a.match\r\n'
-        'user  1001    100   1024 1024   ffffffff 00000000 one.match\r\n'):
+    with self.assertCall(self.call.adb.Shell('ps'),
+        'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n'
+        'user  1000    100   1024 1024   ffffffff 00000000 not.a.match\n'
+        'user  1001    100   1024 1024   ffffffff 00000000 one.match\n'):
       self.assertEqual({'one.match': '1001'}, self.device.GetPids('one.match'))
 
   def testGetPids_mutlipleMatches(self):
-    with self.assertShellCall(
-        'ps',
-        'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n'
-        'user  1000    100   1024 1024   ffffffff 00000000 not\r\n'
-        'user  1001    100   1024 1024   ffffffff 00000000 one.match\r\n'
-        'user  1002    100   1024 1024   ffffffff 00000000 two.match\r\n'
-        'user  1003    100   1024 1024   ffffffff 00000000 three.match\r\n'):
+    with self.assertCall(self.call.adb.Shell('ps'),
+        'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n'
+        'user  1000    100   1024 1024   ffffffff 00000000 not\n'
+        'user  1001    100   1024 1024   ffffffff 00000000 one.match\n'
+        'user  1002    100   1024 1024   ffffffff 00000000 two.match\n'
+        'user  1003    100   1024 1024   ffffffff 00000000 three.match\n'):
       self.assertEqual(
           {'one.match': '1001', 'two.match': '1002', 'three.match': '1003'},
           self.device.GetPids('match'))
 
   def testGetPids_exactMatch(self):
-    with self.assertShellCall(
-        'ps',
-        'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\r\n'
-        'user  1000    100   1024 1024   ffffffff 00000000 not.exact.match\r\n'
-        'user  1234    100   1024 1024   ffffffff 00000000 exact.match\r\n'):
+    with self.assertCall(self.call.adb.Shell('ps'),
+        'USER   PID   PPID  VSIZE  RSS   WCHAN    PC       NAME\n'
+        'user  1000    100   1024 1024   ffffffff 00000000 not.exact.match\n'
+        'user  1234    100   1024 1024   ffffffff 00000000 exact.match\n'):
       self.assertEqual(
           {'not.exact.match': '1000', 'exact.match': '1234'},
           self.device.GetPids('exact.match'))
@@ -1668,6 +1610,7 @@
 
 
 class DeviceUtilsStrTest(DeviceUtilsOldImplTest):
+
   def testStr_noAdbCalls(self):
     with self.assertNoAdbCalls():
       self.assertEqual('0123456789abcdef', str(self.device))
diff --git a/build/android/pylib/forwarder.py b/build/android/pylib/forwarder.py
index 5e45043..5f40a94 100644
--- a/build/android/pylib/forwarder.py
+++ b/build/android/pylib/forwarder.py
@@ -270,6 +270,7 @@
       pid_file.seek(0)
       pid_file.write(
           '%s:%s' % (pid_for_lock, str(_GetProcessStartTime(pid_for_lock))))
+      pid_file.truncate()
 
   def _InitDeviceLocked(self, device, tool):
     """Initializes the device_forwarder daemon for a specific device (once).
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py
index 75892ee..56e7449 100644
--- a/build/android/pylib/gtest/test_runner.py
+++ b/build/android/pylib/gtest/test_runner.py
@@ -7,9 +7,11 @@
 import re
 
 from pylib import pexpect
+from pylib import ports
 from pylib.base import base_test_result
 from pylib.base import base_test_runner
 from pylib.device import device_errors
+from pylib.local import local_test_server_spawner
 from pylib.perf import perf_control
 
 
@@ -53,6 +55,13 @@
     if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
       self._perf_controller = perf_control.PerfControl(self.device)
 
+    if _TestSuiteRequiresMockTestServer(self.test_package.suite_name):
+      self._servers = [
+          local_test_server_spawner.LocalTestServerSpawner(
+              ports.AllocateTestServerPort(), self.device, self.tool)]
+    else:
+      self._servers = []
+
   #override
   def InstallTestPackage(self):
     self.test_package.Install(self.device)
@@ -149,7 +158,8 @@
       test_results = self._ParseTestOutput(
           self.test_package.SpawnTestProcess(self.device))
     finally:
-      self.CleanupSpawningServerState()
+      for s in self._servers:
+        s.Reset()
     # Calculate unknown test results.
     all_tests = set(test.split(':'))
     all_tests_ran = set([t.GetName() for t in test_results.GetAll()])
@@ -164,8 +174,8 @@
   def SetUp(self):
     """Sets up necessary test enviroment for the test suite."""
     super(TestRunner, self).SetUp()
-    if _TestSuiteRequiresMockTestServer(self.test_package.suite_name):
-      self.LaunchChromeTestServerSpawner()
+    for s in self._servers:
+      s.SetUp()
     if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
       self._perf_controller.SetHighPerfMode()
     self.tool.SetupEnvironment()
@@ -173,6 +183,8 @@
   #override
   def TearDown(self):
     """Cleans up the test enviroment for the test suite."""
+    for s in self._servers:
+      s.TearDown()
     if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
       self._perf_controller.SetDefaultPerfMode()
     self.test_package.ClearApplicationState(self.device)
diff --git a/build/android/pylib/instrumentation/test_jar.py b/build/android/pylib/instrumentation/test_jar.py
index c81258f..d83d00a 100644
--- a/build/android/pylib/instrumentation/test_jar.py
+++ b/build/android/pylib/instrumentation/test_jar.py
@@ -23,7 +23,7 @@
 import unittest_util # pylint: disable=F0401
 
 # If you change the cached output of proguard, increment this number
-PICKLE_FORMAT_VERSION = 2
+PICKLE_FORMAT_VERSION = 3
 
 
 class TestJar(object):
@@ -55,6 +55,16 @@
     if not self._GetCachedProguardData():
       self._GetProguardData()
 
+  @staticmethod
+  def _CalculateMd5(path):
+    # TODO(jbudorick): Move MD5sum calculations out of here and
+    # AndroidCommands to their own module.
+    out = cmd_helper.GetCmdOutput(
+        [os.path.join(constants.GetOutDirectory(),
+                      'md5sum_bin_host'),
+        path])
+    return out
+
   def _GetCachedProguardData(self):
     if (os.path.exists(self._pickled_proguard_name) and
         (os.path.getmtime(self._pickled_proguard_name) >
@@ -64,7 +74,9 @@
       try:
         with open(self._pickled_proguard_name, 'r') as r:
           d = pickle.loads(r.read())
-        if d['VERSION'] == PICKLE_FORMAT_VERSION:
+        jar_md5 = self._CalculateMd5(self._jar_path)
+        if (d['JAR_MD5SUM'] == jar_md5 and
+            d['VERSION'] == PICKLE_FORMAT_VERSION):
           self._test_methods = d['TEST_METHODS']
           return True
       except:
@@ -182,7 +194,8 @@
 
     logging.info('Storing proguard output to %s', self._pickled_proguard_name)
     d = {'VERSION': PICKLE_FORMAT_VERSION,
-         'TEST_METHODS': self._test_methods}
+         'TEST_METHODS': self._test_methods,
+         'JAR_MD5SUM': self._CalculateMd5(self._jar_path)}
     with open(self._pickled_proguard_name, 'w') as f:
       f.write(pickle.dumps(d))
 
diff --git a/build/android/pylib/instrumentation/test_result.py b/build/android/pylib/instrumentation/test_result.py
index a0eea65..24e80a8 100644
--- a/build/android/pylib/instrumentation/test_result.py
+++ b/build/android/pylib/instrumentation/test_result.py
@@ -18,7 +18,8 @@
       dur: Duration of the test run in milliseconds.
       log: A string listing any errors.
     """
-    super(InstrumentationTestResult, self).__init__(full_name, test_type, log)
+    super(InstrumentationTestResult, self).__init__(
+        full_name, test_type, dur, log)
     name_pieces = full_name.rsplit('#')
     if len(name_pieces) > 1:
       self._test_name = name_pieces[1]
@@ -27,8 +28,3 @@
       self._class_name = full_name
       self._test_name = full_name
     self._start_date = start_date
-    self._dur = dur
-
-  def GetDur(self):
-    """Get the test duration."""
-    return self._dur
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py
index 3bac503..60e00f3 100644
--- a/build/android/pylib/instrumentation/test_runner.py
+++ b/build/android/pylib/instrumentation/test_runner.py
@@ -369,16 +369,11 @@
     Returns:
       The raw output of am instrument as a list of lines.
     """
-    # Build the 'am instrument' command
-    instrumentation_path = (
-        '%s/%s' % (self.test_pkg.GetPackageName(), self.options.test_runner))
-
-    cmd = ['am', 'instrument', '-r']
-    for k, v in self._GetInstrumentationArgs().iteritems():
-      cmd.extend(['-e', k, v])
-    cmd.extend(['-e', 'class', test])
-    cmd.extend(['-w', instrumentation_path])
-    return self.device.RunShellCommand(cmd, timeout=timeout, retries=0)
+    extras = self._GetInstrumentationArgs()
+    extras['class'] = test
+    return self.device.StartInstrumentation(
+        '%s/%s' % (self.test_pkg.GetPackageName(), self.options.test_runner),
+        raw=True, extras=extras, timeout=timeout, retries=0)
 
   @staticmethod
   def _ParseAmInstrumentRawOutput(raw_output):
@@ -506,7 +501,7 @@
                self.tool.GetTimeoutScale())
     if (self.device.GetProp('ro.build.version.sdk')
         < constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN):
-      timeout *= 4
+      timeout *= 10
 
     start_ms = 0
     duration_ms = 0
diff --git a/build/android/pylib/instrumentation/test_runner_test.py b/build/android/pylib/instrumentation/test_runner_test.py
index 039bb03..0f2845e 100755
--- a/build/android/pylib/instrumentation/test_runner_test.py
+++ b/build/android/pylib/instrumentation/test_runner_test.py
@@ -144,7 +144,7 @@
     self.assertEqual('test.package.TestClass#testMethod', result.GetName())
     self.assertEqual(base_test_result.ResultType.UNKNOWN, result.GetType())
     self.assertEqual('', result.GetLog())
-    self.assertEqual(1000, result.GetDur())
+    self.assertEqual(1000, result.GetDuration())
 
   def testGenerateTestResult_testPassed(self):
     statuses = [
@@ -253,17 +253,18 @@
 
   def test_RunTest_verifyAdbShellCommand(self):
     self.instance.options.test_runner = 'MyTestRunner'
-    self.instance.device.RunShellCommand = mock.Mock()
+    self.instance.device.StartInstrumentation = mock.Mock()
     self.instance.test_pkg.GetPackageName = mock.Mock(
         return_value='test.package')
     self.instance._GetInstrumentationArgs = mock.Mock(
         return_value={'test_arg_key': 'test_arg_value'})
     self.instance._RunTest('test.package.TestClass#testMethod', 100)
-    self.instance.device.RunShellCommand.assert_called_with(
-        ['am', 'instrument', '-r',
-         '-e', 'test_arg_key', 'test_arg_value',
-         '-e', 'class', 'test.package.TestClass#testMethod',
-         '-w', 'test.package/MyTestRunner'],
+    self.instance.device.StartInstrumentation.assert_called_with(
+        'test.package/MyTestRunner', raw=True,
+        extras={
+            'test_arg_key': 'test_arg_value',
+            'class': 'test.package.TestClass#testMethod'
+        },
         timeout=100, retries=0)
 
 if __name__ == '__main__':
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py
index 446bc84..f64a58b 100644
--- a/build/android/pylib/linker/test_case.py
+++ b/build/android/pylib/linker/test_case.py
@@ -340,7 +340,7 @@
         base_test_result.BaseTestResult(
             self.tagged_name,
             status,
-            logs))
+            log=logs))
 
     return results
 
diff --git a/build/android/pylib/local/__init__.py b/build/android/pylib/local/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/local/__init__.py
@@ -0,0 +1,3 @@
+# 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.
diff --git a/build/android/pylib/local/local_test_server_spawner.py b/build/android/pylib/local/local_test_server_spawner.py
new file mode 100644
index 0000000..77f552e
--- /dev/null
+++ b/build/android/pylib/local/local_test_server_spawner.py
@@ -0,0 +1,45 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from pylib import chrome_test_server_spawner
+from pylib import forwarder
+from pylib.base import test_server
+
+
+class LocalTestServerSpawner(test_server.TestServer):
+
+  def __init__(self, port, device, tool):
+    super(LocalTestServerSpawner, self).__init__()
+    self._device = device
+    self._spawning_server = chrome_test_server_spawner.SpawningServer(
+        port, device, tool)
+    self._tool = tool
+
+  @property
+  def server_address(self):
+    return self._spawning_server.server.server_address
+
+  @property
+  def port(self):
+    return self.server_address[1]
+
+  #override
+  def SetUp(self):
+    self._device.WriteFile(
+        '%s/net-test-server-ports' % self._device.GetExternalStoragePath(),
+        '%s:0' % str(self.port))
+    forwarder.Forwarder.Map(
+        [(self.port, self.port)], self._device, self._tool)
+    self._spawning_server.Start()
+
+  #override
+  def Reset(self):
+    self._spawning_server.CleanupState()
+
+  #override
+  def TearDown(self):
+    self.Reset()
+    self._spawning_server.Stop()
+    forwarder.Forwarder.UnmapDevicePort(self.port, self._device)
+
diff --git a/build/android/pylib/uiautomator/test_package.py b/build/android/pylib/uiautomator/test_package.py
index fd9120e..cb51fdf 100644
--- a/build/android/pylib/uiautomator/test_package.py
+++ b/build/android/pylib/uiautomator/test_package.py
@@ -11,6 +11,11 @@
 
 
 class TestPackage(test_jar.TestJar):
+
+  UIAUTOMATOR_PATH = 'uiautomator/'
+  UIAUTOMATOR_DEVICE_DIR = os.path.join(constants.TEST_EXECUTABLE_DIR,
+                                        UIAUTOMATOR_PATH)
+
   def __init__(self, jar_path, jar_info_path):
     test_jar.TestJar.__init__(self, jar_info_path)
 
@@ -24,4 +29,5 @@
 
   # Override.
   def Install(self, device):
-    device.PushChangedFiles([(self._jar_path, constants.TEST_EXECUTABLE_DIR)])
+    device.PushChangedFiles([(self._jar_path, self.UIAUTOMATOR_DEVICE_DIR +
+                              self.GetPackageName())])
diff --git a/build/android/pylib/uiautomator/test_runner.py b/build/android/pylib/uiautomator/test_runner.py
index c0f8f15..f4e5730 100644
--- a/build/android/pylib/uiautomator/test_runner.py
+++ b/build/android/pylib/uiautomator/test_runner.py
@@ -73,7 +73,8 @@
                       package=self._package),
         blocking=True,
         force_stop=True)
-    cmd = ['uiautomator', 'runtest', self.test_pkg.GetPackageName(),
+    cmd = ['uiautomator', 'runtest',
+           self.test_pkg.UIAUTOMATOR_PATH + self.test_pkg.GetPackageName(),
            '-e', 'class', test]
     return self.device.RunShellCommand(cmd, timeout=timeout, retries=0)
 
diff --git a/build/android/pylib/utils/flakiness_dashboard_results_uploader.py b/build/android/pylib/utils/flakiness_dashboard_results_uploader.py
index 246c83b..ff286b6 100644
--- a/build/android/pylib/utils/flakiness_dashboard_results_uploader.py
+++ b/build/android/pylib/utils/flakiness_dashboard_results_uploader.py
@@ -131,7 +131,7 @@
         test_result = json_results_generator.TestResult(
             test=single_test_result.GetName(),
             failed=failed,
-            elapsed_time=single_test_result.GetDur() / 1000)
+            elapsed_time=single_test_result.GetDuration() / 1000)
         # The WebKit TestResult object sets the modifier it based on test name.
         # Since we don't use the same test naming convention as WebKit the
         # modifier will be wrong, so we need to overwrite it.
diff --git a/build/android/pylib/utils/isolator.py b/build/android/pylib/utils/isolator.py
index 9ee5671..afbee2a 100644
--- a/build/android/pylib/utils/isolator.py
+++ b/build/android/pylib/utils/isolator.py
@@ -32,7 +32,6 @@
     'component': 'static_library',
     'fastbuild': '0',
     'icu_use_data_file_flag': '1',
-    'libpeer_target_type': 'static_library',
     'lsan': '0',
     # TODO(maruel): This may not always be true.
     'target_arch': 'arm',
diff --git a/build/android/pylib/utils/mock_calls.py b/build/android/pylib/utils/mock_calls.py
new file mode 100755
index 0000000..1f9d8e3
--- /dev/null
+++ b/build/android/pylib/utils/mock_calls.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+A test facility to assert call sequences while mocking their behavior.
+"""
+
+import os
+import sys
+import unittest
+
+from pylib import constants
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class TestCase(unittest.TestCase):
+  """Adds assertCalls to TestCase objects."""
+  class _AssertCalls(object):
+    def __init__(self, test_case, expected_calls, watched):
+      def call_action(pair):
+        if isinstance(pair, type(mock.call)):
+          return (pair, None)
+        else:
+          return pair
+
+      def do_check(call):
+        def side_effect(*args, **kwargs):
+          received_call = call(*args, **kwargs)
+          self._test_case.assertTrue(
+              self._expected_calls,
+              msg=('Unexpected call: %s' % str(received_call)))
+          expected_call, action = self._expected_calls.pop(0)
+          self._test_case.assertTrue(
+              received_call == expected_call,
+              msg=('Expected call missmatch:\n'
+                   '  expected: %s\n'
+                   '  received: %s\n'
+                   % (str(expected_call), str(received_call))))
+          if callable(action):
+            return action(*args, **kwargs)
+          else:
+            return action
+        return side_effect
+
+      self._test_case = test_case
+      self._expected_calls = [call_action(pair) for pair in expected_calls]
+      watched = watched.copy() # do not pollute the caller's dict
+      watched.update((call.parent.name, call.parent)
+                     for call, _ in self._expected_calls)
+      self._patched = [test_case.patch_call(call, side_effect=do_check(call))
+                       for call in watched.itervalues()]
+
+    def __enter__(self):
+      for patch in self._patched:
+        patch.__enter__()
+      return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+      for patch in self._patched:
+        patch.__exit__(exc_type, exc_val, exc_tb)
+      if exc_type is None:
+        missing = ''.join('  expected: %s\n' % str(call)
+                          for call, _ in self._expected_calls)
+        self._test_case.assertFalse(
+            missing,
+            msg='Expected calls not found:\n' + missing)
+
+  def __init__(self, *args, **kwargs):
+    super(TestCase, self).__init__(*args, **kwargs)
+    self.call = mock.call.self
+    self._watched = {}
+
+  def call_target(self, call):
+    """Resolve a self.call instance to the target it represents.
+
+    Args:
+      call: a self.call instance, e.g. self.call.adb.Shell
+
+    Returns:
+      The target object represented by the call, e.g. self.adb.Shell
+
+    Raises:
+      ValueError if the path of the call does not start with "self", i.e. the
+          target of the call is external to the self object.
+      AttributeError if the path of the call does not specify a valid
+          chain of attributes (without any calls) starting from "self".
+    """
+    path = call.name.split('.')
+    if path.pop(0) != 'self':
+      raise ValueError("Target %r outside of 'self' object" % call.name)
+    target = self
+    for attr in path:
+      target = getattr(target, attr)
+    return target
+
+  def patch_call(self, call, **kwargs):
+    """Patch the target of a mock.call instance.
+
+    Args:
+      call: a mock.call instance identifying a target to patch
+      Extra keyword arguments are processed by mock.patch
+
+    Returns:
+      A context manager to mock/unmock the target of the call
+    """
+    if call.name.startswith('self.'):
+      target = self.call_target(call.parent)
+      _, attribute = call.name.rsplit('.', 1)
+      return mock.patch.object(target, attribute, **kwargs)
+    else:
+      return mock.patch(call.name, **kwargs)
+
+  def watchCalls(self, calls):
+    """Add calls to the set of watched calls.
+
+    Args:
+      calls: a sequence of mock.call instances identifying targets to watch
+    """
+    self._watched.update((call.name, call) for call in calls)
+
+  def watchMethodCalls(self, call):
+    """Watch all public methods of the target identified by a self.call.
+
+    Args:
+      call: a self.call instance indetifying an object
+    """
+    target = self.call_target(call)
+    self.watchCalls(getattr(call, method)
+                    for method in dir(target.__class__)
+                    if not method.startswith('_'))
+
+  def clearWatched(self):
+    """Clear the set of watched calls."""
+    self._watched = {}
+
+  def assertCalls(self, *calls):
+    """A context manager to assert that a sequence of calls is made.
+
+    During the assertion, a number of functions and methods will be "watched",
+    and any calls made to them is expected to appear---in the exact same order,
+    and with the exact same arguments---as specified by the argument |calls|.
+
+    By default, the targets of all expected calls are watched. Further targets
+    to watch may be added using watchCalls and watchMethodCalls.
+
+    Optionaly, each call may be accompanied by an action. If the action is a
+    (non-callable) value, this value will be used as the return value given to
+    the caller when the matching call is found. Alternatively, if the action is
+    a callable, the action will be then called with the same arguments as the
+    intercepted call, so that it can provide a return value or perform other
+    side effects. If the action is missing, a return value of None is assumed.
+
+    Note that mock.Mock objects are often convenient to use as a callable
+    action, e.g. to raise exceptions or return other objects which are
+    themselves callable.
+
+    Args:
+      calls: each argument is either a pair (expected_call, action) or just an
+          expected_call, where expected_call is a mock.call instance.
+
+    Raises:
+      AssertionError if the watched targets do not receive the exact sequence
+          of calls specified. Missing calls, extra calls, and calls with
+          mismatching arguments, all cause the assertion to fail.
+    """
+    return self._AssertCalls(self, calls, self._watched)
+
+  def assertCall(self, call, action=None):
+    return self.assertCalls((call, action))
+
diff --git a/build/android/pylib/utils/mock_calls_test.py b/build/android/pylib/utils/mock_calls_test.py
new file mode 100755
index 0000000..1b474af
--- /dev/null
+++ b/build/android/pylib/utils/mock_calls_test.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Unit tests for the contents of mock_calls.py.
+"""
+
+import logging
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.utils import mock_calls
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class _DummyAdb(object):
+  def __str__(self):
+    return '0123456789abcdef'
+
+  def Push(self, host_path, device_path):
+    logging.debug('(device %s) pushing %r to %r', self, host_path, device_path)
+
+  def IsOnline(self):
+    logging.debug('(device %s) checking device online', self)
+    return True
+
+  def Shell(self, cmd):
+    logging.debug('(device %s) running command %r', self, cmd)
+    return "nice output\n"
+
+  def Reboot(self):
+    logging.debug('(device %s) rebooted!', self)
+
+
+class TestCaseWithAssertCallsTest(mock_calls.TestCase):
+  def setUp(self):
+    self.adb = _DummyAdb()
+
+  def ShellError(self):
+    def action(cmd):
+      raise ValueError('(device %s) command %r is not nice' % (self.adb, cmd))
+    return action
+
+  def get_answer(self):
+    logging.debug("called 'get_answer' of %r object", self)
+    return 42
+
+  def echo(self, thing):
+    logging.debug("called 'echo' of %r object", self)
+    return thing
+
+  def testCallTarget_succeds(self):
+    self.assertEquals(self.adb.Shell,
+                      self.call_target(self.call.adb.Shell))
+
+  def testCallTarget_failsExternal(self):
+    with self.assertRaises(ValueError):
+      self.call_target(mock.call.sys.getcwd)
+
+  def testCallTarget_failsUnknownAttribute(self):
+    with self.assertRaises(AttributeError):
+      self.call_target(self.call.adb.Run)
+
+  def testCallTarget_failsIntermediateCalls(self):
+    with self.assertRaises(AttributeError):
+      self.call_target(self.call.adb.RunShell('cmd').append)
+
+  def testPatchCall_method(self):
+    self.assertEquals(42, self.get_answer())
+    with self.patch_call(self.call.get_answer, return_value=123):
+      self.assertEquals(123, self.get_answer())
+    self.assertEquals(42, self.get_answer())
+
+  def testPatchCall_attribute_method(self):
+    with self.patch_call(self.call.adb.Shell, return_value='hello'):
+      self.assertEquals('hello', self.adb.Shell('echo hello'))
+
+  def testPatchCall_global(self):
+    with self.patch_call(mock.call.os.getcwd, return_value='/some/path'):
+      self.assertEquals('/some/path', os.getcwd())
+
+  def testPatchCall_withSideEffect(self):
+    with self.patch_call(self.call.adb.Shell, side_effect=ValueError):
+      with self.assertRaises(ValueError):
+        self.adb.Shell('echo hello')
+
+  def testAssertCalls_succeeds_simple(self):
+    self.assertEquals(42, self.get_answer())
+    with self.assertCall(self.call.get_answer(), 123):
+      self.assertEquals(123, self.get_answer())
+    self.assertEquals(42, self.get_answer())
+
+  def testAssertCalls_succeeds_multiple(self):
+    with self.assertCalls(
+        (mock.call.os.getcwd(), '/some/path'),
+        (self.call.echo('hello'), 'hello'),
+        (self.call.get_answer(), 11),
+        self.call.adb.Push('this_file', 'that_file'),
+        (self.call.get_answer(), 12)):
+      self.assertEquals(os.getcwd(), '/some/path')
+      self.assertEquals('hello', self.echo('hello'))
+      self.assertEquals(11, self.get_answer())
+      self.adb.Push('this_file', 'that_file')
+      self.assertEquals(12, self.get_answer())
+
+  def testAsserCalls_succeeds_withAction(self):
+    with self.assertCall(
+        self.call.adb.Shell('echo hello'), self.ShellError()):
+      with self.assertRaises(ValueError):
+        self.adb.Shell('echo hello')
+
+  def testAssertCalls_fails_tooManyCalls(self):
+    with self.assertRaises(AssertionError):
+      with self.assertCalls(self.call.adb.IsOnline()):
+        self.adb.IsOnline()
+        self.adb.IsOnline()
+
+  def testAssertCalls_fails_tooFewCalls(self):
+    with self.assertRaises(AssertionError):
+      with self.assertCalls(self.call.adb.IsOnline()):
+        pass
+
+  def testAssertCalls_succeeds_extraCalls(self):
+    # we are not watching Reboot, so the assertion succeeds
+    with self.assertCalls(self.call.adb.IsOnline()):
+      self.adb.IsOnline()
+      self.adb.Reboot()
+
+  def testAssertCalls_fails_extraCalls(self):
+    self.watchCalls([self.call.adb.Reboot])
+    # this time we are also watching Reboot, so the assertion fails
+    with self.assertRaises(AssertionError):
+      with self.assertCalls(self.call.adb.IsOnline()):
+        self.adb.IsOnline()
+        self.adb.Reboot()
+
+  def testAssertCalls_succeeds_NoCalls(self):
+    self.watchMethodCalls(self.call.adb) # we are watching all adb methods
+    with self.assertCalls():
+      pass
+
+  def testAssertCalls_fails_NoCalls(self):
+    self.watchMethodCalls(self.call.adb)
+    with self.assertRaises(AssertionError):
+      with self.assertCalls():
+        self.adb.IsOnline()
+
+
+if __name__ == '__main__':
+  logging.getLogger().setLevel(logging.DEBUG)
+  unittest.main(verbosity=2)
+
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 2e39c3c..d5c9b35 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -64,6 +64,11 @@
   group.add_option('--build-directory', dest='build_directory',
                    help=('Path to the directory in which build files are'
                          ' located (should not include build type)'))
+  group.add_option('--output-directory', dest='output_directory',
+                   help=('Path to the directory in which build files are'
+                         ' located (must include build type). This will take'
+                         ' precedence over --debug, --release and'
+                         ' --build-directory'))
   group.add_option('--num_retries', dest='num_retries', type='int',
                    default=2,
                    help=('Number of retries for a test before '
@@ -95,6 +100,8 @@
   constants.SetBuildType(options.build_type)
   if options.build_directory:
     constants.SetBuildDirectory(options.build_directory)
+  if options.output_directory:
+    constants.SetOutputDirectort(options.output_directory)
   if options.environment not in constants.VALID_ENVIRONMENTS:
     error_func('--environment must be one of: %s' %
                ', '.join(constants.VALID_ENVIRONMENTS))
diff --git a/build/common.gypi b/build/common.gypi
index 753abfe..3ddb01a 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -505,25 +505,9 @@
       # tool explicitly.
       # See third_party/cld_2/cld_2.gyp for more information.
       #   0: Small tables, lower accuracy
-      #   1: Medium tables, medium accuracy
       #   2: Large tables, high accuracy
       'cld2_table_size%': 2,
 
-      # The data acquisition mode for CLD2. Possible values are:
-      #   static:     CLD2 data is statically linked to the executable.
-      #   standalone: CLD2 data is provided in a standalone file that is
-      #               bundled with the executable.
-      #   component:  CLD2 data is provided as a Chrome "component" and is
-      #               downloaded via the component updater.
-      #
-      # For more information on switching the CLD2 data source, see:
-      #   https://sites.google.com/a/chromium.org/dev/developers/how-tos/compact-language-detector-cld-data-source-configuration
-      #
-      # This string will be exposed in chrome://translate-internals under the
-      # heading "CLD Data Source". This allows easy determination of which
-      # data source the browser was built with.
-      'cld2_data_source%': 'static',
-
       # Enable spell checker.
       'enable_spellcheck%': 1,
 
@@ -564,12 +548,6 @@
       # components.
       'use_icu_alternatives_on_android%': 0,
 
-      # XInput2 multitouch support is enabled by default (use_xi2_mt=2).
-      # Setting to zero value disables XI2 MT. When XI2 MT is enabled,
-      # the input value also defines the required XI2 minor minimum version.
-      # For example, use_xi2_mt=2 means XI2.2 or above version is required.
-      'use_xi2_mt%': 2,
-
       # Use of precompiled headers on Windows.
       #
       # This variable may be explicitly set to 1 (enabled) or 0
@@ -813,6 +791,7 @@
           'enable_basic_printing%': 0,
           'enable_print_preview%': 0,
           'enable_session_service%': 0,
+          'enable_spellcheck%': 0,
           'enable_themes%': 0,
           'enable_webrtc%': 0,
           'notifications%': 0,
@@ -1113,7 +1092,6 @@
     'chromecast%': '<(chromecast)',
     'enable_viewport%': '<(enable_viewport)',
     'enable_hidpi%': '<(enable_hidpi)',
-    'use_xi2_mt%':'<(use_xi2_mt)',
     'image_loader_extension%': '<(image_loader_extension)',
     'fastbuild%': '<(fastbuild)',
     'dont_embed_build_metadata%': '<(dont_embed_build_metadata)',
@@ -1186,7 +1164,6 @@
     'enable_google_now%': '<(enable_google_now)',
     'cld_version%': '<(cld_version)',
     'cld2_table_size%': '<(cld2_table_size)',
-    'cld2_data_source%': '<(cld2_data_source)',
     'enable_captive_portal_detection%': '<(enable_captive_portal_detection)',
     'disable_file_support%': '<(disable_file_support)',
     'disable_ftp_support%': '<(disable_ftp_support)',
@@ -1488,7 +1465,6 @@
     # IPC fuzzer is disabled by default.
     'enable_ipc_fuzzer%': 0,
 
-
     # Force disable libstdc++ debug mode.
     'disable_glibcxx_debug%': 0,
 
@@ -1509,6 +1485,12 @@
     'ozone_platform_ozonex%': 0,
     'ozone_platform_test%': 0,
 
+    # Whether the browser is non-native (using Views Toolkit) on Mac.
+    'mac_views_browser%': 0,
+
+    # Experiment: http://crbug.com/426914
+    'envoy%': 0,
+
     'conditions': [
       ['buildtype=="Official"', {
         # Continue to embed build meta data in Official builds, basically the
@@ -2070,8 +2052,11 @@
         ],
       }],
       ['OS=="android"', {
-        'grit_defines': ['-t', 'android',
-                         '-E', 'ANDROID_JAVA_TAGGED_ONLY=true'],
+        'grit_defines': [
+          '-t', 'android',
+          '-E', 'ANDROID_JAVA_TAGGED_ONLY=true',
+          '--no-output-all-resource-defines',
+        ],
       }],
       ['OS=="mac" or OS=="ios"', {
         'grit_defines': ['-D', 'scale_factors=2x'],
@@ -2080,7 +2065,8 @@
         'grit_defines': [
           '-t', 'ios',
           # iOS uses a whitelist to filter resources.
-          '-w', '<(DEPTH)/build/ios/grit_whitelist.txt'
+          '-w', '<(DEPTH)/build/ios/grit_whitelist.txt',
+          '--no-output-all-resource-defines',
         ],
 
         # Enable host builds when generating with ninja-ios.
@@ -2489,7 +2475,7 @@
           'mac_debug_optimization%': '0',   # Use -O0 unless overridden
         }, {
           # See http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Optimize-Options.html
-          'mac_release_optimization%': '3', # Use -O3 unless overridden
+          'mac_release_optimization%': '2', # Use -O2 unless overridden
           'mac_debug_optimization%': '0',   # Use -O0 unless overridden
         }],
         ['OS=="android"', {
@@ -2527,9 +2513,6 @@
         # code generated by flex (used in angle) contains that keyword.
         # http://crbug.com/255186
         '-Wno-deprecated-register',
-
-        # TODO(hans): Clean this up. Or disable with finer granularity.
-        '-Wno-unused-local-typedef',
       ],
     },
     'includes': [ 'set_clang_warning_flags.gypi', ],
@@ -2635,9 +2618,6 @@
       ['enable_pre_sync_backup==1', {
         'defines': ['ENABLE_PRE_SYNC_BACKUP'],
       }],
-      ['use_xi2_mt!=0 and use_x11==1', {
-        'defines': ['USE_XI2_MT=<(use_xi2_mt)'],
-      }],
       ['image_loader_extension==1', {
         'defines': ['IMAGE_LOADER_EXTENSION=1'],
       }],
@@ -2925,11 +2905,6 @@
       ['cld_version!=0', {
         'defines': ['CLD_VERSION=<(cld_version)'],
       }],
-      ['cld_version==2', {
-        # This is used to populate the "CLD Data Source" field in:
-        # chrome://translate-internals
-        'defines': ['CLD2_DATA_SOURCE=<(cld2_data_source)'],
-      }],
       ['enable_basic_printing==1 or enable_print_preview==1', {
         # Convenience define for ENABLE_BASIC_PRINTING || ENABLE_PRINT_PREVIEW.
         'defines': ['ENABLE_PRINTING=1'],
@@ -4209,6 +4184,13 @@
                   '-fsanitize=undefined',
                   # -fsanitize=vptr is incompatible with -fno-rtti.
                   '-fno-sanitize=vptr',
+                  # Employ the experimental PBQP register allocator to avoid
+                  # slow compilation on files with too many basic blocks.
+                  # See http://crbug.com/426271.
+                  '-mllvm -regalloc=pbqp',
+                  # Speculatively use coalescing to slightly improve the code
+                  # generated by PBQP regallocator. May increase compile time.
+                  '-mllvm -pbqp-coalescing',
                 ],
                 'ldflags': [
                   '-fsanitize=undefined',
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index ecbef88..c51709c 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -121,9 +121,6 @@
   }
   if (use_x11) {
     defines += [ "USE_X11=1" ]
-    if (use_xi2_mt > 0) {
-      defines += [ "USE_XI2_MT=$use_xi2_mt" ]
-    }
   }
   if (use_allocator != "tcmalloc") {
     defines += [ "NO_TCMALLOC" ]
diff --git a/build/config/allocator.gni b/build/config/allocator.gni
index acc21d1..2d2fed1 100644
--- a/build/config/allocator.gni
+++ b/build/config/allocator.gni
@@ -1,8 +1,9 @@
 # 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.
-
-if (is_android || cpu_arch == "mipsel" || is_mac || is_asan) {
+ 
+# TODO(GYP): Make tcmalloc work on win.
+if (is_android || cpu_arch == "mipsel" || is_mac || is_asan || is_win) {
   _default_allocator = "none"
 } else {
   _default_allocator = "tcmalloc"
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index de29cce..d6711b8 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -260,6 +260,7 @@
 
   _resource_packaged_apk_path = _base_apk_path + ".ap_"
   _packaged_apk_path = _base_apk_path + ".unfinished.apk"
+  _shared_resources = defined(invoker.shared_resources) && invoker.shared_resources
 
 
   _configuration_name = "Release"
@@ -295,6 +296,10 @@
 
         "--apk-path", rebase_path(_resource_packaged_apk_path, root_build_dir),
       ]
+
+    if (_shared_resources) {
+      args += ["--shared-resources"]
+    }
   }
 
   action("${target_name}__package") {
@@ -718,6 +723,11 @@
       args += ["--v14-verify-only"]
     }
 
+    if (defined(invoker.shared_resources) &&
+        invoker.shared_resources) {
+      args += ["--shared-resources"]
+    }
+
     if (defined(invoker.all_resources_zip_path)) {
       all_resources_zip = invoker.all_resources_zip_path
       outputs += [ all_resources_zip ]
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 9c9287d..d28c481 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -477,6 +477,8 @@
 #     that the resources are v14-compliant (see
 #     build/android/gyp/generate_v14_compatible_resources.py). Defaults to
 #     false.
+#   shared_resources: If true make a resource package that can be loaded by a
+#     different application at runtime to access the package's resources.
 #
 # Example
 #   android_resources("foo_resources") {
@@ -518,6 +520,10 @@
     if (defined(invoker.v14_verify_only)) {
       v14_verify_only = invoker.v14_verify_only
     }
+
+    if (defined(invoker.shared_resources)) {
+      shared_resources = invoker.shared_resources
+    }
   }
 
   group(target_name) {
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 3d1b341..1c51cd0 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -745,9 +745,6 @@
 
         # TODO(thakis): Remove, http://crbug.com/263960
         "-Wno-reserved-user-defined-literal",
-
-        # TODO(hans): Clean this up. Or disable with finer granularity.
-        "-Wno-unused-local-typedef",
       ]
     }
     if (gcc_version >= 48) {
@@ -918,15 +915,28 @@
   cflags = common_optimize_on_cflags
   ldflags = common_optimize_on_ldflags
   if (is_win) {
+    cflags -= [
+      "/Os",
+    ]
     cflags += [
       "/Ot",   # Favor speed over size.
-      "/GL",   # Whole program optimization.
-      # Disable Warning 4702 ("Unreachable code") for the WPO/PGO builds.
-      # Probably anything that this would catch that wouldn't be caught in a
-      # normal build isn't going to actually be a bug, so the incremental value
-      # of C4702 for PGO builds is likely very small.
-      "/wd4702",
     ]
+    if (is_official_build) {
+      # TODO(GYP): TODO(dpranke): Should these only be on in an official
+      # build, or on all the time? For now we'll require official build so
+      # that the compile is clean.
+      cflags += [
+        "/GL",   # Whole program optimization.
+        # Disable Warning 4702 ("Unreachable code") for the WPO/PGO builds.
+        # Probably anything that this would catch that wouldn't be caught in a
+        # normal build isn't going to actually be a bug, so the incremental
+        # value of C4702 for PGO builds is likely very small.
+        "/wd4702",
+      ]
+      ldflags += [
+        "/LTCG",
+      ]
+    }
   } else {
     cflags += [
       "-O2",
diff --git a/build/config/features.gni b/build/config/features.gni
index a395b40..575a89c 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -77,9 +77,8 @@
 use_seccomp_bpf = (is_linux || is_android) &&
   (cpu_arch == "x86" || cpu_arch == "x64" || cpu_arch == "arm")
 
-# Enable notifications everywhere except Android/iOS.
-# Android is http://crbug.com/115320
-enable_notifications = !is_android && !is_ios
+# Enable notifications everywhere except iOS.
+enable_notifications = !is_ios
 
 # TODO(brettw) this should be moved to net and only dependents get this define.
 disable_ftp_support = is_ios
@@ -105,17 +104,6 @@
 
 enable_configuration_policy = true
 
-# The data acquisition mode for CLD2. Possible values are:
-#   static:     CLD2 data is statically linked to the executable.
-#   standalone: CLD2 data is provided in a standalone file that is
-#               bundled with the executable.
-#   component:  CLD2 data is provided as a Chrome "component" and is
-#               downloaded via the component updater.
-#
-# For more information on switching the CLD2 data source, see:
-#   https://sites.google.com/a/chromium.org/dev/developers/how-tos/compact-language-detector-cld-data-source-configuration
-cld2_data_source = "static"
-
 # Enables support for background apps.
 enable_background = !is_ios && !is_android
 
diff --git a/build/config/linux/pkg-config.py b/build/config/linux/pkg-config.py
index 60304d4..a4f4703 100644
--- a/build/config/linux/pkg-config.py
+++ b/build/config/linux/pkg-config.py
@@ -25,6 +25,10 @@
 #
 # When using a sysroot, you must also specify the architecture via
 # "-a <arch>" where arch is either "x86" or "x64".
+#
+# Additionally, you can specify the option --atleast-version. This will skip
+# the normal outputting of a dictionary and instead print true or false,
+# depending on the return value of pkg-config for the given package.
 
 # If this is run on non-Linux platforms, just return nothing and indicate
 # success. This allows us to "kind of emulate" a Linux build from other
@@ -106,6 +110,8 @@
 parser.add_option('-v', action='append', dest='strip_out', type='string')
 parser.add_option('-s', action='store', dest='sysroot', type='string')
 parser.add_option('-a', action='store', dest='arch', type='string')
+parser.add_option('--atleast-version', action='store',
+                  dest='atleast_version', type='string')
 (options, args) = parser.parse_args()
 
 # Make a list of regular expressions to strip out.
@@ -120,6 +126,18 @@
 else:
   prefix = ''
 
+if options.atleast_version:
+  # When asking for the return value, just run pkg-config and print the return
+  # value, no need to do other work.
+  if not subprocess.call([options.pkg_config,
+                          "--atleast-version=" + options.atleast_version] +
+                          args,
+                         env=os.environ):
+    print "true"
+  else:
+    print "false"
+  sys.exit(0)
+
 try:
   flag_string = subprocess.check_output(
       [ options.pkg_config, "--cflags", "--libs-only-l", "--libs-only-L" ] +
diff --git a/build/config/linux/pkg_config.gni b/build/config/linux/pkg_config.gni
index 378863e..687afc5 100644
--- a/build/config/linux/pkg_config.gni
+++ b/build/config/linux/pkg_config.gni
@@ -33,25 +33,29 @@
   pkg_config = ""
 }
 
+pkg_config_script = "//build/config/linux/pkg-config.py"
+
+# Define the args we pass to the pkg-config script for other build files that
+# need to invoke it manually.
+if (sysroot != "") {
+  # Pass the sysroot if we're using one (it requires the CPU arch also).
+  pkg_config_args = ["-s", sysroot, "-a", cpu_arch]
+} else if (pkg_config != "") {
+  pkg_config_args = ["-p", pkg_config]
+} else {
+  pkg_config_args = []
+}
+
 template("pkg_config") {
   assert(defined(invoker.packages),
         "Variable |packages| must be defined to be a list in pkg_config.")
   config(target_name) {
-    if (sysroot != "") {
-      # Pass the sysroot if we're using one (it requires the CPU arch also).
-      args = ["-s", sysroot, "-a", cpu_arch] + invoker.packages
-    } else if (pkg_config != "") {
-      args = ["-p", pkg_config] + invoker.packages
-    } else {
-      args = invoker.packages
-    }
-
+    args = pkg_config_args + invoker.packages
     if (defined(invoker.extra_args)) {
       args += invoker.extra_args
     }
 
-    pkgresult = exec_script("//build/config/linux/pkg-config.py",
-                            args, "value")
+    pkgresult = exec_script(pkg_config_script, args, "value")
     include_dirs = pkgresult[0]
     cflags = pkgresult[1]
 
diff --git a/build/config/ui.gni b/build/config/ui.gni
index f23cd00..dc7a059 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -27,10 +27,6 @@
   # of a replacement for GDI or GTK.
   use_aura = is_win || is_linux
 
-  # XInput2 multitouch support. Zero means disabled, nonzero indicates the
-  # minimum XI2 version. For example, use_xi2_mt=2 means XI2.2 or above.
-  use_xi2_mt = 2
-
   # True means the UI is built using the "views" framework.
   toolkit_views = is_win || is_chromeos || use_aura
 }
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
index 39e5628..aa579ce 100644
--- a/build/ios/grit_whitelist.txt
+++ b/build/ios/grit_whitelist.txt
@@ -1,17 +1,11 @@
 IDR_ABOUT_DOM_DISTILLER_CSS
 IDR_ABOUT_DOM_DISTILLER_HTML
 IDR_ABOUT_DOM_DISTILLER_JS
+IDR_ABOUT_STATS_HTML
+IDR_ABOUT_STATS_JS
 IDR_ABOUT_VERSION_CSS
 IDR_ABOUT_VERSION_HTML
 IDR_ABOUT_VERSION_JS
-IDR_APPLE_FLAGS_HTML
-IDR_AUTOFILL_CC_AMEX
-IDR_AUTOFILL_CC_DINERS
-IDR_AUTOFILL_CC_DISCOVER
-IDR_AUTOFILL_CC_GENERIC
-IDR_AUTOFILL_CC_JCB
-IDR_AUTOFILL_CC_MASTERCARD
-IDR_AUTOFILL_CC_VISA
 IDR_CONTEXTUAL_SEARCH_PROMO_HTML
 IDR_CONTROLLED_SETTING_MANDATORY
 IDR_CRASHES_HTML
@@ -22,6 +16,10 @@
 IDR_DEFAULT_FAVICON_32
 IDR_DEFAULT_FAVICON_64
 IDR_DIR_HEADER_HTML
+IDR_DISTILLER_CSS
+IDR_DISTILLER_JS
+IDR_DOM_DISTILLER_VIEWER_HTML
+IDR_DOM_DISTILLER_VIEWER_JS
 IDR_FLAGS_FAVICON
 IDR_FLAGS_HTML
 IDR_FLAGS_JS
@@ -34,11 +32,11 @@
 IDR_INCOGNITO_TAB_HTML
 IDR_INFOBAR_AUTOFILL_CC
 IDR_INFOBAR_AUTOLOGIN
-IDR_INFOBAR_GEOLOCATION
 IDR_INFOBAR_RESTORE_SESSION
 IDR_INFOBAR_SAVE_PASSWORD
 IDR_INFOBAR_TRANSLATE_IOS
 IDR_INFOBAR_WARNING
+IDR_IS_DISTILLABLE_JS
 IDR_LOCATION_BAR_HTTP
 IDR_NET_ERROR_HTML
 IDR_NET_EXPORT_HTML
@@ -51,6 +49,7 @@
 IDR_OMNIBOX_CLEAR_OTR_IOS
 IDR_OMNIBOX_CLEAR_OTR_PRESSED_IOS
 IDR_OMNIBOX_CLEAR_PRESSED_IOS
+IDR_OMNIBOX_EXTENSION_APP
 IDR_OMNIBOX_HISTORY
 IDR_OMNIBOX_HISTORY_INCOGNITO
 IDR_OMNIBOX_HTTP
@@ -68,6 +67,7 @@
 IDR_OMNIBOX_SEARCH_SECURED
 IDR_OMNIBOX_STAR
 IDR_OMNIBOX_STAR_INCOGNITO
+IDR_OTHER_DEVICES_JS
 IDR_PAGEINFO_BAD
 IDR_PAGEINFO_GOOD
 IDR_PAGEINFO_INFO
@@ -76,7 +76,6 @@
 IDR_POLICY_CSS
 IDR_POLICY_HTML
 IDR_POLICY_JS
-IDR_PRERENDER
 IDR_PRINTER_FAVICON
 IDR_PRODUCT_LOGO_26
 IDR_SAD_FAVICON
@@ -84,8 +83,6 @@
 IDR_SECURITY_INTERSTITIAL_HTML
 IDR_SIGNIN_INTERNALS_INDEX_HTML
 IDR_SIGNIN_INTERNALS_INDEX_JS
-IDR_SSL_BLOCKING_HTML
-IDR_SSL_ROAD_BLOCK_HTML
 IDR_SYNC_INTERNALS_ABOUT_JS
 IDR_SYNC_INTERNALS_CHROME_SYNC_JS
 IDR_SYNC_INTERNALS_DATA_JS
@@ -100,84 +97,9 @@
 IDR_TOOLBAR_SHADOW_FULL_BLEED
 IDR_TRANSLATE_JS
 IDR_UBER_UTILS_JS
-IDR_WEBUI_CSS_ALERT_OVERLAY
-IDR_WEBUI_CSS_APPS_COMMON
-IDR_WEBUI_CSS_APPS_TOPBUTTON_BAR
-IDR_WEBUI_CSS_BUBBLE
-IDR_WEBUI_CSS_BUBBLE_BUTTON
-IDR_WEBUI_CSS_BUTTER_BAR
-IDR_WEBUI_CSS_CHROME
-IDR_WEBUI_CSS_DIALOGS
-IDR_WEBUI_CSS_LIST
-IDR_WEBUI_CSS_MENU
-IDR_WEBUI_CSS_MENU_BUTTON
-IDR_WEBUI_CSS_OVERLAY
-IDR_WEBUI_CSS_SPINNER
-IDR_WEBUI_CSS_TABLE
-IDR_WEBUI_CSS_TABS
-IDR_WEBUI_CSS_THROBBER
-IDR_WEBUI_CSS_TRASH
-IDR_WEBUI_CSS_TREE
-IDR_WEBUI_CSS_TREE_JS
-IDR_WEBUI_CSS_UI_ACCOUNT_TWEAKS
-IDR_WEBUI_CSS_WIDGETS
-IDR_WEBUI_I18N_PROCESS_JS
 IDR_WEBUI_I18N_TEMPLATE2_JS
-IDR_WEBUI_I18N_TEMPLATE_JS
-IDR_WEBUI_IMAGES_SELECT
 IDR_WEBUI_JSTEMPLATE_JS
-IDR_WEBUI_JS_ASSERT
-IDR_WEBUI_JS_CR
-IDR_WEBUI_JS_CR_EVENT_TARGET
-IDR_WEBUI_JS_CR_LINK_CONTROLLER
-IDR_WEBUI_JS_CR_UI
-IDR_WEBUI_JS_CR_UI_ALERT_OVERLAY
-IDR_WEBUI_JS_CR_UI_ARRAY_DATA_MODEL
-IDR_WEBUI_JS_CR_UI_AUTOCOMPLETE_LIST
-IDR_WEBUI_JS_CR_UI_BUBBLE
-IDR_WEBUI_JS_CR_UI_BUBBLE_BUTTON
-IDR_WEBUI_JS_CR_UI_CARD_SLIDER
-IDR_WEBUI_JS_CR_UI_COMMAND
-IDR_WEBUI_JS_CR_UI_CONTEXT_MENU_BUTTON
-IDR_WEBUI_JS_CR_UI_CONTEXT_MENU_HANDLER
-IDR_WEBUI_JS_CR_UI_DIALOGS
-IDR_WEBUI_JS_CR_UI_DRAG_WRAPPER
-IDR_WEBUI_JS_CR_UI_FOCUS_GRID
-IDR_WEBUI_JS_CR_UI_FOCUS_MANAGER
-IDR_WEBUI_JS_CR_UI_FOCUS_OUTLINE_MANAGER
-IDR_WEBUI_JS_CR_UI_FOCUS_ROW
-IDR_WEBUI_JS_CR_UI_GRID
-IDR_WEBUI_JS_CR_UI_LIST
-IDR_WEBUI_JS_CR_UI_LIST_ITEM
-IDR_WEBUI_JS_CR_UI_LIST_SELECTION_CONTROLLER
-IDR_WEBUI_JS_CR_UI_LIST_SELECTION_MODEL
-IDR_WEBUI_JS_CR_UI_LIST_SINGLE_SELECTION_MODEL
-IDR_WEBUI_JS_CR_UI_MENU
-IDR_WEBUI_JS_CR_UI_MENU_BUTTON
-IDR_WEBUI_JS_CR_UI_MENU_ITEM
-IDR_WEBUI_JS_CR_UI_OVERLAY
-IDR_WEBUI_JS_CR_UI_PAGE_MANAGER_PAGE
-IDR_WEBUI_JS_CR_UI_PAGE_MANAGER_PAGE_MANAGER
-IDR_WEBUI_JS_CR_UI_POSITION_UTIL
-IDR_WEBUI_JS_CR_UI_REPEATING_BUTTON
-IDR_WEBUI_JS_CR_UI_SPLITTER
-IDR_WEBUI_JS_CR_UI_TABLE
-IDR_WEBUI_JS_CR_UI_TABLE_COLUMN
-IDR_WEBUI_JS_CR_UI_TABLE_COLUMN_MODEL
-IDR_WEBUI_JS_CR_UI_TABLE_HEADER
-IDR_WEBUI_JS_CR_UI_TABLE_LIST
-IDR_WEBUI_JS_CR_UI_TABLE_SPLITTER
-IDR_WEBUI_JS_CR_UI_TABS
-IDR_WEBUI_JS_CR_UI_TOUCH_HANDLER
-IDR_WEBUI_JS_CR_UI_TREE
-IDR_WEBUI_JS_EVENT_TRACKER
-IDR_WEBUI_JS_I18N_TEMPLATE_NO_PROCESS
 IDR_WEBUI_JS_LOAD_TIME_DATA
-IDR_WEBUI_JS_MEDIA_COMMON
-IDR_WEBUI_JS_PARSE_HTML_SUBSET
-IDR_WEBUI_JS_UI_ACCOUNT_TWEAKS
-IDR_WEBUI_JS_UTIL
-IDR_WEBUI_JS_WEBUI_RESOURCE_TEST
 IDS_ABOUT_MAC
 IDS_ABOUT_VERSION_COMMAND_LINE
 IDS_ABOUT_VERSION_COMPANY_NAME
@@ -1151,6 +1073,7 @@
 IDS_SYNC_UNRECOVERABLE_ERROR_HELP_URL
 IDS_SYNC_UPGRADE_CLIENT
 IDS_SYSTEM_FLAGS_OWNER_ONLY
+IDS_TERMS_HTML
 IDS_TIME_DAYS_1ST_DEFAULT
 IDS_TIME_DAYS_1ST_FEW
 IDS_TIME_DAYS_1ST_MANY
diff --git a/build/java_apk.gypi b/build/java_apk.gypi
index 18e6ccf..4243554 100644
--- a/build/java_apk.gypi
+++ b/build/java_apk.gypi
@@ -44,6 +44,8 @@
 #    shared library to be included in this apk. A stripped copy of the
 #    library will be included in the apk.
 #  resource_dir - The directory for resources.
+#  shared_resources - Make a resource package that can be loaded by a different
+#    application at runtime to access the package's resources.
 #  R_package - A custom Java package to generate the resource file R.java in.
 #    By default, the package given in AndroidManifest.xml will be used.
 #  use_chromium_linker - Enable the content dynamic linker that allows sharing the
@@ -126,6 +128,7 @@
     'resource_zip_path': '<(intermediate_dir)/<(_target_name).resources.zip',
     'resource_packaged_apk_name': '<(apk_name)-resources.ap_',
     'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)',
+    'shared_resources%': 0,
     'unsigned_apk_path': '<(intermediate_dir)/<(apk_name)-unsigned.apk',
     'final_apk_path%': '<(PRODUCT_DIR)/apks/<(apk_name).apk',
     'incomplete_apk_path': '<(intermediate_dir)/<(apk_name)-incomplete.apk',
@@ -575,7 +578,10 @@
             'additional_res_packages=': [],
           }],
           ['res_v14_verify_only == 1', {
-            'process_resources_options': ['--v14-verify-only']
+            'process_resources_options+': ['--v14-verify-only']
+          }],
+          ['shared_resources == 1', {
+            'process_resources_options+': ['--shared-resources']
           }],
         ],
       },
@@ -825,10 +831,16 @@
       'action_name': 'package_resources',
       'message': 'packaging resources for <(_target_name)',
       'variables': {
+        'package_resources_options': [],
         'package_resource_zip_input_paths': [
           '<(resource_zip_path)',
           '>@(dependencies_res_zip_paths)',
         ],
+        'conditions': [
+          ['shared_resources == 1', {
+            'package_resources_options+': ['--shared-resources']
+          }],
+        ],
       },
       'conditions': [
         ['is_test_apk == 1', {
@@ -868,6 +880,8 @@
         '--no-compress', '<(extensions_to_not_compress)',
 
         '--apk-path', '<(resource_packaged_apk_path)',
+
+        '<@(package_resources_options)',
       ],
     },
     {
diff --git a/build/landmines.py b/build/landmines.py
index 2ddf346..cb3bdab 100755
--- a/build/landmines.py
+++ b/build/landmines.py
@@ -54,6 +54,79 @@
   return os.path.abspath(ret)
 
 
+def extract_gn_build_commands(build_ninja_file):
+  """Extracts from a build.ninja the commands to run GN.
+
+  The commands to run GN are the gn rule and build.ninja build step at the
+  top of the build.ninja file. We want to keep these when deleting GN builds
+  since we want to preserve the command-line flags to GN.
+
+  On error, returns the empty string."""
+  result = ""
+  with open(build_ninja_file, 'r') as f:
+    # Read until the second blank line. The first thing GN writes to the file
+    # is the "rule gn" and the second is the section for "build build.ninja",
+    # separated by blank lines.
+    num_blank_lines = 0
+    while num_blank_lines < 2:
+      line = f.readline()
+      if len(line) == 0:
+        return ''  # Unexpected EOF.
+      result += line
+      if line[0] == '\n':
+        num_blank_lines = num_blank_lines + 1
+  return result
+
+def delete_build_dir(build_dir):
+  # GN writes a build.ninja.d file. Note that not all GN builds have args.gn.
+  build_ninja_d_file = os.path.join(build_dir, 'build.ninja.d')
+  if not os.path.exists(build_ninja_d_file):
+    shutil.rmtree(build_dir)
+    return
+
+  # GN builds aren't automatically regenerated when you sync. To avoid
+  # messing with the GN workflow, erase everything but the args file, and
+  # write a dummy build.ninja file that will automatically rerun GN the next
+  # time Ninja is run.
+  build_ninja_file = os.path.join(build_dir, 'build.ninja')
+  build_commands = extract_gn_build_commands(build_ninja_file)
+
+  try:
+    gn_args_file = os.path.join(build_dir, 'args.gn')
+    with open(gn_args_file, 'r') as f:
+      args_contents = f.read()
+  except IOError:
+    args_contents = ''
+
+  shutil.rmtree(build_dir)
+
+  # Put back the args file (if any).
+  os.mkdir(build_dir)
+  if args_contents != '':
+    with open(gn_args_file, 'w') as f:
+      f.write(args_contents)
+
+  # Write the build.ninja file sufficiently to regenerate itself.
+  with open(os.path.join(build_dir, 'build.ninja'), 'w') as f:
+    if build_commands != '':
+      f.write(build_commands)
+    else:
+      # Couldn't parse the build.ninja file, write a default thing.
+      f.write('''rule gn
+command = gn -q gen //out/%s/
+description = Regenerating ninja files
+
+build build.ninja: gn
+generator = 1
+depfile = build.ninja.d
+''' % (os.path.split(build_dir)[1]))
+
+  # Write a .d file for the build which references a nonexistant file. This
+  # will make Ninja always mark the build as dirty.
+  with open(build_ninja_d_file, 'w') as f:
+    f.write('build.ninja: nonexistant_file.gn\n')
+
+
 def clobber_if_necessary(new_landmines):
   """Does the work of setting, planting, and triggering landmines."""
   out_dir = get_build_dir(landmine_utils.builder())
@@ -82,7 +155,7 @@
         if os.path.isfile(path):
           os.unlink(path)
         elif os.path.isdir(path):
-          shutil.rmtree(path)
+          delete_build_dir(path)
 
   # Save current set of landmines for next time.
   with open(landmines_path, 'w') as f:
diff --git a/build/secondary/third_party/nss/BUILD.gn b/build/secondary/third_party/nss/BUILD.gn
index 30364d1..a285ca1 100644
--- a/build/secondary/third_party/nss/BUILD.gn
+++ b/build/secondary/third_party/nss/BUILD.gn
@@ -1159,6 +1159,10 @@
           "USE_HW_AES",
           "INTEL_GCM",
         ]
+        sources -= [
+          "nss/lib/freebl/mpi/mpi_amd64.c",
+        ]
+
       } else if (cpu_arch == "x64") {
         sources -= [
           "nss/lib/freebl/intel-aes-x86-masm.asm",
diff --git a/build/tree_truth.sh b/build/tree_truth.sh
index 03d0523..617092d 100755
--- a/build/tree_truth.sh
+++ b/build/tree_truth.sh
@@ -87,9 +87,10 @@
 # Print a summary of the last 10 commits for each repo.
 tt_brief_summary() {
   echo "@@@BUILD_STEP Brief summary of recent CLs in every branch@@@"
-  for p in $@; do
-    echo $project
-    (cd $CHROME_SRC/../$p && git log -n 10 --format="   %H %s   %an, %ad" | cat)
+  for project in $@; do
+    echo $project:
+    local full_path=$CHROME_SRC/../$project
+    (cd $full_path && git log -n 10 --format="   %H %s   %an, %ad" | cat)
     echo "================================================================="
   done
 }
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index 78ed34c..526203f 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -145,4 +145,3 @@
 Oh god the bots are red! I'm blind! Mmmm, cronuts.
 
 If you stand on your head, you will get footprints in your hair.
-
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index f753895..3b3ed6d 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -64,6 +64,7 @@
     "base/switches.h",
     "base/tiling_data.cc",
     "base/tiling_data.h",
+    "base/time_util.h",
     "base/unique_notifier.cc",
     "base/unique_notifier.h",
     "base/util.h",
@@ -112,11 +113,14 @@
     "debug/unittest_only_benchmark.h",
     "debug/unittest_only_benchmark_impl.cc",
     "debug/unittest_only_benchmark_impl.h",
+    "input/input_handler.cc",
     "input/input_handler.h",
     "input/page_scale_animation.cc",
     "input/page_scale_animation.h",
     "input/layer_selection_bound.cc",
     "input/layer_selection_bound.h",
+    "input/scroll_elasticity_helper.cc",
+    "input/scroll_elasticity_helper.h",
     "input/selection_bound_type.h",
     "input/top_controls_manager.cc",
     "input/top_controls_manager.h",
@@ -346,8 +350,6 @@
     "resources/picture_layer_tiling_set.h",
     "resources/picture_pile.cc",
     "resources/picture_pile.h",
-    "resources/picture_pile_base.cc",
-    "resources/picture_pile_base.h",
     "resources/picture_pile_impl.cc",
     "resources/picture_pile_impl.h",
     "resources/pixel_buffer_raster_worker_pool.cc",
@@ -532,6 +534,7 @@
     "test/fake_picture_layer_impl.h",
     "test/fake_picture_layer_tiling_client.cc",
     "test/fake_picture_layer_tiling_client.h",
+    "test/fake_picture_pile.h",
     "test/fake_picture_pile_impl.cc",
     "test/fake_picture_pile_impl.h",
     "test/fake_proxy.cc",
diff --git a/cc/animation/animation.cc b/cc/animation/animation.cc
index e49cf1e..f5abfa0 100644
--- a/cc/animation/animation.cc
+++ b/cc/animation/animation.cc
@@ -9,6 +9,7 @@
 #include "base/debug/trace_event.h"
 #include "base/strings/string_util.h"
 #include "cc/animation/animation_curve.h"
+#include "cc/base/time_util.h"
 
 namespace {
 
@@ -154,17 +155,18 @@
     return false;
 
   return run_state_ == Running && iterations_ >= 0 &&
-         iterations_ * curve_->Duration() / std::abs(playback_rate_) <=
-             (monotonic_time + time_offset_ - start_time_ - total_paused_time_)
-                 .InSecondsF();
+         TimeUtil::Scale(curve_->Duration(),
+                         iterations_ / std::abs(playback_rate_)) <=
+             (monotonic_time + time_offset_ - start_time_ - total_paused_time_);
 }
 
 bool Animation::InEffect(base::TimeTicks monotonic_time) const {
-  return ConvertToActiveTime(monotonic_time) >= 0 ||
+  return ConvertToActiveTime(monotonic_time) >= base::TimeDelta() ||
          (fill_mode_ == FillModeBoth || fill_mode_ == FillModeBackwards);
 }
 
-double Animation::ConvertToActiveTime(base::TimeTicks monotonic_time) const {
+base::TimeDelta Animation::ConvertToActiveTime(
+    base::TimeTicks monotonic_time) const {
   base::TimeTicks trimmed = monotonic_time + time_offset_;
 
   // If we're paused, time is 'stuck' at the pause time.
@@ -181,56 +183,60 @@
       needs_synchronized_start_time())
     trimmed = base::TimeTicks() + time_offset_;
 
-  return (trimmed - base::TimeTicks()).InSecondsF();
+  return (trimmed - base::TimeTicks());
 }
 
-double Animation::TrimTimeToCurrentIteration(
+base::TimeDelta Animation::TrimTimeToCurrentIteration(
     base::TimeTicks monotonic_time) const {
   // Check for valid parameters
   DCHECK(playback_rate_);
   DCHECK_GE(iteration_start_, 0);
 
-  double active_time = ConvertToActiveTime(monotonic_time);
-  double start_offset = iteration_start_ * curve_->Duration();
+  base::TimeDelta active_time = ConvertToActiveTime(monotonic_time);
+  base::TimeDelta start_offset =
+      TimeUtil::Scale(curve_->Duration(), iteration_start_);
 
   // Return start offset if we are before the start of the animation
-  if (active_time < 0)
+  if (active_time < base::TimeDelta())
     return start_offset;
-
   // Always return zero if we have no iterations.
   if (!iterations_)
-    return 0;
+    return base::TimeDelta();
 
   // Don't attempt to trim if we have no duration.
-  if (curve_->Duration() <= 0)
-    return 0;
+  if (curve_->Duration() <= base::TimeDelta())
+    return base::TimeDelta();
 
-  double repeated_duration = iterations_ * curve_->Duration();
-  double active_duration = repeated_duration / std::abs(playback_rate_);
+  base::TimeDelta repeated_duration =
+      TimeUtil::Scale(curve_->Duration(), iterations_);
+  base::TimeDelta active_duration =
+      TimeUtil::Scale(repeated_duration, 1.0 / std::abs(playback_rate_));
 
   // Check if we are past active duration
   if (iterations_ > 0 && active_time >= active_duration)
     active_time = active_duration;
 
   // Calculate the scaled active time
-  double scaled_active_time;
+  base::TimeDelta scaled_active_time;
   if (playback_rate_ < 0)
     scaled_active_time =
-        (active_time - active_duration) * playback_rate_ + start_offset;
+        TimeUtil::Scale((active_time - active_duration), playback_rate_) +
+        start_offset;
   else
-    scaled_active_time = active_time * playback_rate_ + start_offset;
+    scaled_active_time =
+        TimeUtil::Scale(active_time, playback_rate_) + start_offset;
 
   // Calculate the iteration time
-  double iteration_time;
+  base::TimeDelta iteration_time;
   if (scaled_active_time - start_offset == repeated_duration &&
       fmod(iterations_ + iteration_start_, 1) == 0)
     iteration_time = curve_->Duration();
   else
-    iteration_time = fmod(scaled_active_time, curve_->Duration());
+    iteration_time = TimeUtil::Mod(scaled_active_time, curve_->Duration());
 
   // Calculate the current iteration
   int iteration;
-  if (scaled_active_time <= 0)
+  if (scaled_active_time <= base::TimeDelta())
     iteration = 0;
   else if (iteration_time == curve_->Duration())
     iteration = ceil(iteration_start_ + iterations_ - 1);
diff --git a/cc/animation/animation.h b/cc/animation/animation.h
index 7856497..80c0763 100644
--- a/cc/animation/animation.h
+++ b/cc/animation/animation.h
@@ -142,7 +142,8 @@
 
   // Takes the given absolute time, and using the start time and the number
   // of iterations, returns the relative time in the current iteration.
-  double TrimTimeToCurrentIteration(base::TimeTicks monotonic_time) const;
+  base::TimeDelta TrimTimeToCurrentIteration(
+      base::TimeTicks monotonic_time) const;
 
   scoped_ptr<Animation> CloneAndInitialize(RunState initial_run_state) const;
 
@@ -169,7 +170,7 @@
             int group_id,
             TargetProperty target_property);
 
-  double ConvertToActiveTime(base::TimeTicks monotonic_time) const;
+  base::TimeDelta ConvertToActiveTime(base::TimeTicks monotonic_time) const;
 
   scoped_ptr<AnimationCurve> curve_;
 
diff --git a/cc/animation/animation_curve.h b/cc/animation/animation_curve.h
index 57c42c7..c03feb8 100644
--- a/cc/animation/animation_curve.h
+++ b/cc/animation/animation_curve.h
@@ -6,6 +6,7 @@
 #define CC_ANIMATION_ANIMATION_CURVE_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
 #include "cc/base/cc_export.h"
 #include "cc/output/filter_operations.h"
 #include "ui/gfx/transform.h"
@@ -30,7 +31,7 @@
 
   virtual ~AnimationCurve() {}
 
-  virtual double Duration() const = 0;
+  virtual base::TimeDelta Duration() const = 0;
   virtual CurveType Type() const = 0;
   virtual scoped_ptr<AnimationCurve> Clone() const = 0;
 
diff --git a/cc/animation/animation_unittest.cc b/cc/animation/animation_unittest.cc
index b1592d6..2522f19 100644
--- a/cc/animation/animation_unittest.cc
+++ b/cc/animation/animation_unittest.cc
@@ -41,166 +41,257 @@
 
 TEST(AnimationTest, TrimTimeZeroIterations) {
   scoped_ptr<Animation> anim(CreateAnimation(0));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeOneIteration) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeOneHalfIteration) {
   scoped_ptr<Animation> anim(CreateAnimation(1.5));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.9, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.9)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.9, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.9))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeInfiniteIterations) {
   scoped_ptr<Animation> anim(CreateAnimation(-1));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(-1));
   anim->set_direction(Animation::Reverse);
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+  EXPECT_EQ(
+      1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                      .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                      .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeAlternateInfiniteIterations) {
   scoped_ptr<Animation> anim(CreateAnimation(-1));
   anim->set_direction(Animation::Alternate);
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                      .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                      .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeAlternateOneIteration) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
   anim->set_direction(Animation::Alternate);
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                      .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeAlternateTwoIterations) {
   scoped_ptr<Animation> anim(CreateAnimation(2));
   anim->set_direction(Animation::Alternate);
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                      .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+                      .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeAlternateTwoHalfIterations) {
   scoped_ptr<Animation> anim(CreateAnimation(2.5));
   anim->set_direction(Animation::Alternate);
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.50)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                      .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+                      .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.50))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeAlternateReverseInfiniteIterations) {
   scoped_ptr<Animation> anim(CreateAnimation(-1));
   anim->set_direction(Animation::AlternateReverse);
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                      .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                      .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeAlternateReverseOneIteration) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
   anim->set_direction(Animation::AlternateReverse);
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                      .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeAlternateReverseTwoIterations) {
   scoped_ptr<Animation> anim(CreateAnimation(2));
   anim->set_direction(Animation::AlternateReverse);
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                      .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                      .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+                      .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeStartTime) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
   anim->set_start_time(TicksFromSecondsF(4));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)));
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)).InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+                     .InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeStartTimeReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
   anim->set_start_time(TicksFromSecondsF(4));
   anim->set_direction(Animation::Reverse);
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)));
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+                     .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeTimeOffset) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
   anim->set_time_offset(TimeDelta::FromMilliseconds(4000));
   anim->set_start_time(TicksFromSecondsF(4));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeTimeOffsetReverse) {
@@ -208,20 +299,28 @@
   anim->set_time_offset(TimeDelta::FromMilliseconds(4000));
   anim->set_start_time(TicksFromSecondsF(4));
   anim->set_direction(Animation::Reverse);
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeNegativeTimeOffset) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
   anim->set_time_offset(TimeDelta::FromMilliseconds(-4000));
 
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)).InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+                     .InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeNegativeTimeOffsetReverse) {
@@ -229,103 +328,149 @@
   anim->set_time_offset(TimeDelta::FromMilliseconds(-4000));
   anim->set_direction(Animation::Reverse);
 
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+                     .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimePauseResume) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
   anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
   anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.5));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+                     .InSecondsF());
   anim->SetRunState(Animation::Running, TicksFromSecondsF(1024.0));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5)));
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+                     .InSecondsF());
+  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5))
+                   .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimePauseResumeReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
   anim->set_direction(Animation::Reverse);
   anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
   anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.25));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+                      .InSecondsF());
   anim->SetRunState(Animation::Running, TicksFromSecondsF(1024.0));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.75)));
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+                      .InSecondsF());
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.75))
+                   .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeSuspendResume) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
   anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
   anim->Suspend(TicksFromSecondsF(0.5));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+                     .InSecondsF());
   anim->Resume(TicksFromSecondsF(1024));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5)));
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+                     .InSecondsF());
+  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5))
+                   .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeSuspendResumeReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(1));
   anim->set_direction(Animation::Reverse);
   anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                      .InSecondsF());
   anim->Suspend(TicksFromSecondsF(0.75));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+                      .InSecondsF());
   anim->Resume(TicksFromSecondsF(1024));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.25)));
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+                      .InSecondsF());
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.25))
+                   .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeZeroDuration) {
   scoped_ptr<Animation> anim(CreateAnimation(0, 0));
   anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeStarting) {
   scoped_ptr<Animation> anim(CreateAnimation(1, 5.0));
   anim->SetRunState(Animation::Starting, TicksFromSecondsF(0.0));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
   anim->set_time_offset(TimeDelta::FromMilliseconds(2000));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
   anim->set_start_time(TicksFromSecondsF(1.0));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeNeedsSynchronizedStartTime) {
   scoped_ptr<Animation> anim(CreateAnimation(1, 5.0));
   anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
   anim->set_needs_synchronized_start_time(true);
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
   anim->set_time_offset(TimeDelta::FromMilliseconds(2000));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
   anim->set_start_time(TicksFromSecondsF(1.0));
   anim->set_needs_synchronized_start_time(false);
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, IsFinishedAtZeroIterations) {
@@ -437,223 +582,362 @@
 
 TEST(AnimationTest, TrimTimePlaybackNormal) {
   scoped_ptr<Animation> anim(CreateAnimation(1, 1, 1));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimePlaybackSlow) {
   scoped_ptr<Animation> anim(CreateAnimation(1, 1, 0.5));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                      .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimePlaybackFast) {
   scoped_ptr<Animation> anim(CreateAnimation(1, 4, 2));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+  EXPECT_EQ(
+      2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+  EXPECT_EQ(
+      3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
+  EXPECT_EQ(
+      4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+  EXPECT_EQ(
+      4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimePlaybackNormalReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(1, 2, -1));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                     .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimePlaybackSlowReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(1, 2, -0.5));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
-  EXPECT_EQ(1.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(1.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3)));
-  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+  EXPECT_EQ(1.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                      .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                      .InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+  EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+                      .InSecondsF());
+  EXPECT_EQ(
+      0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3)).InSecondsF());
+  EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+                      .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4)).InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimePlaybackFastReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(1, 2, -2));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                     .InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                     .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimePlaybackFastInfiniteIterations) {
   scoped_ptr<Animation> anim(CreateAnimation(-1, 4, 4));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.0)));
-  EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.5)));
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(
+      2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+  EXPECT_EQ(
+      2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.0))
+                   .InSecondsF());
+  EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.5))
+                   .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimePlaybackNormalDoubleReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(1, 1, -1));
   anim->set_direction(Animation::Reverse);
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimePlaybackFastDoubleReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(1, 4, -2));
   anim->set_direction(Animation::Reverse);
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+  EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                   .InSecondsF());
+  EXPECT_EQ(
+      0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+  EXPECT_EQ(
+      1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+  EXPECT_EQ(
+      2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+  EXPECT_EQ(
+      3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
+  EXPECT_EQ(
+      4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+  EXPECT_EQ(
+      4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)).InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFast) {
   scoped_ptr<Animation> anim(CreateAnimation(2, 2, 2));
   anim->set_direction(Animation::Alternate);
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFastReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(2, 2, 2));
   anim->set_direction(Animation::AlternateReverse);
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFastDoubleReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(2, 2, -2));
   anim->set_direction(Animation::AlternateReverse);
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest,
      TrimTimeAlternateReverseThreeIterationsPlaybackFastAlternateReverse) {
   scoped_ptr<Animation> anim(CreateAnimation(3, 2, -2));
   anim->set_direction(Animation::AlternateReverse);
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.25)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.25))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest,
      TrimTimeAlternateReverseTwoIterationsPlaybackNormalAlternate) {
   scoped_ptr<Animation> anim(CreateAnimation(2, 2, -1));
   anim->set_direction(Animation::Alternate);
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                     .InSecondsF());
+  EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeIterationStart) {
   scoped_ptr<Animation> anim(CreateAnimation(2, 1, 1));
   anim->set_iteration_start(0.5);
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeIterationStartAlternate) {
   scoped_ptr<Animation> anim(CreateAnimation(2, 1, 1));
   anim->set_direction(Animation::Alternate);
   anim->set_iteration_start(0.3);
-  EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.8, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.7)));
-  EXPECT_EQ(0.7, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.2)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.7)));
+  EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.8, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.7))
+                     .InSecondsF());
+  EXPECT_EQ(0.7, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.2))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.7))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, TrimTimeIterationStartAlternateThreeIterations) {
   scoped_ptr<Animation> anim(CreateAnimation(3, 1, 1));
   anim->set_direction(Animation::Alternate);
   anim->set_iteration_start(1);
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest,
@@ -661,11 +945,16 @@
   scoped_ptr<Animation> anim(CreateAnimation(3, 1, -1));
   anim->set_direction(Animation::Alternate);
   anim->set_iteration_start(1);
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
-  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
-  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+                     .InSecondsF());
+  EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+                     .InSecondsF());
+  EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+                     .InSecondsF());
 }
 
 TEST(AnimationTest, InEffectFillMode) {
diff --git a/cc/animation/keyframed_animation_curve.cc b/cc/animation/keyframed_animation_curve.cc
index 333a5c9..a6dc8c5 100644
--- a/cc/animation/keyframed_animation_curve.cc
+++ b/cc/animation/keyframed_animation_curve.cc
@@ -205,8 +205,9 @@
   InsertKeyframe(keyframe.Pass(), &keyframes_);
 }
 
-double KeyframedColorAnimationCurve::Duration() const {
-  return keyframes_.back()->Time() - keyframes_.front()->Time();
+base::TimeDelta KeyframedColorAnimationCurve::Duration() const {
+  return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
+                                       keyframes_.front()->Time());
 }
 
 scoped_ptr<AnimationCurve> KeyframedColorAnimationCurve::Clone() const {
@@ -252,8 +253,9 @@
   InsertKeyframe(keyframe.Pass(), &keyframes_);
 }
 
-double KeyframedFloatAnimationCurve::Duration() const {
-  return keyframes_.back()->Time() - keyframes_.front()->Time();
+base::TimeDelta KeyframedFloatAnimationCurve::Duration() const {
+  return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
+                                       keyframes_.front()->Time());
 }
 
 scoped_ptr<AnimationCurve> KeyframedFloatAnimationCurve::Clone() const {
@@ -297,8 +299,9 @@
   InsertKeyframe(keyframe.Pass(), &keyframes_);
 }
 
-double KeyframedTransformAnimationCurve::Duration() const {
-  return keyframes_.back()->Time() - keyframes_.front()->Time();
+base::TimeDelta KeyframedTransformAnimationCurve::Duration() const {
+  return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
+                                       keyframes_.front()->Time());
 }
 
 scoped_ptr<AnimationCurve> KeyframedTransformAnimationCurve::Clone() const {
@@ -408,8 +411,9 @@
   InsertKeyframe(keyframe.Pass(), &keyframes_);
 }
 
-double KeyframedFilterAnimationCurve::Duration() const {
-  return keyframes_.back()->Time() - keyframes_.front()->Time();
+base::TimeDelta KeyframedFilterAnimationCurve::Duration() const {
+  return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
+                                       keyframes_.front()->Time());
 }
 
 scoped_ptr<AnimationCurve> KeyframedFilterAnimationCurve::Clone() const {
diff --git a/cc/animation/keyframed_animation_curve.h b/cc/animation/keyframed_animation_curve.h
index a6e6740..ff746fe 100644
--- a/cc/animation/keyframed_animation_curve.h
+++ b/cc/animation/keyframed_animation_curve.h
@@ -5,6 +5,7 @@
 #ifndef CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
 #define CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
 
+#include "base/time/time.h"
 #include "cc/animation/animation_curve.h"
 #include "cc/animation/timing_function.h"
 #include "cc/animation/transform_operations.h"
@@ -126,7 +127,7 @@
   }
 
   // AnimationCurve implementation
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   scoped_ptr<AnimationCurve> Clone() const override;
 
   // BackgrounColorAnimationCurve implementation
@@ -156,7 +157,7 @@
   }
 
   // AnimationCurve implementation
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   scoped_ptr<AnimationCurve> Clone() const override;
 
   // FloatAnimationCurve implementation
@@ -187,7 +188,7 @@
   }
 
   // AnimationCurve implementation
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   scoped_ptr<AnimationCurve> Clone() const override;
 
   // TransformAnimationCurve implementation
@@ -224,7 +225,7 @@
   }
 
   // AnimationCurve implementation
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   scoped_ptr<AnimationCurve> Clone() const override;
 
   // FilterAnimationCurve implementation
diff --git a/cc/animation/layer_animation_controller.cc b/cc/animation/layer_animation_controller.cc
index b779a37..f621ad3 100644
--- a/cc/animation/layer_animation_controller.cc
+++ b/cc/animation/layer_animation_controller.cc
@@ -148,7 +148,8 @@
     if (!animation->InEffect(monotonic_time))
       continue;
 
-    double trimmed = animation->TrimTimeToCurrentIteration(monotonic_time);
+    double trimmed =
+        animation->TrimTimeToCurrentIteration(monotonic_time).InSecondsF();
     switch (animation->target_property()) {
       case Animation::Opacity: {
         AnimationEvent event(AnimationEvent::PropertyUpdate,
@@ -212,7 +213,11 @@
   if (!HasActiveValueObserver())
     return;
 
-  DCHECK(last_tick_time_ != base::TimeTicks());
+  // Animate hasn't been called, this happens if an observer has been added
+  // between the Commit and Draw phases.
+  if (last_tick_time_ == base::TimeTicks())
+    return;
+
   if (start_ready_animations)
     PromoteStartedAnimations(last_tick_time_, events);
 
@@ -856,8 +861,9 @@
       if (!animations_[i]->InEffect(monotonic_time))
         continue;
 
-      double trimmed =
-          animations_[i]->TrimTimeToCurrentIteration(monotonic_time);
+      double trimmed = animations_[i]
+                           ->TrimTimeToCurrentIteration(monotonic_time)
+                           .InSecondsF();
 
       switch (animations_[i]->target_property()) {
         case Animation::Transform: {
diff --git a/cc/animation/layer_animation_controller_unittest.cc b/cc/animation/layer_animation_controller_unittest.cc
index 49ac0a5..4fa3d84 100644
--- a/cc/animation/layer_animation_controller_unittest.cc
+++ b/cc/animation/layer_animation_controller_unittest.cc
@@ -673,14 +673,11 @@
   controller->PushAnimationUpdatesTo(controller_impl.get());
   controller_impl->ActivateAnimations();
   EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
-  double duration_in_seconds =
-      controller_impl->GetAnimation(Animation::ScrollOffset)
-          ->curve()
-          ->Duration();
-  TimeDelta duration = TimeDelta::FromMicroseconds(
-      duration_in_seconds * base::Time::kMicrosecondsPerSecond);
+  TimeDelta duration = controller_impl->GetAnimation(Animation::ScrollOffset)
+                           ->curve()
+                           ->Duration();
   EXPECT_EQ(
-      duration_in_seconds,
+      duration,
       controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration());
 
   controller->Animate(kInitialTickTime);
@@ -755,12 +752,11 @@
   controller->PushAnimationUpdatesTo(controller_impl.get());
   controller_impl->ActivateAnimations();
   EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
-  double duration_in_seconds =
-      controller_impl->GetAnimation(Animation::ScrollOffset)
-          ->curve()
-          ->Duration();
+  TimeDelta duration = controller_impl->GetAnimation(Animation::ScrollOffset)
+                           ->curve()
+                           ->Duration();
   EXPECT_EQ(
-      duration_in_seconds,
+      duration,
       controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration());
 
   controller->Animate(kInitialTickTime);
@@ -776,8 +772,6 @@
   const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get());
   EXPECT_FALSE(event);
 
-  TimeDelta duration = TimeDelta::FromMicroseconds(
-      duration_in_seconds * base::Time::kMicrosecondsPerSecond);
 
   controller->NotifyAnimationStarted((*events)[0]);
   controller->Animate(kInitialTickTime + duration / 2);
@@ -820,7 +814,7 @@
           target_value,
           EaseInOutTimingFunction::Create().Pass()));
   curve->SetInitialValue(initial_value);
-  double duration_in_seconds = curve->Duration();
+  double duration_in_seconds = curve->Duration().InSecondsF();
 
   scoped_ptr<Animation> animation(
       Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
diff --git a/cc/animation/scroll_offset_animation_curve.cc b/cc/animation/scroll_offset_animation_curve.cc
index 641c9e0..e0b1a3b 100644
--- a/cc/animation/scroll_offset_animation_curve.cc
+++ b/cc/animation/scroll_offset_animation_curve.cc
@@ -83,8 +83,8 @@
           progress, initial_value_.y(), target_value_.y()));
 }
 
-double ScrollOffsetAnimationCurve::Duration() const {
-  return total_animation_duration_.InSecondsF();
+base::TimeDelta ScrollOffsetAnimationCurve::Duration() const {
+  return total_animation_duration_;
 }
 
 AnimationCurve::CurveType ScrollOffsetAnimationCurve::Type() const {
diff --git a/cc/animation/scroll_offset_animation_curve.h b/cc/animation/scroll_offset_animation_curve.h
index 0c8692a..50dfb17 100644
--- a/cc/animation/scroll_offset_animation_curve.h
+++ b/cc/animation/scroll_offset_animation_curve.h
@@ -29,7 +29,7 @@
   void UpdateTarget(double t, const gfx::ScrollOffset& new_target);
 
   // AnimationCurve implementation
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   CurveType Type() const override;
   scoped_ptr<AnimationCurve> Clone() const override;
 
diff --git a/cc/animation/scroll_offset_animation_curve_unittest.cc b/cc/animation/scroll_offset_animation_curve_unittest.cc
index d89784a..d57814e 100644
--- a/cc/animation/scroll_offset_animation_curve_unittest.cc
+++ b/cc/animation/scroll_offset_animation_curve_unittest.cc
@@ -19,39 +19,39 @@
           EaseInOutTimingFunction::Create().Pass()));
 
   curve->SetInitialValue(target_value);
-  EXPECT_DOUBLE_EQ(0.0, curve->Duration());
+  EXPECT_DOUBLE_EQ(0.0, curve->Duration().InSecondsF());
 
   // x decreases, y stays the same.
   curve->SetInitialValue(gfx::ScrollOffset(136.f, 200.f));
-  EXPECT_DOUBLE_EQ(0.1, curve->Duration());
+  EXPECT_DOUBLE_EQ(0.1, curve->Duration().InSecondsF());
 
   // x increases, y stays the same.
   curve->SetInitialValue(gfx::ScrollOffset(19.f, 200.f));
-  EXPECT_DOUBLE_EQ(0.15, curve->Duration());
+  EXPECT_DOUBLE_EQ(0.15, curve->Duration().InSecondsF());
 
   // x stays the same, y decreases.
   curve->SetInitialValue(gfx::ScrollOffset(100.f, 344.f));
-  EXPECT_DOUBLE_EQ(0.2, curve->Duration());
+  EXPECT_DOUBLE_EQ(0.2, curve->Duration().InSecondsF());
 
   // x stays the same, y increases.
   curve->SetInitialValue(gfx::ScrollOffset(100.f, 191.f));
-  EXPECT_DOUBLE_EQ(0.05, curve->Duration());
+  EXPECT_DOUBLE_EQ(0.05, curve->Duration().InSecondsF());
 
   // x decreases, y decreases.
   curve->SetInitialValue(gfx::ScrollOffset(32500.f, 500.f));
-  EXPECT_DOUBLE_EQ(3.0, curve->Duration());
+  EXPECT_DOUBLE_EQ(3.0, curve->Duration().InSecondsF());
 
   // x decreases, y increases.
   curve->SetInitialValue(gfx::ScrollOffset(150.f, 119.f));
-  EXPECT_DOUBLE_EQ(0.15, curve->Duration());
+  EXPECT_DOUBLE_EQ(0.15, curve->Duration().InSecondsF());
 
   // x increases, y decreases.
   curve->SetInitialValue(gfx::ScrollOffset(0.f, 14600.f));
-  EXPECT_DOUBLE_EQ(2.0, curve->Duration());
+  EXPECT_DOUBLE_EQ(2.0, curve->Duration().InSecondsF());
 
   // x increases, y increases.
   curve->SetInitialValue(gfx::ScrollOffset(95.f, 191.f));
-  EXPECT_DOUBLE_EQ(0.05, curve->Duration());
+  EXPECT_DOUBLE_EQ(0.05, curve->Duration().InSecondsF());
 }
 
 TEST(ScrollOffsetAnimationCurveTest, GetValue) {
@@ -63,22 +63,22 @@
           EaseInOutTimingFunction::Create().Pass()));
   curve->SetInitialValue(initial_value);
 
-  double duration = curve->Duration();
-  EXPECT_GT(curve->Duration(), 0);
-  EXPECT_LT(curve->Duration(), 0.1);
+  double duration_in_seconds = curve->Duration().InSecondsF();
+  EXPECT_GT(curve->Duration().InSecondsF(), 0);
+  EXPECT_LT(curve->Duration().InSecondsF(), 0.1);
 
   EXPECT_EQ(AnimationCurve::ScrollOffset, curve->Type());
-  EXPECT_EQ(duration, curve->Duration());
+  EXPECT_EQ(duration_in_seconds, curve->Duration().InSecondsF());
 
   EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(-1.0));
   EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(0.0));
   EXPECT_VECTOR2DF_EQ(gfx::ScrollOffset(6.f, 30.f),
-                      curve->GetValue(duration/2.0));
-  EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration));
-  EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration+1.0));
+                      curve->GetValue(duration_in_seconds / 2.0));
+  EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration_in_seconds));
+  EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration_in_seconds + 1.0));
 
   // Verify that GetValue takes the timing function into account.
-  gfx::ScrollOffset value = curve->GetValue(duration/4.0);
+  gfx::ScrollOffset value = curve->GetValue(duration_in_seconds / 4.0);
   EXPECT_NEAR(3.0333f, value.x(), 0.00015f);
   EXPECT_NEAR(37.4168f, value.y(), 0.00015f);
 }
@@ -92,30 +92,30 @@
           target_value,
           EaseInOutTimingFunction::Create().Pass()));
   curve->SetInitialValue(initial_value);
-  double duration = curve->Duration();
+  double duration_in_seconds = curve->Duration().InSecondsF();
 
   scoped_ptr<AnimationCurve> clone(curve->Clone().Pass());
 
   EXPECT_EQ(AnimationCurve::ScrollOffset, clone->Type());
-  EXPECT_EQ(duration, clone->Duration());
+  EXPECT_EQ(duration_in_seconds, clone->Duration().InSecondsF());
 
   EXPECT_VECTOR2DF_EQ(initial_value,
                       clone->ToScrollOffsetAnimationCurve()->GetValue(-1.0));
   EXPECT_VECTOR2DF_EQ(initial_value,
                       clone->ToScrollOffsetAnimationCurve()->GetValue(0.0));
-  EXPECT_VECTOR2DF_EQ(
-      gfx::ScrollOffset(6.f, 30.f),
-      clone->ToScrollOffsetAnimationCurve()->GetValue(duration / 2.0));
+  EXPECT_VECTOR2DF_EQ(gfx::ScrollOffset(6.f, 30.f),
+                      clone->ToScrollOffsetAnimationCurve()->GetValue(
+                          duration_in_seconds / 2.0));
   EXPECT_VECTOR2DF_EQ(
       target_value,
-      clone->ToScrollOffsetAnimationCurve()->GetValue(duration));
-  EXPECT_VECTOR2DF_EQ(
-      target_value,
-      clone->ToScrollOffsetAnimationCurve()->GetValue(duration + 1.0));
+      clone->ToScrollOffsetAnimationCurve()->GetValue(duration_in_seconds));
+  EXPECT_VECTOR2DF_EQ(target_value,
+                      clone->ToScrollOffsetAnimationCurve()->GetValue(
+                          duration_in_seconds + 1.0));
 
   // Verify that the timing function was cloned correctly.
-  gfx::ScrollOffset value =
-      clone->ToScrollOffsetAnimationCurve()->GetValue(duration / 4.0);
+  gfx::ScrollOffset value = clone->ToScrollOffsetAnimationCurve()->GetValue(
+      duration_in_seconds / 4.0);
   EXPECT_NEAR(3.0333f, value.x(), 0.00015f);
   EXPECT_NEAR(37.4168f, value.y(), 0.00015f);
 }
@@ -127,20 +127,20 @@
       ScrollOffsetAnimationCurve::Create(
           target_value, EaseInOutTimingFunction::Create().Pass()));
   curve->SetInitialValue(initial_value);
-  EXPECT_EQ(1.0, curve->Duration());
+  EXPECT_EQ(1.0, curve->Duration().InSecondsF());
   EXPECT_EQ(1800.0, curve->GetValue(0.5).y());
   EXPECT_EQ(3600.0, curve->GetValue(1.0).y());
 
   curve->UpdateTarget(0.5, gfx::ScrollOffset(0.0, 9900.0));
 
-  EXPECT_EQ(2.0, curve->Duration());
+  EXPECT_EQ(2.0, curve->Duration().InSecondsF());
   EXPECT_EQ(1800.0, curve->GetValue(0.5).y());
   EXPECT_NEAR(5566.49, curve->GetValue(1.0).y(), 0.01);
   EXPECT_EQ(9900.0, curve->GetValue(2.0).y());
 
   curve->UpdateTarget(1.0, gfx::ScrollOffset(0.0, 7200.0));
 
-  EXPECT_NEAR(1.674, curve->Duration(), 0.01);
+  EXPECT_NEAR(1.674, curve->Duration().InSecondsF(), 0.01);
   EXPECT_NEAR(5566.49, curve->GetValue(1.0).y(), 0.01);
   EXPECT_EQ(7200.0, curve->GetValue(1.674).y());
 }
diff --git a/cc/base/time_util.h b/cc/base/time_util.h
new file mode 100644
index 0000000..dc07e74
--- /dev/null
+++ b/cc/base/time_util.h
@@ -0,0 +1,30 @@
+// 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_BASE_TIME_UTIL_H_
+#define CC_BASE_TIME_UTIL_H_
+
+namespace base {
+class TimeDelta;
+}
+
+namespace cc {
+
+class CC_EXPORT TimeUtil {
+ public:
+  static base::TimeDelta Scale(base::TimeDelta time_delta, double value) {
+    return base::TimeDelta::FromInternalValue(static_cast<int64>(
+        static_cast<double>(time_delta.ToInternalValue()) * value));
+  }
+
+  static base::TimeDelta Mod(base::TimeDelta dividend,
+                             base::TimeDelta divisor) {
+    return base::TimeDelta::FromInternalValue(dividend.ToInternalValue() %
+                                              divisor.ToInternalValue());
+  }
+};
+
+}  // namespace cc
+
+#endif  // CC_BASE_TIME_UTIL_H_
diff --git a/cc/blink/web_scroll_offset_animation_curve_impl.cc b/cc/blink/web_scroll_offset_animation_curve_impl.cc
index e789631..ba55d5b 100644
--- a/cc/blink/web_scroll_offset_animation_curve_impl.cc
+++ b/cc/blink/web_scroll_offset_animation_curve_impl.cc
@@ -39,7 +39,7 @@
 }
 
 double WebScrollOffsetAnimationCurveImpl::duration() const {
-  return curve_->Duration();
+  return curve_->Duration().InSecondsF();
 }
 
 scoped_ptr<cc::AnimationCurve>
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 308a61d..fac01a7 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -92,6 +92,7 @@
         'base/switches.h',
         'base/tiling_data.cc',
         'base/tiling_data.h',
+        'base/time_util.h',
         'base/unique_notifier.cc',
         'base/unique_notifier.h',
         'base/util.h',
@@ -140,11 +141,14 @@
         'debug/unittest_only_benchmark.h',
         'debug/unittest_only_benchmark_impl.cc',
         'debug/unittest_only_benchmark_impl.h',
+        'input/input_handler.cc',
         'input/input_handler.h',
         'input/page_scale_animation.cc',
         'input/page_scale_animation.h',
         'input/layer_selection_bound.cc',
         'input/layer_selection_bound.h',
+        'input/scroll_elasticity_helper.cc',
+        'input/scroll_elasticity_helper.h',
         'input/selection_bound_type.h',
         'input/top_controls_manager.cc',
         'input/top_controls_manager.h',
@@ -381,8 +385,6 @@
         'resources/picture_layer_tiling_set.h',
         'resources/picture_pile.cc',
         'resources/picture_pile.h',
-        'resources/picture_pile_base.cc',
-        'resources/picture_pile_base.h',
         'resources/picture_pile_impl.cc',
         'resources/picture_pile_impl.h',
         'resources/pixel_buffer_raster_worker_pool.cc',
@@ -403,6 +405,7 @@
         'resources/raster_worker_pool.h',
         'resources/rasterizer.cc',
         'resources/rasterizer.h',
+        'resources/recording_source.h',
         'resources/release_callback.h',
         'resources/resource.cc',
         'resources/resource.h',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 75267ef..db58318 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -170,6 +170,7 @@
       'test/fake_picture_layer_impl.h',
       'test/fake_picture_layer_tiling_client.cc',
       'test/fake_picture_layer_tiling_client.h',
+      'test/fake_picture_pile.h',
       'test/fake_picture_pile_impl.cc',
       'test/fake_picture_pile_impl.h',
       'test/fake_proxy.cc',
diff --git a/cc/debug/benchmark_instrumentation.cc b/cc/debug/benchmark_instrumentation.cc
index 74caae8..1cb5bc3 100644
--- a/cc/debug/benchmark_instrumentation.cc
+++ b/cc/debug/benchmark_instrumentation.cc
@@ -12,16 +12,7 @@
 // tools/perf/measurements/rendering_stats.py accordingly.
 // The benchmarks search for events and their arguments by name.
 
-void IssueMainThreadRenderingStatsEvent(
-    const RenderingStats::MainThreadRenderingStats& stats) {
-  TRACE_EVENT_INSTANT1("benchmark",
-                       "BenchmarkInstrumentation::MainThreadRenderingStats",
-                       TRACE_EVENT_SCOPE_THREAD,
-                       "data", stats.AsTraceableData());
-}
-
-void IssueImplThreadRenderingStatsEvent(
-    const RenderingStats::ImplThreadRenderingStats& stats) {
+void IssueImplThreadRenderingStatsEvent(const RenderingStats& stats) {
   TRACE_EVENT_INSTANT1("benchmark",
                        "BenchmarkInstrumentation::ImplThreadRenderingStats",
                        TRACE_EVENT_SCOPE_THREAD,
diff --git a/cc/debug/benchmark_instrumentation.h b/cc/debug/benchmark_instrumentation.h
index bd524b9..944ac66 100644
--- a/cc/debug/benchmark_instrumentation.h
+++ b/cc/debug/benchmark_instrumentation.h
@@ -42,10 +42,7 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedBeginFrameTask);
 };
 
-void IssueMainThreadRenderingStatsEvent(
-    const RenderingStats::MainThreadRenderingStats& stats);
-void IssueImplThreadRenderingStatsEvent(
-    const RenderingStats::ImplThreadRenderingStats& stats);
+void IssueImplThreadRenderingStatsEvent(const RenderingStats& stats);
 void CC_EXPORT IssueDisplayRenderingStatsEvent();
 
 }  // namespace benchmark_instrumentation
diff --git a/cc/debug/picture_record_benchmark.cc b/cc/debug/picture_record_benchmark.cc
index 5f832ae..ab50c7c 100644
--- a/cc/debug/picture_record_benchmark.cc
+++ b/cc/debug/picture_record_benchmark.cc
@@ -10,8 +10,10 @@
 #include "base/values.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/picture_layer.h"
+#include "cc/resources/picture.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_common.h"
+#include "third_party/skia/include/core/SkBBHFactory.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace cc {
diff --git a/cc/debug/rasterize_and_record_benchmark.cc b/cc/debug/rasterize_and_record_benchmark.cc
index f24dce3..a2052ab 100644
--- a/cc/debug/rasterize_and_record_benchmark.cc
+++ b/cc/debug/rasterize_and_record_benchmark.cc
@@ -15,6 +15,7 @@
 #include "cc/debug/rasterize_and_record_benchmark_impl.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/picture_layer.h"
+#include "cc/resources/picture_pile.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "ui/gfx/geometry/rect.h"
@@ -106,7 +107,7 @@
   gfx::Size tile_grid_size = host_->settings().default_tile_size;
 
   SkTileGridFactory::TileGridInfo tile_grid_info;
-  PicturePileBase::ComputeTileGridInfo(tile_grid_size, &tile_grid_info);
+  PicturePile::ComputeTileGridInfo(tile_grid_size, &tile_grid_info);
 
   gfx::Rect visible_content_rect = gfx::ScaleToEnclosingRect(
       layer->visible_content_rect(), 1.f / layer->contents_scale_x());
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc
index 2ffac1b..07058d0 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -121,6 +121,10 @@
     return base_client_->GetRecycledTwinTiling(tiling);
   }
 
+  TilePriority::PriorityBin GetMaxTilePriorityBin() const override {
+    return base_client_->GetMaxTilePriorityBin();
+  }
+
   size_t GetMaxTilesForInterestArea() const override {
     return base_client_->GetMaxTilesForInterestArea();
   }
diff --git a/cc/debug/rendering_stats.cc b/cc/debug/rendering_stats.cc
index 558c882..9c62a3c 100644
--- a/cc/debug/rendering_stats.cc
+++ b/cc/debug/rendering_stats.cc
@@ -18,9 +18,8 @@
 
 void RenderingStats::TimeDeltaList::AddToTracedValue(
     base::debug::TracedValue* list_value) const {
-  std::list<base::TimeDelta>::const_iterator iter;
-  for (iter = values.begin(); iter != values.end(); ++iter) {
-    list_value->AppendDouble(iter->InMillisecondsF());
+  for (const auto& value : values) {
+    list_value->AppendDouble(value.InMillisecondsF());
   }
 }
 
@@ -32,43 +31,17 @@
   return values.empty() ? base::TimeDelta() : values.back();
 }
 
-RenderingStats::MainThreadRenderingStats::MainThreadRenderingStats()
-    : painted_pixel_count(0), recorded_pixel_count(0) {
-}
-
-RenderingStats::MainThreadRenderingStats::~MainThreadRenderingStats() {
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-RenderingStats::MainThreadRenderingStats::AsTraceableData() const {
-  scoped_refptr<base::debug::TracedValue> record_data =
-      new base::debug::TracedValue();
-  record_data->SetDouble("paint_time", paint_time.InSecondsF());
-  record_data->SetInteger("painted_pixel_count", painted_pixel_count);
-  record_data->SetDouble("record_time", record_time.InSecondsF());
-  record_data->SetInteger("recorded_pixel_count", recorded_pixel_count);
-  return record_data;
-}
-
-void RenderingStats::MainThreadRenderingStats::Add(
-    const MainThreadRenderingStats& other) {
-  paint_time += other.paint_time;
-  painted_pixel_count += other.painted_pixel_count;
-  record_time += other.record_time;
-  recorded_pixel_count += other.recorded_pixel_count;
-}
-
-RenderingStats::ImplThreadRenderingStats::ImplThreadRenderingStats()
+RenderingStats::RenderingStats()
     : frame_count(0),
       visible_content_area(0),
       approximated_visible_content_area(0) {
 }
 
-RenderingStats::ImplThreadRenderingStats::~ImplThreadRenderingStats() {
+RenderingStats::~RenderingStats() {
 }
 
 scoped_refptr<base::debug::ConvertableToTraceFormat>
-RenderingStats::ImplThreadRenderingStats::AsTraceableData() const {
+RenderingStats::AsTraceableData() const {
   scoped_refptr<base::debug::TracedValue> record_data =
       new base::debug::TracedValue();
   record_data->SetInteger("frame_count", frame_count);
@@ -102,8 +75,7 @@
   return record_data;
 }
 
-void RenderingStats::ImplThreadRenderingStats::Add(
-    const ImplThreadRenderingStats& other) {
+void RenderingStats::Add(const RenderingStats& other) {
   frame_count += other.frame_count;
   visible_content_area += other.visible_content_area;
   approximated_visible_content_area += other.approximated_visible_content_area;
@@ -119,9 +91,4 @@
       other.commit_to_activate_duration_estimate);
 }
 
-void RenderingStats::Add(const RenderingStats& other) {
-  main_stats.Add(other.main_stats);
-  impl_stats.Add(other.impl_stats);
-}
-
 }  // namespace cc
diff --git a/cc/debug/rendering_stats.h b/cc/debug/rendering_stats.h
index 7b1898a..193454c 100644
--- a/cc/debug/rendering_stats.h
+++ b/cc/debug/rendering_stats.h
@@ -31,51 +31,27 @@
     base::TimeDelta GetLastTimeDelta() const;
 
    private:
-    std::list<base::TimeDelta> values;
+    std::vector<base::TimeDelta> values;
   };
 
-  struct CC_EXPORT MainThreadRenderingStats {
-    // Note: when adding new members, please remember to update Add in
-    // rendering_stats.cc.
+  RenderingStats();
+  ~RenderingStats();
 
-    base::TimeDelta paint_time;
-    int64 painted_pixel_count;
-    base::TimeDelta record_time;
-    int64 recorded_pixel_count;
+  // Note: when adding new members, please remember to update Add in
+  // rendering_stats.cc.
 
-    MainThreadRenderingStats();
-    ~MainThreadRenderingStats();
-    scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData()
-        const;
-    void Add(const MainThreadRenderingStats& other);
-  };
+  int64 frame_count;
+  int64 visible_content_area;
+  int64 approximated_visible_content_area;
 
-  struct CC_EXPORT ImplThreadRenderingStats {
-    // Note: when adding new members, please remember to update Add in
-    // rendering_stats.cc.
+  TimeDeltaList draw_duration;
+  TimeDeltaList draw_duration_estimate;
+  TimeDeltaList begin_main_frame_to_commit_duration;
+  TimeDeltaList begin_main_frame_to_commit_duration_estimate;
+  TimeDeltaList commit_to_activate_duration;
+  TimeDeltaList commit_to_activate_duration_estimate;
 
-    int64 frame_count;
-    int64 visible_content_area;
-    int64 approximated_visible_content_area;
-
-    TimeDeltaList draw_duration;
-    TimeDeltaList draw_duration_estimate;
-    TimeDeltaList begin_main_frame_to_commit_duration;
-    TimeDeltaList begin_main_frame_to_commit_duration_estimate;
-    TimeDeltaList commit_to_activate_duration;
-    TimeDeltaList commit_to_activate_duration_estimate;
-
-    ImplThreadRenderingStats();
-    ~ImplThreadRenderingStats();
-    scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData()
-        const;
-    void Add(const ImplThreadRenderingStats& other);
-  };
-
-  MainThreadRenderingStats main_stats;
-  ImplThreadRenderingStats impl_stats;
-
-  // Add fields of |other| to the fields in this structure.
+  scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData() const;
   void Add(const RenderingStats& other);
 };
 
diff --git a/cc/debug/rendering_stats_instrumentation.cc b/cc/debug/rendering_stats_instrumentation.cc
index f5f2e07..c707e23 100644
--- a/cc/debug/rendering_stats_instrumentation.cc
+++ b/cc/debug/rendering_stats_instrumentation.cc
@@ -18,14 +18,7 @@
 
 RenderingStatsInstrumentation::~RenderingStatsInstrumentation() {}
 
-RenderingStats::MainThreadRenderingStats
-RenderingStatsInstrumentation::main_thread_rendering_stats() {
-  base::AutoLock scoped_lock(lock_);
-  return main_thread_rendering_stats_;
-}
-
-RenderingStats::ImplThreadRenderingStats
-RenderingStatsInstrumentation::impl_thread_rendering_stats() {
+RenderingStats RenderingStatsInstrumentation::impl_thread_rendering_stats() {
   base::AutoLock scoped_lock(lock_);
   return impl_thread_rendering_stats_;
 }
@@ -33,23 +26,15 @@
 RenderingStats RenderingStatsInstrumentation::GetRenderingStats() {
   base::AutoLock scoped_lock(lock_);
   RenderingStats rendering_stats;
-  rendering_stats.main_stats = main_thread_rendering_stats_accu_;
-  rendering_stats.main_stats.Add(main_thread_rendering_stats_);
-  rendering_stats.impl_stats = impl_thread_rendering_stats_accu_;
-  rendering_stats.impl_stats.Add(impl_thread_rendering_stats_);
+  rendering_stats = impl_thread_rendering_stats_accu_;
+  rendering_stats.Add(impl_thread_rendering_stats_);
   return rendering_stats;
 }
 
-void RenderingStatsInstrumentation::AccumulateAndClearMainThreadStats() {
-  base::AutoLock scoped_lock(lock_);
-  main_thread_rendering_stats_accu_.Add(main_thread_rendering_stats_);
-  main_thread_rendering_stats_ = RenderingStats::MainThreadRenderingStats();
-}
-
 void RenderingStatsInstrumentation::AccumulateAndClearImplThreadStats() {
   base::AutoLock scoped_lock(lock_);
   impl_thread_rendering_stats_accu_.Add(impl_thread_rendering_stats_);
-  impl_thread_rendering_stats_ = RenderingStats::ImplThreadRenderingStats();
+  impl_thread_rendering_stats_ = RenderingStats();
 }
 
 base::TimeTicks RenderingStatsInstrumentation::StartRecording() const {
@@ -79,26 +64,6 @@
   impl_thread_rendering_stats_.frame_count += count;
 }
 
-void RenderingStatsInstrumentation::AddPaint(base::TimeDelta duration,
-                                             int64 pixels) {
-  if (!record_rendering_stats_)
-    return;
-
-  base::AutoLock scoped_lock(lock_);
-  main_thread_rendering_stats_.paint_time += duration;
-  main_thread_rendering_stats_.painted_pixel_count += pixels;
-}
-
-void RenderingStatsInstrumentation::AddRecord(base::TimeDelta duration,
-                                              int64 pixels) {
-  if (!record_rendering_stats_)
-    return;
-
-  base::AutoLock scoped_lock(lock_);
-  main_thread_rendering_stats_.record_time += duration;
-  main_thread_rendering_stats_.recorded_pixel_count += pixels;
-}
-
 void RenderingStatsInstrumentation::AddVisibleContentArea(int64 area) {
   if (!record_rendering_stats_)
     return;
diff --git a/cc/debug/rendering_stats_instrumentation.h b/cc/debug/rendering_stats_instrumentation.h
index 734583a..8d95929 100644
--- a/cc/debug/rendering_stats_instrumentation.h
+++ b/cc/debug/rendering_stats_instrumentation.h
@@ -18,19 +18,12 @@
   static scoped_ptr<RenderingStatsInstrumentation> Create();
   virtual ~RenderingStatsInstrumentation();
 
-  // Return copy of current main thread rendering stats.
-  RenderingStats::MainThreadRenderingStats main_thread_rendering_stats();
-
   // Return copy of current impl thread rendering stats.
-  RenderingStats::ImplThreadRenderingStats impl_thread_rendering_stats();
+  RenderingStats impl_thread_rendering_stats();
 
   // Return the accumulated, combined rendering stats.
   RenderingStats GetRenderingStats();
 
-  // Add current main thread rendering stats to accumulator and
-  // clear current stats.
-  void AccumulateAndClearMainThreadStats();
-
   // Add current impl thread rendering stats to accumulator and
   // clear current stats.
   void AccumulateAndClearImplThreadStats();
@@ -48,8 +41,6 @@
   base::TimeDelta EndRecording(base::TimeTicks start_time) const;
 
   void IncrementFrameCount(int64 count);
-  void AddPaint(base::TimeDelta duration, int64 pixels);
-  void AddRecord(base::TimeDelta duration, int64 pixels);
   void AddVisibleContentArea(int64 area);
   void AddApproximatedVisibleContentArea(int64 area);
   void AddDrawDuration(base::TimeDelta draw_duration,
@@ -65,10 +56,8 @@
   RenderingStatsInstrumentation();
 
  private:
-  RenderingStats::MainThreadRenderingStats main_thread_rendering_stats_;
-  RenderingStats::MainThreadRenderingStats main_thread_rendering_stats_accu_;
-  RenderingStats::ImplThreadRenderingStats impl_thread_rendering_stats_;
-  RenderingStats::ImplThreadRenderingStats impl_thread_rendering_stats_accu_;
+  RenderingStats impl_thread_rendering_stats_;
+  RenderingStats impl_thread_rendering_stats_accu_;
 
   bool record_rendering_stats_;
 
diff --git a/cc/input/input_handler.cc b/cc/input/input_handler.cc
new file mode 100644
index 0000000..336d0d4
--- /dev/null
+++ b/cc/input/input_handler.cc
@@ -0,0 +1,13 @@
+// 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/input/input_handler.h"
+
+namespace cc {
+
+InputHandlerScrollResult::InputHandlerScrollResult()
+    : did_scroll(false), did_overscroll_root(false) {
+}
+
+}  // namespace cc
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index b3205a8..7b83e4b 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -6,6 +6,7 @@
 #define CC_INPUT_INPUT_HANDLER_H_
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
 #include "cc/base/cc_export.h"
 #include "cc/base/swap_promise_monitor.h"
@@ -23,6 +24,22 @@
 namespace cc {
 
 class LayerScrollOffsetDelegate;
+class ScrollElasticityHelper;
+
+struct CC_EXPORT InputHandlerScrollResult {
+  InputHandlerScrollResult();
+  // Did any layer scroll as a result this ScrollBy call?
+  bool did_scroll;
+  // Was any of the scroll delta argument to this ScrollBy call not used?
+  bool did_overscroll_root;
+  // The total overscroll that has been accumulated by all ScrollBy calls that
+  // have had overscroll since the last ScrollBegin call. This resets upon a
+  // ScrollBy with no overscroll.
+  gfx::Vector2dF accumulated_root_overscroll;
+  // The amount of the scroll delta argument to this ScrollBy call that was not
+  // used for scrolling.
+  gfx::Vector2dF unused_scroll_delta;
+};
 
 class CC_EXPORT InputHandlerClient {
  public:
@@ -32,13 +49,6 @@
   virtual void Animate(base::TimeTicks time) = 0;
   virtual void MainThreadHasStoppedFlinging() = 0;
 
-  // Called when scroll deltas reaching the root scrolling layer go unused.
-  // The accumulated overscroll is scoped by the most recent call to
-  // InputHandler::ScrollBegin.
-  virtual void DidOverscroll(const gfx::PointF& causal_event_viewport_point,
-                             const gfx::Vector2dF& accumulated_overscroll,
-                             const gfx::Vector2dF& latest_overscroll_delta) = 0;
-
  protected:
   InputHandlerClient() {}
 
@@ -85,15 +95,16 @@
   // should be in viewport (logical pixel) coordinates. Otherwise they are in
   // scrolling layer's (logical pixel) space. If there is no room to move the
   // layer in the requested direction, its first ancestor layer that can be
-  // scrolled will be moved instead. If no layer can be moved in the requested
-  // direction at all, then false is returned. If any layer is moved, then
-  // true is returned.
+  // scrolled will be moved instead. The return value's |did_scroll| field is
+  // set to false if no layer can be moved in the requested direction at all,
+  // and set to true if any layer is moved.
   // If the scroll delta hits the root layer, and the layer can no longer move,
   // the root overscroll accumulated within this ScrollBegin() scope is reported
-  // to the client.
+  // in the return value's |accumulated_overscroll| field.
   // Should only be called if ScrollBegin() returned ScrollStarted.
-  virtual bool ScrollBy(const gfx::Point& viewport_point,
-                        const gfx::Vector2dF& scroll_delta) = 0;
+  virtual InputHandlerScrollResult ScrollBy(
+      const gfx::Point& viewport_point,
+      const gfx::Vector2dF& scroll_delta) = 0;
 
   virtual bool ScrollVerticallyByPage(const gfx::Point& viewport_point,
                                       ScrollDirection direction) = 0;
@@ -140,6 +151,8 @@
   virtual scoped_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
       ui::LatencyInfo* latency) = 0;
 
+  virtual ScrollElasticityHelper* CreateScrollElasticityHelper() = 0;
+
  protected:
   InputHandler() {}
   virtual ~InputHandler() {}
diff --git a/cc/input/scroll_elasticity_helper.cc b/cc/input/scroll_elasticity_helper.cc
new file mode 100644
index 0000000..54da888
--- /dev/null
+++ b/cc/input/scroll_elasticity_helper.cc
@@ -0,0 +1,101 @@
+// 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/input/scroll_elasticity_helper.h"
+
+#include "cc/layers/layer_impl.h"
+#include "cc/trees/layer_tree_host_impl.h"
+#include "cc/trees/layer_tree_impl.h"
+
+namespace cc {
+
+ScrollElasticityHelper::ScrollElasticityHelper(LayerTreeHostImpl* layer_tree)
+    : layer_tree_host_impl_(layer_tree), timer_active_(false) {
+}
+
+ScrollElasticityHelper::~ScrollElasticityHelper() {
+}
+
+bool ScrollElasticityHelper::AllowsHorizontalStretching() {
+  // The WebKit implementation has this interface because it is written in terms
+  // of overscrolling on a per-layer basis, not for the whole layer tree. In
+  // that implementation, this always returns true for the frame view's
+  // scrollable area.
+  // TODO(ccameron): This is function is redundant and may be removed.
+  return true;
+}
+
+bool ScrollElasticityHelper::AllowsVerticalStretching() {
+  // TODO(ccameron): This is function is redundant and may be removed.
+  return true;
+}
+
+gfx::Vector2dF ScrollElasticityHelper::StretchAmount() {
+  return stretch_offset_;
+}
+
+bool ScrollElasticityHelper::PinnedInDirection(
+    const gfx::Vector2dF& direction) {
+  gfx::ScrollOffset scroll_offset =
+      layer_tree_host_impl_->active_tree()->TotalScrollOffset();
+  gfx::ScrollOffset max_scroll_offset =
+      layer_tree_host_impl_->active_tree()->TotalMaxScrollOffset();
+  bool result = false;
+  if (direction.x() < 0)
+    result |= scroll_offset.x() <= 0;
+  if (direction.x() > 0)
+    result |= scroll_offset.x() >= max_scroll_offset.x();
+  if (direction.y() < 0)
+    result |= scroll_offset.y() <= 0;
+  if (direction.y() > 0)
+    result |= scroll_offset.y() >= max_scroll_offset.y();
+  return result;
+}
+
+bool ScrollElasticityHelper::CanScrollHorizontally() {
+  return layer_tree_host_impl_->active_tree()->TotalMaxScrollOffset().x() > 0;
+}
+
+bool ScrollElasticityHelper::CanScrollVertically() {
+  return layer_tree_host_impl_->active_tree()->TotalMaxScrollOffset().y() > 0;
+}
+
+gfx::Vector2dF ScrollElasticityHelper::AbsoluteScrollPosition() {
+  // TODO(ccameron): This is function is redundant and may be removed.
+  return stretch_offset_;
+}
+
+void ScrollElasticityHelper::ImmediateScrollBy(const gfx::Vector2dF& scroll) {
+  // TODO(ccameron): This is function is redundant and may be removed.
+}
+
+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.
+}
+
+void ScrollElasticityHelper::StartSnapRubberbandTimer() {
+  if (timer_active_)
+    return;
+  timer_active_ = true;
+  layer_tree_host_impl_->SetNeedsAnimate();
+}
+
+void ScrollElasticityHelper::StopSnapRubberbandTimer() {
+  timer_active_ = false;
+}
+
+void ScrollElasticityHelper::SnapRubberbandTimerFired() {
+  if (timer_active_)
+    layer_tree_host_impl_->SetNeedsAnimate();
+}
+
+void ScrollElasticityHelper::AdjustScrollPositionToBoundsIfNecessary() {
+  // TODO(ccameron): This is function is redundant and may be removed.
+}
+
+}  // namespace cc
diff --git a/cc/input/scroll_elasticity_helper.h b/cc/input/scroll_elasticity_helper.h
new file mode 100644
index 0000000..645b20c
--- /dev/null
+++ b/cc/input/scroll_elasticity_helper.h
@@ -0,0 +1,84 @@
+// 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_INPUT_SCROLL_ELASTICITY_HELPER_H_
+#define CC_INPUT_SCROLL_ELASTICITY_HELPER_H_
+
+#include "base/time/time.h"
+#include "cc/base/cc_export.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace cc {
+
+class LayerTreeHostImpl;
+
+// ScrollElasticityHelper is based on
+// WebKit/Source/platform/mac/ScrollElasticityController.h
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Interface between a LayerTreeHostImpl and the ScrollElasticityController. It
+// would be possible, in principle, for LayerTreeHostImpl to implement this
+// interface itself. This artificial boundary is introduced to reduce the amount
+// of logic and state held directly inside LayerTreeHostImpl.
+class CC_EXPORT ScrollElasticityHelper {
+ public:
+  explicit ScrollElasticityHelper(LayerTreeHostImpl* layer_tree);
+  ~ScrollElasticityHelper();
+
+  bool AllowsHorizontalStretching();
+  bool AllowsVerticalStretching();
+  // The amount that the view is stretched past the normal allowable bounds.
+  // The "overhang" amount.
+  gfx::Vector2dF StretchAmount();
+  bool PinnedInDirection(const gfx::Vector2dF& direction);
+  bool CanScrollHorizontally();
+  bool CanScrollVertically();
+
+  // Return the absolute scroll position, not relative to the scroll origin.
+  gfx::Vector2dF AbsoluteScrollPosition();
+
+  void ImmediateScrollBy(const gfx::Vector2dF& scroll);
+  void ImmediateScrollByWithoutContentEdgeConstraints(
+      const gfx::Vector2dF& scroll);
+  void StartSnapRubberbandTimer();
+  void StopSnapRubberbandTimer();
+  void SnapRubberbandTimerFired();
+
+  // If the current scroll position is within the overhang area, this function
+  // will cause
+  // the page to scroll to the nearest boundary point.
+  void AdjustScrollPositionToBoundsIfNecessary();
+
+ private:
+  LayerTreeHostImpl* layer_tree_host_impl_;
+  gfx::Vector2dF stretch_offset_;
+  bool timer_active_;
+};
+
+}  // namespace cc
+
+#endif  // CC_INPUT_SCROLL_ELASTICITY_HELPER_H_
diff --git a/cc/layers/content_layer.cc b/cc/layers/content_layer.cc
index d3e9a28..88031e4 100644
--- a/cc/layers/content_layer.cc
+++ b/cc/layers/content_layer.cc
@@ -57,13 +57,6 @@
 
   if (!updater_.get())
     return;
-
-  if (host) {
-    updater_->set_rendering_stats_instrumentation(
-        host->rendering_stats_instrumentation());
-  } else {
-    updater_->set_rendering_stats_instrumentation(nullptr);
-  }
 }
 
 void ContentLayer::SetTexturePriorities(
@@ -108,7 +101,6 @@
   } else {
     updater_ = BitmapContentLayerUpdater::Create(
         painter.Pass(),
-        rendering_stats_instrumentation(),
         id());
   }
   updater_->SetOpaque(contents_opaque());
diff --git a/cc/layers/draw_properties.h b/cc/layers/draw_properties.h
index 403393e..2e54083 100644
--- a/cc/layers/draw_properties.h
+++ b/cc/layers/draw_properties.h
@@ -6,6 +6,7 @@
 #define CC_LAYERS_DRAW_PROPERTIES_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "third_party/skia/include/core/SkXfermode.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/transform.h"
 
@@ -17,6 +18,7 @@
 struct CC_EXPORT DrawProperties {
   DrawProperties()
       : opacity(0.f),
+        blend_mode(SkXfermode::kSrcOver_Mode),
         opacity_is_animating(false),
         screen_space_opacity_is_animating(false),
         target_space_transform_is_animating(false),
@@ -53,6 +55,10 @@
   // opacity, or when opacity is compounded by the hierarchy.
   float opacity;
 
+  // DrawProperties::blend_mode may be different than LayerType::blend_mode,
+  // when a RenderSurface re-parents the layer's blend_mode.
+  SkXfermode::Mode blend_mode;
+
   // xxx_is_animating flags are used to indicate whether the DrawProperties
   // are actually meaningful on the main thread. When the properties are
   // animating, the main thread may not have the same values that are used
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index f09761b..a99ede8 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -255,14 +255,11 @@
 }
 
 void LayerImpl::PopulateSharedQuadState(SharedQuadState* state) const {
-  state->SetAll(draw_properties_.target_space_transform,
-                draw_properties_.content_bounds,
-                draw_properties_.visible_content_rect,
-                draw_properties_.clip_rect,
-                draw_properties_.is_clipped,
-                draw_properties_.opacity,
-                blend_mode_,
-                sorting_context_id_);
+  state->SetAll(
+      draw_properties_.target_space_transform, draw_properties_.content_bounds,
+      draw_properties_.visible_content_rect, draw_properties_.clip_rect,
+      draw_properties_.is_clipped, draw_properties_.opacity,
+      draw_properties_.blend_mode, sorting_context_id_);
 }
 
 bool LayerImpl::WillDraw(DrawMode draw_mode,
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 5fe679c..12f1dca 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -323,6 +323,9 @@
     return draw_properties_.screen_space_transform;
   }
   float draw_opacity() const { return draw_properties_.opacity; }
+  SkXfermode::Mode draw_blend_mode() const {
+    return draw_properties_.blend_mode;
+  }
   bool draw_opacity_is_animating() const {
     return draw_properties_.opacity_is_animating;
   }
diff --git a/cc/layers/layer_perftest.cc b/cc/layers/layer_perftest.cc
index fcd0844..f42e228 100644
--- a/cc/layers/layer_perftest.cc
+++ b/cc/layers/layer_perftest.cc
@@ -40,7 +40,7 @@
   virtual void SetUp() override {
     layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_);
     layer_tree_host_->InitializeSingleThreaded(
-        &fake_client_, base::MessageLoopProxy::current());
+        &fake_client_, base::MessageLoopProxy::current(), nullptr);
   }
 
   virtual void TearDown() override {
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index ecdd916..246a658 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -42,7 +42,9 @@
  public:
   explicit MockLayerTreeHost(FakeLayerTreeHostClient* client)
       : LayerTreeHost(client, nullptr, nullptr, LayerTreeSettings()) {
-    InitializeSingleThreaded(client, base::MessageLoopProxy::current());
+    InitializeSingleThreaded(client,
+                             base::MessageLoopProxy::current(),
+                             nullptr);
   }
 
   MOCK_METHOD0(SetNeedsCommit, void());
@@ -935,7 +937,8 @@
                shared_bitmap_manager_.get(),
                gpu_memory_buffer_manager_.get(),
                LayerTreeSettings(),
-               base::MessageLoopProxy::current()).Pass();
+               base::MessageLoopProxy::current(),
+               nullptr);
   }
 
   scoped_ptr<LayerTreeHost> Create(LayerTreeSettings settings) {
@@ -945,7 +948,8 @@
                shared_bitmap_manager_.get(),
                gpu_memory_buffer_manager_.get(),
                settings,
-               base::MessageLoopProxy::current()).Pass();
+               base::MessageLoopProxy::current(),
+               nullptr);
   }
 
  private:
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc
index fcaacc7..1c766ba 100644
--- a/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -60,9 +60,9 @@
     }
     TestablePictureImageLayerImpl* layer =
         new TestablePictureImageLayerImpl(tree, id);
-    layer->pile_ = FakePicturePileImpl::CreateInfiniteFilledPile();
-    layer->SetBounds(layer->pile_->tiling_size());
-    layer->SetContentBounds(layer->pile_->tiling_size());
+    layer->raster_source_ = FakePicturePileImpl::CreateInfiniteFilledPile();
+    layer->SetBounds(layer->raster_source_->GetSize());
+    layer->SetContentBounds(layer->raster_source_->GetSize());
     return make_scoped_ptr(layer);
   }
 
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index c56ff8b..5d45cae 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -7,6 +7,7 @@
 #include "base/auto_reset.h"
 #include "cc/layers/content_layer_client.h"
 #include "cc/layers/picture_layer_impl.h"
+#include "cc/resources/picture_pile.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "third_party/skia/include/core/SkPictureRecorder.h"
 #include "ui/gfx/geometry/rect_conversions.h"
@@ -19,6 +20,7 @@
 
 PictureLayer::PictureLayer(ContentLayerClient* client)
     : client_(client),
+      recording_source_(new PicturePile),
       instrumentation_object_tracker_(id()),
       update_source_frame_number_(-1),
       can_use_lcd_text_last_frame_(can_use_lcd_text()) {
@@ -37,38 +39,39 @@
 
   int source_frame_number = layer_tree_host()->source_frame_number();
   gfx::Size impl_bounds = layer_impl->bounds();
-  gfx::Size pile_bounds = pile_.tiling_size();
+  gfx::Size recording_source_bounds = recording_source_->GetSize();
 
-  // If update called, then pile size must match bounds pushed to impl layer.
+  // If update called, then recording source size must match bounds pushed to
+  // impl layer.
   DCHECK_IMPLIES(update_source_frame_number_ == source_frame_number,
-                 impl_bounds == pile_bounds)
-      << " bounds " << impl_bounds.ToString() << " pile "
-      << pile_bounds.ToString();
+                 impl_bounds == recording_source_bounds)
+      << " bounds " << impl_bounds.ToString() << " recording source "
+      << recording_source_bounds.ToString();
 
   if (update_source_frame_number_ != source_frame_number &&
-      pile_bounds != impl_bounds) {
+      recording_source_bounds != impl_bounds) {
     // Update may not get called for the layer (if it's not in the viewport
-    // for example, even though it has resized making the pile no longer
-    // valid. In this case just destroy the pile.
-    pile_.SetEmptyBounds();
+    // for example, even though it has resized making the recording source no
+    // longer valid. In this case just destroy the recording source.
+    recording_source_->SetEmptyBounds();
   }
 
   // Unlike other properties, invalidation must always be set on layer_impl.
   // See PictureLayerImpl::PushPropertiesTo for more details.
   layer_impl->invalidation_.Clear();
-  layer_impl->invalidation_.Swap(&pile_invalidation_);
-  layer_impl->UpdatePile(PicturePileImpl::CreateFromOther(&pile_));
+  layer_impl->invalidation_.Swap(&recording_invalidation_);
+  layer_impl->UpdateRasterSource(recording_source_->CreateRasterSource());
 }
 
 void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
   Layer::SetLayerTreeHost(host);
   if (host) {
-    pile_.SetMinContentsScale(host->settings().minimum_contents_scale);
-    pile_.SetTileGridSize(host->settings().default_tile_grid_size);
-    pile_.set_slow_down_raster_scale_factor(
+    // TODO(hendrikw): Perhaps use and initialization function to do this work.
+    recording_source_->SetMinContentsScale(
+        host->settings().minimum_contents_scale);
+    recording_source_->SetTileGridSize(host->settings().default_tile_grid_size);
+    recording_source_->SetSlowdownRasterScaleFactor(
         host->debug_state().slow_down_raster_scale_factor);
-    pile_.set_show_debug_picture_borders(
-        host->debug_state().show_picture_borders);
   }
 }
 
@@ -97,7 +100,8 @@
   gfx::Size layer_size = paint_properties().bounds;
 
   if (last_updated_visible_content_rect_ == visible_content_rect() &&
-      pile_.tiling_size() == layer_size && pending_invalidation_.IsEmpty()) {
+      recording_source_->GetSize() == layer_size &&
+      pending_invalidation_.IsEmpty()) {
     // Only early out if the visible content rect of this layer hasn't changed.
     return updated;
   }
@@ -110,7 +114,7 @@
 
   // Calling paint in WebKit can sometimes cause invalidations, so save
   // off the invalidation prior to calling update.
-  pending_invalidation_.Swap(&pile_invalidation_);
+  pending_invalidation_.Swap(&recording_invalidation_);
   pending_invalidation_.Clear();
 
   if (layer_tree_host()->settings().record_full_layer) {
@@ -124,32 +128,26 @@
   // to the impl side so that it drops tiles that may not have a recording
   // for them.
   DCHECK(client_);
-  updated |=
-      pile_.UpdateAndExpandInvalidation(client_,
-                                        &pile_invalidation_,
-                                        SafeOpaqueBackgroundColor(),
-                                        contents_opaque(),
-                                        client_->FillsBoundsCompletely(),
-                                        layer_size,
-                                        visible_layer_rect,
-                                        update_source_frame_number_,
-                                        Picture::RECORD_NORMALLY,
-                                        rendering_stats_instrumentation());
+  updated |= recording_source_->UpdateAndExpandInvalidation(
+      client_, &recording_invalidation_, SafeOpaqueBackgroundColor(),
+      contents_opaque(), client_->FillsBoundsCompletely(), layer_size,
+      visible_layer_rect, update_source_frame_number_,
+      Picture::RECORD_NORMALLY);
   last_updated_visible_content_rect_ = visible_content_rect();
 
   if (updated) {
     SetNeedsPushProperties();
   } else {
-    // If this invalidation did not affect the pile, then it can be cleared as
-    // an optimization.
-    pile_invalidation_.Clear();
+    // If this invalidation did not affect the recording source, then it can be
+    // cleared as an optimization.
+    recording_invalidation_.Clear();
   }
 
   return updated;
 }
 
 void PictureLayer::SetIsMask(bool is_mask) {
-  pile_.set_is_mask(is_mask);
+  recording_source_->SetIsMask(is_mask);
 }
 
 bool PictureLayer::SupportsLCDText() const {
@@ -166,7 +164,7 @@
 }
 
 skia::RefPtr<SkPicture> PictureLayer::GetPicture() const {
-  // We could either flatten the PicturePile into a single SkPicture,
+  // We could either flatten the RecordingSource into a single SkPicture,
   // or paint a fresh one depending on what we intend to do with the
   // picture. For now we just paint a fresh one to get consistent results.
   if (!DrawsContent())
@@ -185,7 +183,7 @@
 }
 
 bool PictureLayer::IsSuitableForGpuRasterization() const {
-  return pile_.is_suitable_for_gpu_rasterization();
+  return recording_source_->IsSuitableForGpuRasterization();
 }
 
 void PictureLayer::ClearClient() {
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index 232dba2..2969ee1 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -9,12 +9,12 @@
 #include "cc/debug/devtools_instrumentation.h"
 #include "cc/debug/micro_benchmark_controller.h"
 #include "cc/layers/layer.h"
-#include "cc/resources/picture_pile.h"
 #include "cc/trees/occlusion_tracker.h"
 
 namespace cc {
 
 class ContentLayerClient;
+class RecordingSource;
 class ResourceUpdateQueue;
 
 class CC_EXPORT PictureLayer : public Layer {
@@ -39,7 +39,9 @@
 
   ContentLayerClient* client() { return client_; }
 
-  PicturePile* GetPicturePileForTesting() { return &pile_; }
+  RecordingSource* GetRecordingSourceForTesting() {
+    return recording_source_.get();
+  }
 
  protected:
   explicit PictureLayer(ContentLayerClient* client);
@@ -50,13 +52,13 @@
 
  private:
   ContentLayerClient* client_;
-  PicturePile pile_;
+  scoped_ptr<RecordingSource> recording_source_;
   devtools_instrumentation::
       ScopedLayerObjectTracker instrumentation_object_tracker_;
   // Invalidation to use the next time update is called.
   InvalidationRegion pending_invalidation_;
   // Invalidation from the last time update was called.
-  Region pile_invalidation_;
+  Region recording_invalidation_;
   gfx::Rect last_updated_visible_content_rect_;
 
   int update_source_frame_number_;
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index f9678cc..6d89140 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -71,7 +71,7 @@
 PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
     : LayerImpl(tree_impl, id),
       twin_layer_(nullptr),
-      pile_(PicturePileImpl::Create()),
+      raster_source_(PicturePileImpl::Create()),
       ideal_page_scale_(0.f),
       ideal_device_scale_(0.f),
       ideal_source_scale_(0.f),
@@ -122,9 +122,9 @@
   twin_layer_ = layer_impl;
   layer_impl->twin_layer_ = this;
 
-  layer_impl->UpdatePile(pile_);
+  layer_impl->UpdateRasterSource(raster_source_);
 
-  DCHECK(!pile_->is_solid_color() || !tilings_->num_tilings());
+  DCHECK(!raster_source_->IsSolidColor() || !tilings_->num_tilings());
   // Tilings would be expensive to push, so we swap.
   layer_impl->tilings_.swap(tilings_);
   layer_impl->tilings_->SetClient(layer_impl);
@@ -132,7 +132,7 @@
     tilings_->SetClient(this);
 
   // Ensure that the recycle tree doesn't have any unshared tiles.
-  if (tilings_ && pile_->is_solid_color())
+  if (tilings_ && raster_source_->IsSolidColor())
     tilings_->RemoveAllTilings();
 
   // Remove invalidated tiles from what will become a recycle tree.
@@ -158,9 +158,10 @@
   needs_push_properties_ = true;
 }
 
-void PictureLayerImpl::UpdatePile(scoped_refptr<PicturePileImpl> pile) {
+void PictureLayerImpl::UpdateRasterSource(
+    scoped_refptr<RasterSource> raster_source) {
   bool could_have_tilings = CanHaveTilings();
-  pile_.swap(pile);
+  raster_source_.swap(raster_source);
 
   // Need to call UpdateTiles again if CanHaveTilings changed.
   if (could_have_tilings != CanHaveTilings()) {
@@ -174,26 +175,24 @@
   DCHECK(!needs_post_commit_initialization_);
   // The bounds and the pile size may differ if the pile wasn't updated (ie.
   // PictureLayer::Update didn't happen). In that case the pile will be empty.
-  DCHECK_IMPLIES(!pile_->tiling_size().IsEmpty(),
-                 bounds() == pile_->tiling_size())
+  DCHECK_IMPLIES(!raster_source_->GetSize().IsEmpty(),
+                 bounds() == raster_source_->GetSize())
       << " bounds " << bounds().ToString() << " pile "
-      << pile_->tiling_size().ToString();
+      << raster_source_->GetSize().ToString();
 
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
 
-  if (pile_->is_solid_color()) {
+  if (raster_source_->IsSolidColor()) {
     PopulateSharedQuadState(shared_quad_state);
 
     AppendDebugBorderQuad(
         render_pass, bounds(), shared_quad_state, append_quads_data);
 
-    SolidColorLayerImpl::AppendSolidQuads(render_pass,
-                                          occlusion_in_content_space,
-                                          shared_quad_state,
-                                          visible_content_rect(),
-                                          pile_->solid_color(),
-                                          append_quads_data);
+    SolidColorLayerImpl::AppendSolidQuads(
+        render_pass, occlusion_in_content_space, shared_quad_state,
+        visible_content_rect(), raster_source_->GetSolidColor(),
+        append_quads_data);
     return;
   }
 
@@ -210,14 +209,11 @@
       occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
           scaled_draw_transform);
 
-  shared_quad_state->SetAll(scaled_draw_transform,
-                            scaled_content_bounds,
-                            scaled_visible_content_rect,
-                            draw_properties().clip_rect,
-                            draw_properties().is_clipped,
-                            draw_properties().opacity,
-                            blend_mode(),
-                            sorting_context_id_);
+  shared_quad_state->SetAll(
+      scaled_draw_transform, scaled_content_bounds, scaled_visible_content_rect,
+      draw_properties().clip_rect, draw_properties().is_clipped,
+      draw_properties().opacity, draw_properties().blend_mode,
+      sorting_context_id_);
 
   if (current_draw_mode_ == DRAW_MODE_RESOURCELESS_SOFTWARE) {
     AppendDebugBorderQuad(
@@ -241,16 +237,9 @@
 
     PictureDrawQuad* quad =
         render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-    quad->SetNew(shared_quad_state,
-                 geometry_rect,
-                 opaque_rect,
-                 visible_geometry_rect,
-                 texture_rect,
-                 texture_size,
-                 RGBA_8888,
-                 quad_content_rect,
-                 max_contents_scale,
-                 pile_);
+    quad->SetNew(shared_quad_state, geometry_rect, opaque_rect,
+                 visible_geometry_rect, texture_rect, texture_size, RGBA_8888,
+                 quad_content_rect, max_contents_scale, raster_source_);
     return;
   }
 
@@ -382,16 +371,10 @@
               resource_provider->memory_efficient_texture_format();
           PictureDrawQuad* quad =
               render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-          quad->SetNew(shared_quad_state,
-                       geometry_rect,
-                       opaque_rect,
-                       visible_geometry_rect,
-                       texture_rect,
-                       iter.texture_size(),
-                       format,
-                       iter->content_rect(),
-                       iter->contents_scale(),
-                       pile_);
+          quad->SetNew(shared_quad_state, geometry_rect, opaque_rect,
+                       visible_geometry_rect, texture_rect, iter.texture_size(),
+                       format, iter->content_rect(), iter->contents_scale(),
+                       raster_source_);
           has_draw_quad = true;
           break;
         }
@@ -506,7 +489,7 @@
       draw_properties().screen_space_transform_is_animating;
 
   if (draw_transform_is_animating())
-    pile_->set_likely_to_be_used_for_transform_animation();
+    raster_source_->SetShouldAttemptToUseDistanceFieldText();
 
   should_update_tile_priorities_ = true;
 
@@ -515,7 +498,7 @@
 
 void PictureLayerImpl::UpdateTilePriorities(
     const Occlusion& occlusion_in_content_space) {
-  DCHECK(!pile_->is_solid_color() || !tilings_->num_tilings());
+  DCHECK(!raster_source_->IsSolidColor() || !tilings_->num_tilings());
   double current_frame_time_in_seconds =
       (layer_tree_impl()->CurrentBeginFrameArgs().frame_time -
        base::TimeTicks()).InSecondsF();
@@ -607,7 +590,7 @@
 }
 
 void PictureLayerImpl::DidBeginTracing() {
-  pile_->DidBeginTracing();
+  raster_source_->DidBeginTracing();
 }
 
 void PictureLayerImpl::ReleaseResources() {
@@ -623,13 +606,13 @@
 }
 
 skia::RefPtr<SkPicture> PictureLayerImpl::GetPicture() {
-  return pile_->GetFlattenedPicture();
+  return raster_source_->GetFlattenedPicture();
 }
 
 scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling,
                                                const gfx::Rect& content_rect) {
-  DCHECK(!pile_->is_solid_color());
-  if (!pile_->CanRaster(tiling->contents_scale(), content_rect))
+  DCHECK(!raster_source_->IsSolidColor());
+  if (!raster_source_->CoversRect(content_rect, tiling->contents_scale()))
     return scoped_refptr<Tile>();
 
   int flags = 0;
@@ -640,21 +623,17 @@
   // memory savings that we can get. Note that we don't handle solid color
   // masks, so we shouldn't bother analyzing those.
   // Bugs: crbug.com/397198, crbug.com/396908
-  if (!pile_->is_mask())
+  if (!raster_source_->IsMask())
     flags = Tile::USE_PICTURE_ANALYSIS;
 
   return layer_tree_impl()->tile_manager()->CreateTile(
-      pile_.get(),
-      content_rect.size(),
-      content_rect,
-      tiling->contents_scale(),
-      id(),
-      layer_tree_impl()->source_frame_number(),
+      raster_source_.get(), content_rect.size(), content_rect,
+      tiling->contents_scale(), id(), layer_tree_impl()->source_frame_number(),
       flags);
 }
 
 RasterSource* PictureLayerImpl::GetRasterSource() {
-  return pile_.get();
+  return raster_source_.get();
 }
 
 const Region* PictureLayerImpl::GetPendingInvalidation() {
@@ -685,6 +664,12 @@
   return recycled_twin->tilings_->TilingAtScale(tiling->contents_scale());
 }
 
+TilePriority::PriorityBin PictureLayerImpl::GetMaxTilePriorityBin() const {
+  if (!HasValidTilePriorities())
+    return TilePriority::EVENTUALLY;
+  return TilePriority::NOW;
+}
+
 size_t PictureLayerImpl::GetMaxTilesForInterestArea() const {
   return layer_tree_impl()->settings().max_tiles_for_interest_area;
 }
@@ -714,7 +699,7 @@
   int max_texture_size =
       layer_tree_impl()->resource_provider()->max_texture_size();
 
-  if (pile_->is_mask()) {
+  if (raster_source_->IsMask()) {
     // Masks are not tiled, so if we can't cover the whole mask with one tile,
     // don't make any tiles at all. Returning an empty size signals this.
     if (content_bounds.width() > max_texture_size ||
@@ -803,10 +788,9 @@
 
   bool synced_high_res_tiling = false;
   if (CanHaveTilings()) {
-    synced_high_res_tiling = tilings_->SyncTilings(*other->tilings_,
-                                                   pile_->tiling_size(),
-                                                   invalidation_,
-                                                   MinimumContentsScale());
+    synced_high_res_tiling =
+        tilings_->SyncTilings(*other->tilings_, raster_source_->GetSize(),
+                              invalidation_, MinimumContentsScale());
   } else {
     RemoveAllTilings();
   }
@@ -830,7 +814,7 @@
     return;
   if (!CanHaveTilingWithScale(tiling->contents_scale()))
     return;
-  tilings_->AddTiling(tiling->contents_scale(), pile_->tiling_size());
+  tilings_->AddTiling(tiling->contents_scale(), raster_source_->GetSize());
 
   // If this tree needs update draw properties, then the tiling will
   // get updated prior to drawing or activation.  If this tree does not
@@ -849,7 +833,7 @@
 void PictureLayerImpl::GetContentsResourceId(
     ResourceProvider::ResourceId* resource_id,
     gfx::Size* resource_size) const {
-  DCHECK_EQ(bounds().ToString(), pile_->tiling_size().ToString());
+  DCHECK_EQ(bounds().ToString(), raster_source_->GetSize().ToString());
   gfx::Rect content_rect(bounds());
   PictureLayerTilingSet::CoverageIterator iter(
       tilings_.get(), 1.f, content_rect, ideal_contents_scale_);
@@ -899,9 +883,9 @@
       "contents_scale: " << contents_scale;
 
   PictureLayerTiling* tiling =
-      tilings_->AddTiling(contents_scale, pile_->tiling_size());
+      tilings_->AddTiling(contents_scale, raster_source_->GetSize());
 
-  DCHECK(pile_->HasRecordings());
+  DCHECK(raster_source_->HasRecordings());
 
   if (PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer())
     twin_layer->SyncTiling(tiling);
@@ -1100,7 +1084,7 @@
     float maximum_scale = draw_properties().maximum_animation_contents_scale;
     if (maximum_scale) {
       gfx::Size bounds_at_maximum_scale = gfx::ToCeiledSize(
-          gfx::ScaleSize(pile_->tiling_size(), maximum_scale));
+          gfx::ScaleSize(raster_source_->GetSize(), maximum_scale));
       if (bounds_at_maximum_scale.GetArea() <=
           layer_tree_impl()->device_viewport_size().GetArea())
         can_raster_at_maximum_scale = true;
@@ -1120,7 +1104,7 @@
   // If this layer would create zero or one tiles at this content scale,
   // don't create a low res tiling.
   gfx::Size raster_bounds = gfx::ToCeiledSize(
-      gfx::ScaleSize(pile_->tiling_size(), raster_contents_scale_));
+      gfx::ScaleSize(raster_source_->GetSize(), raster_contents_scale_));
   gfx::Size tile_size = CalculateTileSize(raster_bounds);
   bool tile_covers_bounds = tile_size.width() >= raster_bounds.width() &&
                             tile_size.height() >= raster_bounds.height();
@@ -1227,8 +1211,8 @@
   // then it will end up having less than one pixel of content in that
   // dimension.  Bump the minimum contents scale up in this case to prevent
   // this from happening.
-  int min_dimension =
-      std::min(pile_->tiling_size().width(), pile_->tiling_size().height());
+  int min_dimension = std::min(raster_source_->GetSize().width(),
+                               raster_source_->GetSize().height());
   if (!min_dimension)
     return setting_min;
 
@@ -1249,11 +1233,11 @@
 }
 
 bool PictureLayerImpl::CanHaveTilings() const {
-  if (pile_->is_solid_color())
+  if (raster_source_->IsSolidColor())
     return false;
   if (!DrawsContent())
     return false;
-  if (!pile_->HasRecordings())
+  if (!raster_source_->HasRecordings())
     return false;
   return true;
 }
@@ -1353,7 +1337,7 @@
   state->EndArray();
 
   state->BeginArray("pictures");
-  pile_->AsValueInto(state);
+  raster_source_->AsValueInto(state);
   state->EndArray();
 
   state->BeginArray("invalidation");
@@ -1362,12 +1346,9 @@
 
   state->BeginArray("coverage_tiles");
   for (PictureLayerTilingSet::CoverageIterator iter(
-           tilings_.get(),
-           1.f,
-           gfx::Rect(pile_->tiling_size()),
+           tilings_.get(), 1.f, gfx::Rect(raster_source_->GetSize()),
            ideal_contents_scale_);
-       iter;
-       ++iter) {
+       iter; ++iter) {
     state->BeginDictionary();
 
     state->BeginArray("geometry_rect");
@@ -1403,10 +1384,8 @@
   return IsOnActiveOrPendingTree() && IsDrawnRenderSurfaceLayerListMember();
 }
 
-bool PictureLayerImpl::AllTilesRequiredForActivationAreReadyToDraw() const {
-  if (!layer_tree_impl()->IsPendingTree())
-    return true;
-
+bool PictureLayerImpl::AllTilesRequiredAreReadyToDraw(
+    TileRequirementCheck is_tile_required_callback) const {
   if (!HasValidTilePriorities())
     return true;
 
@@ -1438,11 +1417,9 @@
       // be out of date. It is updated in the raster/eviction iterators.
       // TODO(vmpstr): Remove the comment once you can't access this information
       // from the tile.
-      if (tiling->IsTileRequiredForActivation(tile) && !tile->IsReadyToDraw()) {
-        TRACE_EVENT_INSTANT0("cc",
-                             "PictureLayerImpl::"
-                             "AllTilesRequiredForActivationAreReadyToDraw not "
-                             "ready to activate",
+      if ((tiling->*is_tile_required_callback)(tile) &&
+          !tile->IsReadyToDraw()) {
+        TRACE_EVENT_INSTANT0("cc", "Tile required, but not ready to draw.",
                              TRACE_EVENT_SCOPE_THREAD);
         return false;
       }
@@ -1452,6 +1429,22 @@
   return true;
 }
 
+bool PictureLayerImpl::AllTilesRequiredForActivationAreReadyToDraw() const {
+  if (!layer_tree_impl()->IsPendingTree())
+    return true;
+
+  return AllTilesRequiredAreReadyToDraw(
+      &PictureLayerTiling::IsTileRequiredForActivationIfVisible);
+}
+
+bool PictureLayerImpl::AllTilesRequiredForDrawAreReadyToDraw() const {
+  if (!layer_tree_impl()->IsActiveTree())
+    return true;
+
+  return AllTilesRequiredAreReadyToDraw(
+      &PictureLayerTiling::IsTileRequiredForDrawIfVisible);
+}
+
 PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator()
     : layer_(nullptr), current_stage_(arraysize(stages_)) {
 }
@@ -1586,11 +1579,12 @@
       tree_priority_(tree_priority),
       current_category_(PictureLayerTiling::EVENTUALLY),
       current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
-      current_tiling_(CurrentTilingRange().start - 1u) {
-  // TODO(vmpstr): Once tile priorities are determined by the iterators, ensure
-  // that layers that don't have valid tile priorities have lowest priorities so
-  // they evict their tiles first (crbug.com/381704)
-  DCHECK(layer_->tilings_);
+      current_tiling_(0u) {
+  // Early out if the layer has no tilings.
+  if (!layer_->tilings_ || !layer_->tilings_->num_tilings())
+    return;
+
+  current_tiling_ = CurrentTilingRange().start - 1u;
   do {
     if (!AdvanceToNextTiling())
       break;
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 024e315..b341bde 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -126,6 +126,7 @@
       const PictureLayerTiling* tiling) const override;
   PictureLayerTiling* GetRecycledTwinTiling(
       const PictureLayerTiling* tiling) override;
+  TilePriority::PriorityBin GetMaxTilePriorityBin() const override;
   size_t GetMaxTilesForInterestArea() const override;
   float GetSkewportTargetTimeInSeconds() const override;
   int GetSkewportExtrapolationLimitInContentPixels() const override;
@@ -149,9 +150,11 @@
   // Virtual for testing.
   virtual bool HasValidTilePriorities() const;
   bool AllTilesRequiredForActivationAreReadyToDraw() const;
+  bool AllTilesRequiredForDrawAreReadyToDraw() const;
 
  protected:
   friend class LayerRasterTileIterator;
+  using TileRequirementCheck = bool (PictureLayerTiling::*)(const Tile*) const;
 
   PictureLayerImpl(LayerTreeImpl* tree_impl, int id);
   PictureLayerTiling* AddTiling(float contents_scale);
@@ -169,7 +172,7 @@
   void ResetRasterScale();
   gfx::Rect GetViewportForTilePriorityInContentSpace() const;
   PictureLayerImpl* GetRecycledTwinLayer() const;
-  void UpdatePile(scoped_refptr<PicturePileImpl> pile);
+  void UpdateRasterSource(scoped_refptr<RasterSource> raster_source);
 
   void DoPostCommitInitializationIfNeeded() {
     if (needs_post_commit_initialization_)
@@ -180,6 +183,11 @@
   bool CanHaveTilings() const;
   bool CanHaveTilingWithScale(float contents_scale) const;
   void SanityCheckTilingState() const;
+  // Checks if all tiles required for a certain action (e.g. activation) are
+  // ready to draw.  is_tile_required_callback gets called on all candidate
+  // tiles and returns true if the tile is required for the action.
+  bool AllTilesRequiredAreReadyToDraw(
+      TileRequirementCheck is_tile_required_callback) const;
 
   bool ShouldAdjustRasterScaleDuringScaleAnimations() const;
 
@@ -193,7 +201,7 @@
   PictureLayerImpl* twin_layer_;
 
   scoped_ptr<PictureLayerTilingSet> tilings_;
-  scoped_refptr<PicturePileImpl> pile_;
+  scoped_refptr<RasterSource> raster_source_;
   Region invalidation_;
 
   float ideal_page_scale_;
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc
index aeea2bb..7f1ce85 100644
--- a/cc/layers/picture_layer_impl_perftest.cc
+++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -58,7 +58,7 @@
     pending_tree->DetachLayerTree();
 
     scoped_ptr<FakePictureLayerImpl> pending_layer =
-        FakePictureLayerImpl::CreateWithPile(pending_tree, 7, pile);
+        FakePictureLayerImpl::CreateWithRasterSource(pending_tree, 7, pile);
     pending_layer->SetDrawsContent(true);
     pending_tree->SetRootLayer(pending_layer.Pass());
 
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index a46386c..a75feb0 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -134,7 +134,7 @@
       pending_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
   }
 
-  void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
+  void SetupPendingTree(scoped_refptr<RasterSource> raster_source) {
     host_impl_.CreatePendingTree();
     host_impl_.pending_tree()->SetPageScaleFactorAndLimits(1.f, 0.25f, 100.f);
     LayerTreeImpl* pending_tree = host_impl_.pending_tree();
@@ -147,14 +147,14 @@
     if (old_pending_root) {
       pending_layer.reset(
           static_cast<FakePictureLayerImpl*>(old_pending_root.release()));
-      pending_layer->SetPile(pile);
+      pending_layer->SetRasterSource(raster_source);
     } else {
-      pending_layer =
-          FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
+      pending_layer = FakePictureLayerImpl::CreateWithRasterSource(
+          pending_tree, id_, raster_source);
       pending_layer->SetDrawsContent(true);
     }
     // The bounds() just mirror the pile size.
-    pending_layer->SetBounds(pending_layer->pile()->tiling_size());
+    pending_layer->SetBounds(pending_layer->raster_source()->GetSize());
     pending_tree->SetRootLayer(pending_layer.Pass());
 
     pending_layer_ = static_cast<FakePictureLayerImpl*>(
@@ -268,8 +268,8 @@
     std::vector<SkRect>::const_iterator rect_iter = rects.begin();
     for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
       MockCanvas mock_canvas(1000, 1000);
-      active_pile->RasterDirect(&mock_canvas, (*tile_iter)->content_rect(),
-                                1.0f);
+      active_pile->PlaybackToSharedCanvas(&mock_canvas,
+                                          (*tile_iter)->content_rect(), 1.0f);
 
       // This test verifies that when drawing the contents of a specific tile
       // at content scale 1.0, the playback canvas never receives content from
@@ -658,10 +658,10 @@
          ++iter) {
       EXPECT_FALSE(iter.full_tile_geometry_rect().IsEmpty());
       // Ensure there is a recording for this tile.
-      bool in_pending = pending_pile->CanRaster(tiling->contents_scale(),
-                                                iter.full_tile_geometry_rect());
-      bool in_active = active_pile->CanRaster(tiling->contents_scale(),
-                                              iter.full_tile_geometry_rect());
+      bool in_pending = pending_pile->CoversRect(iter.full_tile_geometry_rect(),
+                                                 tiling->contents_scale());
+      bool in_active = active_pile->CoversRect(iter.full_tile_geometry_rect(),
+                                               tiling->contents_scale());
 
       if (in_pending && !in_active)
         EXPECT_EQ(pending_pile.get(), iter->raster_source());
@@ -1132,8 +1132,15 @@
 }
 
 TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
-  gfx::Size tile_size(host_impl_.settings().default_tile_size);
-  SetupDefaultTrees(tile_size);
+  gfx::Size layer_bounds(host_impl_.settings().default_tile_size);
+  gfx::Size tile_size(100, 100);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  SetupTrees(pending_pile, active_pile);
 
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
   float device_scale = 1.f;
@@ -1181,8 +1188,8 @@
   ResetTilingsAndRasterScales();
 
   // Mask layers dont create low res since they always fit on one tile.
-  pending_layer_->pile()->set_is_mask(true);
-  active_layer_->pile()->set_is_mask(true);
+  pending_pile->SetIsMask(true);
+  active_pile->SetIsMask(true);
   SetContentsScaleOnBothLayers(contents_scale,
                                device_scale,
                                page_scale,
@@ -1197,7 +1204,7 @@
 
   scoped_refptr<FakePicturePileImpl> valid_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
-  valid_pile->set_is_mask(true);
+  valid_pile->SetIsMask(true);
   SetupPendingTree(valid_pile);
 
   SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
@@ -1224,7 +1231,7 @@
   scoped_refptr<FakePicturePileImpl> huge_pile =
       FakePicturePileImpl::CreateFilledPile(
           tile_size, gfx::Size(max_texture_size + 1, 10));
-  huge_pile->set_is_mask(true);
+  huge_pile->SetIsMask(true);
   SetupPendingTree(huge_pile);
 
   SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
@@ -1249,7 +1256,7 @@
 
   scoped_refptr<FakePicturePileImpl> valid_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
-  valid_pile->set_is_mask(true);
+  valid_pile->SetIsMask(true);
   SetupPendingTree(valid_pile);
 
   float ideal_contents_scale = 1.3f;
@@ -1499,7 +1506,7 @@
   EXPECT_EQ(0.f, active_layer_->ideal_contents_scale());
 
   // Push non-solid-color pending pile makes active layer can have tilings.
-  active_layer_->UpdatePile(pending_pile);
+  active_layer_->UpdateRasterSource(pending_pile);
   ASSERT_TRUE(active_layer_->CanHaveTilings());
 
   // Update properties with non-solid color pile should allow tilings.
@@ -2044,7 +2051,8 @@
   LayerTreeImpl* pending_tree = host_impl_.pending_tree();
 
   scoped_ptr<FakePictureLayerImpl> pending_layer =
-      FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pending_pile);
+      FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_,
+                                                   pending_pile);
   pending_layer->SetDrawsContent(true);
   pending_tree->SetRootLayer(pending_layer.Pass());
 
@@ -3708,9 +3716,10 @@
 
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, bounds);
-  pending_pile->set_is_mask(true);
-  scoped_ptr<FakePictureLayerImpl> mask = FakePictureLayerImpl::CreateWithPile(
-      host_impl_.pending_tree(), 3, pending_pile);
+  pending_pile->SetIsMask(true);
+  scoped_ptr<FakePictureLayerImpl> mask =
+      FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 3,
+                                                   pending_pile);
 
   mask->SetBounds(bounds);
   mask->SetContentBounds(bounds);
@@ -4485,31 +4494,23 @@
   FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&host_client);
   host->SetRootLayer(layer);
-  PicturePile* pile = layer->GetPicturePileForTesting();
+  RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
 
   host_impl_.SetViewportSize(layer_bounds);
 
   int frame_number = 0;
-  FakeRenderingStatsInstrumentation stats_instrumentation;
 
   client.set_fill_with_nonsolid_color(!test_for_solid);
 
   Region invalidation(layer_rect);
-  pile->UpdateAndExpandInvalidation(&client,
-                                    &invalidation,
-                                    SK_ColorWHITE,
-                                    false,
-                                    false,
-                                    layer_bounds,
-                                    layer_rect,
-                                    frame_number++,
-                                    Picture::RECORD_NORMALLY,
-                                    &stats_instrumentation);
+  recording_source->UpdateAndExpandInvalidation(
+      &client, &invalidation, SK_ColorWHITE, false, false, layer_bounds,
+      layer_rect, frame_number++, Picture::RECORD_NORMALLY);
 
-  scoped_refptr<PicturePileImpl> pending_pile =
-      PicturePileImpl::CreateFromOther(pile);
+  scoped_refptr<RasterSource> pending_raster_source =
+      recording_source->CreateRasterSource();
 
-  SetupPendingTree(pending_pile);
+  SetupPendingTree(pending_raster_source);
   ActivateTree();
 
   active_layer_->set_fixed_tile_size(tile_size);
@@ -4560,31 +4561,23 @@
   FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&host_client);
   host->SetRootLayer(layer);
-  PicturePile* pile = layer->GetPicturePileForTesting();
+  RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
 
   host_impl_.SetViewportSize(layer_bounds);
 
   int frame_number = 0;
-  FakeRenderingStatsInstrumentation stats_instrumentation;
 
   client.set_fill_with_nonsolid_color(true);
 
   Region invalidation1(layer_rect);
-  pile->UpdateAndExpandInvalidation(&client,
-                                    &invalidation1,
-                                    SK_ColorWHITE,
-                                    false,
-                                    false,
-                                    layer_bounds,
-                                    layer_rect,
-                                    frame_number++,
-                                    Picture::RECORD_NORMALLY,
-                                    &stats_instrumentation);
+  recording_source->UpdateAndExpandInvalidation(
+      &client, &invalidation1, SK_ColorWHITE, false, false, layer_bounds,
+      layer_rect, frame_number++, Picture::RECORD_NORMALLY);
 
-  scoped_refptr<PicturePileImpl> pending_pile1 =
-      PicturePileImpl::CreateFromOther(pile);
+  scoped_refptr<RasterSource> raster_source1 =
+      recording_source->CreateRasterSource();
 
-  SetupPendingTree(pending_pile1);
+  SetupPendingTree(raster_source1);
   ActivateTree();
   host_impl_.active_tree()->UpdateDrawProperties();
 
@@ -4595,21 +4588,14 @@
   client.set_fill_with_nonsolid_color(false);
 
   Region invalidation2(layer_rect);
-  pile->UpdateAndExpandInvalidation(&client,
-                                    &invalidation2,
-                                    SK_ColorWHITE,
-                                    false,
-                                    false,
-                                    layer_bounds,
-                                    layer_rect,
-                                    frame_number++,
-                                    Picture::RECORD_NORMALLY,
-                                    &stats_instrumentation);
+  recording_source->UpdateAndExpandInvalidation(
+      &client, &invalidation2, SK_ColorWHITE, false, false, layer_bounds,
+      layer_rect, frame_number++, Picture::RECORD_NORMALLY);
 
-  scoped_refptr<PicturePileImpl> pending_pile2 =
-      PicturePileImpl::CreateFromOther(pile);
+  scoped_refptr<RasterSource> raster_source2 =
+      recording_source->CreateRasterSource();
 
-  SetupPendingTree(pending_pile2);
+  SetupPendingTree(raster_source2);
   ActivateTree();
 
   // We've switched to a solid color, so we should end up with no tilings.
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
index ca622aa..7873b48 100644
--- a/cc/layers/picture_layer_unittest.cc
+++ b/cc/layers/picture_layer_unittest.cc
@@ -66,23 +66,23 @@
     layer->PushPropertiesTo(layer_impl.get());
     EXPECT_FALSE(layer_impl->CanHaveTilings());
     EXPECT_TRUE(layer_impl->bounds() == gfx::Size(0, 0));
-    EXPECT_EQ(gfx::Size(), layer_impl->pile()->tiling_size());
-    EXPECT_FALSE(layer_impl->pile()->HasRecordings());
+    EXPECT_EQ(gfx::Size(), layer_impl->raster_source()->GetSize());
+    EXPECT_FALSE(layer_impl->raster_source()->HasRecordings());
   }
 }
 
 TEST(PictureLayerTest, SuitableForGpuRasterization) {
   MockContentLayerClient client;
   scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
-  PicturePile* pile = layer->GetPicturePileForTesting();
+  RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
 
   // Layer is suitable for gpu rasterization by default.
-  EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+  EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
   EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
 
   // Veto gpu rasterization.
-  pile->SetUnsuitableForGpuRasterizationForTesting();
-  EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+  recording_source->SetUnsuitableForGpuRasterizationForTesting();
+  EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization());
   EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
 }
 
@@ -99,7 +99,7 @@
 
   // Tile-grid is set according to its setting.
   SkTileGridFactory::TileGridInfo info =
-      layer->GetPicturePileForTesting()->GetTileGridInfoForTesting();
+      layer->GetRecordingSourceForTesting()->GetTileGridInfoForTesting();
   EXPECT_EQ(info.fTileInterval.width(), 123 - 2 * info.fMargin.width());
   EXPECT_EQ(info.fTileInterval.height(), 123 - 2 * info.fMargin.height());
 }
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc
index 68398fe..8175efa 100644
--- a/cc/layers/render_surface_unittest.cc
+++ b/cc/layers/render_surface_unittest.cc
@@ -92,6 +92,9 @@
   owning_layer->CreateRenderSurface();
   ASSERT_TRUE(owning_layer->render_surface());
   owning_layer->draw_properties().render_target = owning_layer.get();
+
+  SkXfermode::Mode blend_mode = SkXfermode::kSoftLight_Mode;
+  owning_layer->SetBlendMode(blend_mode);
   RenderSurfaceImpl* render_surface = owning_layer->render_surface();
 
   root_layer->AddChild(owning_layer.Pass());
@@ -131,6 +134,7 @@
   EXPECT_RECT_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);
 }
 
 class TestRenderPassSink : public RenderPassSink {
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index 25fa708..8a998f3 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -632,7 +632,9 @@
         next_id_(1),
         total_ui_resource_created_(0),
         total_ui_resource_deleted_(0) {
-    InitializeSingleThreaded(client, base::MessageLoopProxy::current());
+    InitializeSingleThreaded(client,
+                             base::MessageLoopProxy::current(),
+                             nullptr);
   }
 
   UIResourceId CreateUIResource(UIResourceClient* content) override {
diff --git a/cc/layers/solid_color_layer_impl_unittest.cc b/cc/layers/solid_color_layer_impl_unittest.cc
index 768fae4..320345f 100644
--- a/cc/layers/solid_color_layer_impl_unittest.cc
+++ b/cc/layers/solid_color_layer_impl_unittest.cc
@@ -102,6 +102,31 @@
                 ->opacity());
 }
 
+TEST(SolidColorLayerImplTest, VerifyCorrectBlendModeInQuad) {
+  const SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode;
+
+  scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+
+  gfx::Size layer_size = gfx::Size(100, 100);
+  gfx::Rect visible_content_rect = gfx::Rect(layer_size);
+
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+  scoped_ptr<SolidColorLayerImpl> layer =
+      SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
+  layer->SetBounds(layer_size);
+  layer->SetContentBounds(layer_size);
+  layer->draw_properties().blend_mode = blend_mode;
+
+  AppendQuadsData data;
+  layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+
+  ASSERT_EQ(render_pass->quad_list.size(), 1U);
+  EXPECT_EQ(blend_mode,
+            render_pass->quad_list.front()->shared_quad_state->blend_mode);
+}
+
 TEST(SolidColorLayerImplTest, VerifyOpaqueRect) {
   gfx::Size layer_size = gfx::Size(100, 100);
   gfx::Rect visible_content_rect = gfx::Rect(layer_size);
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc
index f1909b4..ab6289e 100644
--- a/cc/layers/surface_layer.cc
+++ b/cc/layers/surface_layer.cc
@@ -44,6 +44,7 @@
 SurfaceLayer::SurfaceLayer(const SatisfyCallback& satisfy_callback,
                            const RequireCallback& require_callback)
     : Layer(),
+      surface_scale_(1.f),
       satisfy_callback_(satisfy_callback),
       require_callback_(require_callback) {
 }
@@ -53,9 +54,13 @@
   DCHECK(destroy_sequence_.is_null());
 }
 
-void SurfaceLayer::SetSurfaceId(SurfaceId surface_id) {
+void SurfaceLayer::SetSurfaceId(SurfaceId surface_id,
+                                float scale,
+                                const gfx::Size& size) {
   SatisfyDestroySequence();
   surface_id_ = surface_id;
+  surface_size_ = size;
+  surface_scale_ = scale;
   CreateNewDestroySequence();
 
   UpdateDrawsContent(HasDrawableContent());
@@ -88,6 +93,15 @@
   layer_impl->SetSurfaceId(surface_id_);
 }
 
+void SurfaceLayer::CalculateContentsScale(float ideal_contents_scale,
+                                          float* contents_scale_x,
+                                          float* contents_scale_y,
+                                          gfx::Size* content_bounds) {
+  *content_bounds = surface_size_;
+  *contents_scale_x = surface_scale_;
+  *contents_scale_y = surface_scale_;
+}
+
 void SurfaceLayer::CreateNewDestroySequence() {
   DCHECK(destroy_sequence_.is_null());
   if (layer_tree_host()) {
diff --git a/cc/layers/surface_layer.h b/cc/layers/surface_layer.h
index 4292549..9b73589 100644
--- a/cc/layers/surface_layer.h
+++ b/cc/layers/surface_layer.h
@@ -9,6 +9,7 @@
 #include "cc/layers/layer.h"
 #include "cc/surfaces/surface_id.h"
 #include "cc/surfaces/surface_sequence.h"
+#include "ui/gfx/size.h"
 
 namespace cc {
 
@@ -29,12 +30,16 @@
       const SatisfyCallback& satisfy_callback,
       const RequireCallback& require_callback);
 
-  void SetSurfaceId(SurfaceId surface_id);
+  void SetSurfaceId(SurfaceId surface_id, float scale, const gfx::Size& size);
 
   // Layer overrides.
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
   void SetLayerTreeHost(LayerTreeHost* host) override;
   void PushPropertiesTo(LayerImpl* layer) override;
+  void CalculateContentsScale(float ideal_contents_scale,
+                              float* contents_scale_x,
+                              float* contents_scale_y,
+                              gfx::Size* content_bounds) override;
 
  protected:
   SurfaceLayer(const SatisfyCallback& satisfy_callback,
@@ -47,6 +52,8 @@
   void SatisfyDestroySequence();
 
   SurfaceId surface_id_;
+  gfx::Size surface_size_;
+  float surface_scale_;
   SurfaceSequence destroy_sequence_;
   SatisfyCallback satisfy_callback_;
   RequireCallback require_callback_;
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc
index 99d0e17..73415c0 100644
--- a/cc/layers/surface_layer_unittest.cc
+++ b/cc/layers/surface_layer_unittest.cc
@@ -65,7 +65,7 @@
   scoped_refptr<SurfaceLayer> layer(SurfaceLayer::Create(
       base::Bind(&SatisfyCallback, &blank_change),
       base::Bind(&RequireCallback, &required_id, &required_seq)));
-  layer->SetSurfaceId(SurfaceId(1));
+  layer->SetSurfaceId(SurfaceId(1), 1.f, gfx::Size(1, 1));
   layer_tree_host_->set_surface_id_namespace(1);
   layer_tree_host_->SetRootLayer(layer);
 
@@ -74,7 +74,7 @@
   scoped_refptr<SurfaceLayer> layer2(SurfaceLayer::Create(
       base::Bind(&SatisfyCallback, &blank_change),
       base::Bind(&RequireCallback, &required_id, &required_seq)));
-  layer2->SetSurfaceId(SurfaceId(1));
+  layer2->SetSurfaceId(SurfaceId(1), 1.f, gfx::Size(1, 1));
   layer_tree_host2->set_surface_id_namespace(2);
   layer_tree_host2->SetRootLayer(layer2);
 
@@ -110,6 +110,36 @@
   EXPECT_EQ(2u, required_seq.size());
 }
 
+static void CalcDrawProps(FakeLayerTreeHost* host, float device_scale_factor) {
+  RenderSurfaceLayerList render_surface_layer_list;
+  LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+      host->root_layer(), gfx::Size(500, 500), &render_surface_layer_list);
+  inputs.device_scale_factor = device_scale_factor;
+  LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+}
+
+// Check that setting content scale on the surface works.
+TEST_F(SurfaceLayerTest, ScaleSurface) {
+  SurfaceSequence blank_change;
+  SurfaceId required_id;
+  std::set<SurfaceSequence> required_seq;
+  scoped_refptr<SurfaceLayer> layer(SurfaceLayer::Create(
+      base::Bind(&SatisfyCallback, &blank_change),
+      base::Bind(&RequireCallback, &required_id, &required_seq)));
+  gfx::Size surface_size(10, 15);
+  layer->SetSurfaceId(SurfaceId(1), 2.f, surface_size);
+  layer->SetBounds(gfx::Size(25, 45));
+  layer_tree_host_->SetRootLayer(layer);
+
+  CalcDrawProps(layer_tree_host_.get(), 5.f);
+  EXPECT_EQ(2.f, layer->contents_scale_x());
+  EXPECT_EQ(2.f, layer->contents_scale_y());
+  EXPECT_EQ(surface_size.ToString(), layer->content_bounds().ToString());
+
+  layer_tree_host_->SetRootLayer(nullptr);
+  layer_tree_host_.reset();
+}
+
 // Check that SurfaceSequence is sent through swap promise.
 class SurfaceLayerSwapPromise : public LayerTreeTest {
  public:
@@ -121,7 +151,7 @@
     layer_ = SurfaceLayer::Create(
         base::Bind(&SatisfyCallback, &satisfied_sequence_),
         base::Bind(&RequireCallback, &required_id_, &required_set_));
-    layer_->SetSurfaceId(SurfaceId(1));
+    layer_->SetSurfaceId(SurfaceId(1), 1.f, gfx::Size(1, 1));
 
     // Layer hasn't been added to tree so no SurfaceSequence generated yet.
     EXPECT_EQ(0u, required_set_.size());
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index d355b62..f2ee269 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -52,7 +52,9 @@
  public:
   explicit MockLayerTreeHost(FakeLayerTreeHostClient* client)
       : LayerTreeHost(client, nullptr, nullptr, LayerTreeSettings()) {
-    InitializeSingleThreaded(client, base::MessageLoopProxy::current());
+    InitializeSingleThreaded(client,
+                             base::MessageLoopProxy::current(),
+                             nullptr);
   }
 
   MOCK_METHOD0(SetNeedsCommit, void());
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index 9c814be..7433a14 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -82,7 +82,8 @@
       : LayerTreeHost(client, manager, NULL, settings),
         output_surface_created_(false) {
     LayerTreeHost::InitializeThreaded(base::MessageLoopProxy::current(),
-                                      impl_task_runner);
+                                      impl_task_runner,
+                                      nullptr);
   }
 
   bool output_surface_created_;
@@ -1663,8 +1664,7 @@
       : FakeTiledLayer(manager) {
     scoped_ptr<TrackingLayerPainter> painter(TrackingLayerPainter::Create());
     tracking_layer_painter_ = painter.get();
-    layer_updater_ = BitmapContentLayerUpdater::Create(
-        painter.Pass(), &stats_instrumentation_, 0);
+    layer_updater_ = BitmapContentLayerUpdater::Create(painter.Pass(), 0);
   }
 
   TrackingLayerPainter* tracking_layer_painter() const {
@@ -1677,7 +1677,6 @@
 
   TrackingLayerPainter* tracking_layer_painter_;
   scoped_refptr<BitmapContentLayerUpdater> layer_updater_;
-  FakeRenderingStatsInstrumentation stats_instrumentation_;
 };
 
 TEST_F(TiledLayerTest, NonIntegerContentsScaleIsNotDistortedDuringPaint) {
diff --git a/cc/layers/ui_resource_layer_unittest.cc b/cc/layers/ui_resource_layer_unittest.cc
index 784ff35..09d57a9 100644
--- a/cc/layers/ui_resource_layer_unittest.cc
+++ b/cc/layers/ui_resource_layer_unittest.cc
@@ -36,7 +36,9 @@
   virtual void SetUp() {
     layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_);
     layer_tree_host_->InitializeSingleThreaded(
-        &fake_client_, base::MessageLoopProxy::current());
+        &fake_client_,
+        base::MessageLoopProxy::current(),
+        nullptr);
   }
 
   virtual void TearDown() {
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc
index 8251a09..a7e1bde 100644
--- a/cc/layers/video_layer_impl.cc
+++ b/cc/layers/video_layer_impl.cc
@@ -159,14 +159,9 @@
 
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  shared_quad_state->SetAll(transform,
-                            rotated_size,
-                            visible_content_rect(),
-                            clip_rect(),
-                            is_clipped(),
-                            draw_opacity(),
-                            blend_mode(),
-                            sorting_context_id());
+  shared_quad_state->SetAll(transform, rotated_size, visible_content_rect(),
+                            clip_rect(), is_clipped(), draw_opacity(),
+                            draw_blend_mode(), sorting_context_id());
 
   AppendDebugBorderQuad(
       render_pass, rotated_size, shared_quad_state, append_quads_data);
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 4eb1324..cb6189e 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -98,6 +98,8 @@
   switch (mode) {
     case SkXfermode::kSrcOver_Mode:
       return BlendModeNormal;
+    case SkXfermode::kScreen_Mode:
+      return BlendModeScreen;
     case SkXfermode::kOverlay_Mode:
       return BlendModeOverlay;
     case SkXfermode::kDarken_Mode:
@@ -128,7 +130,7 @@
       return BlendModeLuminosity;
     default:
       NOTREACHED();
-      return BlendModeNormal;
+      return BlendModeNone;
   }
 }
 
@@ -865,99 +867,8 @@
   return background_with_filters;
 }
 
-scoped_ptr<ScopedResource>
-GLRenderer::ApplyInverseTransformForBackgroundFilters(
-    DrawingFrame* frame,
-    const RenderPassDrawQuad* quad,
-    const gfx::Transform& contents_device_transform,
-    skia::RefPtr<SkImage> filtered_device_background,
-    const gfx::Rect& backdrop_bounding_rect) {
-  // This method draws a background filter, which applies a filter to any pixels
-  // behind the quad and seen through its background.  The algorithm works as
-  // follows:
-  // 1. Read the pixels in the bounding box into a buffer.
-  // Moved to GLRenderer::GetBackdropBoundingBoxForRenderPassQuad().
-  // 2. Read the pixels in the bounding box into a buffer R.
-  // Moved to GLRenderer::GetBackdropTexture().
-  // 3. Apply the background filter to R, so that it is applied in the pixels'
-  // coordinate space. Moved to GLRenderer::ApplyBackgroundFilters().
-  // 4. Apply the quad's inverse transform to map the pixels in R into the
-  // quad's content space. This implicitly clips R by the content bounds of the
-  // quad since the destination texture has bounds matching the quad's content.
-  // 5. Draw the background texture for the contents using the same transform as
-  // used to draw the contents itself. This is done without blending to replace
-  // the current background pixels with the new filtered background.
-  // 6. Draw the contents of the quad over drop of the new background with
-  // blending, as per usual. The filtered background pixels will show through
-  // any non-opaque pixels in this draws.
-  //
-  // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
-
-  // TODO(danakj): When this algorithm changes, update
-  // LayerTreeHost::PrioritizeTextures() accordingly.
-
-  DCHECK(filtered_device_background);
-
-  GrTexture* texture = filtered_device_background->getTexture();
-
-  scoped_ptr<ScopedResource> background_texture =
-      ScopedResource::Create(resource_provider_);
-  background_texture->Allocate(
-      quad->rect.size(),
-      ResourceProvider::TextureHintImmutableFramebuffer,
-      RGBA_8888);
-
-  const RenderPass* target_render_pass = frame->current_render_pass;
-  bool using_background_texture =
-      UseScopedTexture(frame, background_texture.get(), quad->rect);
-
-  if (using_background_texture) {
-    // Copy the readback pixels from device to the background texture for the
-    // surface.
-
-    gfx::Transform contents_device_transform_inverse(
-        gfx::Transform::kSkipInitialization);
-    bool did_invert = contents_device_transform.GetInverse(
-        &contents_device_transform_inverse);
-    DCHECK(did_invert);
-    gfx::Transform device_to_framebuffer_transform;
-    QuadRectTransform(
-        &device_to_framebuffer_transform, gfx::Transform(), quad->rect);
-    device_to_framebuffer_transform.PreconcatTransform(
-        contents_device_transform_inverse);
-
-#ifndef NDEBUG
-    GLC(gl_, gl_->ClearColor(0, 0, 1, 1));
-    gl_->Clear(GL_COLOR_BUFFER_BIT);
-#endif
-
-    // The background_texture is oriented the same as the frame buffer.
-    // The transform we are copying with has a vertical flip, as well as
-    // the |device_to_framebuffer_transform|, which cancel each other out. So do
-    // not flip the contents in the shader to maintain orientation.
-    bool flip_vertically = false;
-
-    CopyTextureToFramebuffer(frame,
-                             texture->getTextureHandle(),
-                             backdrop_bounding_rect,
-                             device_to_framebuffer_transform,
-                             flip_vertically);
-  }
-
-  UseRenderPass(frame, target_render_pass);
-
-  if (!using_background_texture)
-    return nullptr;
-  return background_texture.Pass();
-}
-
 void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
                                     const RenderPassDrawQuad* quad) {
-  SkXfermode::Mode blend_mode = quad->shared_quad_state->blend_mode;
-  SetBlendEnabled(
-      CanApplyBlendModeUsingBlendFunc(blend_mode) &&
-      (quad->ShouldDrawWithBlending() || !IsDefaultBlendMode(blend_mode)));
-
   ScopedResource* contents_texture =
       render_pass_textures_.get(quad->render_pass_id);
   if (!contents_texture || !contents_texture->id())
@@ -983,62 +894,59 @@
     SetupQuadForAntialiasing(contents_device_transform, quad,
                              &surface_quad, edge);
 
-  bool need_background_texture = !CanApplyBlendModeUsingBlendFunc(blend_mode) ||
-                                 ShouldApplyBackgroundFilters(frame, quad);
+  SkXfermode::Mode blend_mode = quad->shared_quad_state->blend_mode;
+  bool use_shaders_for_blending =
+      !CanApplyBlendModeUsingBlendFunc(blend_mode) ||
+      ShouldApplyBackgroundFilters(frame, quad) ||
+      settings_->force_blending_with_shaders;
 
   scoped_ptr<ScopedResource> background_texture;
   skia::RefPtr<SkImage> background_image;
   gfx::Rect background_rect;
-  if (need_background_texture) {
+  if (use_shaders_for_blending) {
     // Compute a bounding box around the pixels that will be visible through
     // the quad.
     background_rect = GetBackdropBoundingBoxForRenderPassQuad(
         frame, quad, contents_device_transform, use_aa);
-  }
 
-  if (!background_rect.IsEmpty()) {
-    // The pixels from the filtered background should completely replace the
-    // current pixel values.
-    bool disable_blending = blend_enabled();
-    if (disable_blending)
-      SetBlendEnabled(false);
+    if (!background_rect.IsEmpty()) {
+      // The pixels from the filtered background should completely replace the
+      // current pixel values.
+      if (blend_enabled())
+        SetBlendEnabled(false);
 
-    // Read the pixels in the bounding box into a buffer R.
-    scoped_ptr<ScopedResource> scoped_background_texture =
-        GetBackdropTexture(background_rect);
+      // Read the pixels in the bounding box into a buffer R.
+      // This function allocates a texture, which should contribute to the
+      // amount of memory used by render surfaces:
+      // LayerTreeHost::CalculateMemoryForRenderSurfaces.
+      background_texture = GetBackdropTexture(background_rect);
 
-    skia::RefPtr<SkImage> background_with_filters;
-    if (ShouldApplyBackgroundFilters(frame, quad) &&
-        scoped_background_texture) {
-      // Apply the background filters to R, so that it is applied in the pixels'
-      // coordinate space.
-      background_with_filters =
-          ApplyBackgroundFilters(frame, quad, scoped_background_texture.get());
-    }
-
-    if (CanApplyBlendModeUsingBlendFunc(blend_mode) &&
-        background_with_filters) {
-      // The background with filters will be copied to the frame buffer.
-      // Apply the quad's inverse transform to map the pixels in R into the
-      // quad's content space. This implicitly clips R by the content bounds of
-      // the quad since the destination texture has bounds matching the quad's
-      // content.
-      background_texture = ApplyInverseTransformForBackgroundFilters(
-          frame, quad, contents_device_transform, background_with_filters,
-          background_rect);
-    } else if (!CanApplyBlendModeUsingBlendFunc(blend_mode)) {
-      if (background_with_filters) {
-        // The background with filters will be used as backdrop for blending.
-        background_image = background_with_filters;
-      } else {
-        background_texture = scoped_background_texture.Pass();
+      if (ShouldApplyBackgroundFilters(frame, quad) && background_texture) {
+        // Apply the background filters to R, so that it is applied in the
+        // pixels' coordinate space.
+        background_image =
+            ApplyBackgroundFilters(frame, quad, background_texture.get());
       }
     }
 
-    if (disable_blending)
-      SetBlendEnabled(true);
+    if (!background_texture) {
+      // Something went wrong with reading the backdrop.
+      DCHECK(!background_image);
+      use_shaders_for_blending = false;
+    } else if (background_image) {
+      background_texture.reset();
+    } else if (CanApplyBlendModeUsingBlendFunc(blend_mode) &&
+               ShouldApplyBackgroundFilters(frame, quad)) {
+      // Something went wrong with applying background filters to the backdrop.
+      use_shaders_for_blending = false;
+      background_texture.reset();
+    }
   }
 
+  SetBlendEnabled(
+      !use_shaders_for_blending &&
+      (quad->ShouldDrawWithBlending() || !IsDefaultBlendMode(blend_mode)));
+
   // TODO(senorblanco): Cache this value so that we don't have to do it for both
   // the surface and its replica.  Apply filters to the contents texture.
   skia::RefPtr<SkImage> filter_image;
@@ -1071,25 +979,6 @@
     }
   }
 
-  if (background_texture && ShouldApplyBackgroundFilters(frame, quad)) {
-    // Draw the background texture if it has some filters applied.
-    DCHECK(CanApplyBlendModeUsingBlendFunc(blend_mode));
-    DCHECK(background_texture->size() == quad->rect.size());
-    ResourceProvider::ScopedReadLockGL lock(resource_provider_,
-                                            background_texture->id());
-
-    // The background_texture is oriented the same as the frame buffer. The
-    // transform we are copying with has a vertical flip, so flip the contents
-    // in the shader to maintain orientation
-    bool flip_vertically = true;
-
-    CopyTextureToFramebuffer(frame,
-                             lock.texture_id(),
-                             quad->rect,
-                             quad->quadTransform(),
-                             flip_vertically);
-  }
-
   scoped_ptr<ResourceProvider::ScopedSamplerGL> mask_resource_lock;
   unsigned mask_texture_id = 0;
   SamplerType mask_sampler = SamplerTypeNA;
@@ -1100,9 +989,6 @@
     mask_sampler = SamplerTypeFromTextureTarget(mask_resource_lock->target());
   }
 
-  // TODO(danakj): use the background_texture and blend the background in with
-  // this draw instead of having a separate copy of the background texture.
-
   scoped_ptr<ResourceProvider::ScopedSamplerGL> contents_resource_lock;
   if (filter_image) {
     GrTexture* texture = filter_image->getTexture();
@@ -1116,7 +1002,7 @@
               contents_resource_lock->target());
   }
 
-  if (CanApplyBlendModeUsingBlendFunc(blend_mode)) {
+  if (!use_shaders_for_blending) {
     if (!use_blend_equation_advanced_coherent_ && use_blend_equation_advanced_)
       GLC(gl_, gl_->BlendBarrierKHR());
 
@@ -1143,10 +1029,10 @@
   int shader_backdrop_location = -1;
   int shader_backdrop_rect_location = -1;
 
-  BlendMode shader_blend_mode = ((background_texture || background_image) &&
-                                 !CanApplyBlendModeUsingBlendFunc(blend_mode))
+  DCHECK_EQ(background_texture || background_image, use_shaders_for_blending);
+  BlendMode shader_blend_mode = use_shaders_for_blending
                                     ? BlendModeFromSkXfermode(blend_mode)
-                                    : BlendModeNormal;
+                                    : BlendModeNone;
 
   if (use_aa && mask_texture_id && !use_color_matrix) {
     const RenderPassMaskProgramAA* program = GetRenderPassMaskProgramAA(
@@ -1423,7 +1309,7 @@
   if (filter_image)
     GLC(gl_, gl_->Flush());
 
-  if (CanApplyBlendModeUsingBlendFunc(blend_mode))
+  if (!use_shaders_for_blending)
     RestoreBlendFuncToDefault(blend_mode);
 }
 
@@ -2096,8 +1982,8 @@
   }
 
   SkCanvas canvas(on_demand_tile_raster_bitmap_);
-  quad->picture_pile->PlaybackToCanvas(&canvas, quad->content_rect,
-                                       quad->contents_scale);
+  quad->raster_source->PlaybackToCanvas(&canvas, quad->content_rect,
+                                        quad->contents_scale);
 
   uint8_t* bitmap_pixels = NULL;
   SkBitmap on_demand_tile_raster_bitmap_dest;
@@ -2451,43 +2337,6 @@
   GLC(gl_, gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0));
 }
 
-void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame* frame,
-                                          int texture_id,
-                                          const gfx::Rect& rect,
-                                          const gfx::Transform& draw_matrix,
-                                          bool flip_vertically) {
-  TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
-      gl_, &highp_threshold_cache_, highp_threshold_min_, rect.bottom_right());
-
-  const RenderPassProgram* program =
-      GetRenderPassProgram(tex_coord_precision, BlendModeNormal);
-  SetUseProgram(program->program());
-
-  GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
-
-  if (flip_vertically) {
-    GLC(gl_,
-        gl_->Uniform4f(program->vertex_shader().tex_transform_location(),
-                       0.f,
-                       1.f,
-                       1.f,
-                       -1.f));
-  } else {
-    GLC(gl_,
-        gl_->Uniform4f(program->vertex_shader().tex_transform_location(),
-                       0.f,
-                       0.f,
-                       1.f,
-                       1.f));
-  }
-
-  SetShaderOpacity(1.f, program->fragment_shader().alpha_location());
-  DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
-  GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, texture_id));
-  DrawQuadGeometry(
-      frame, draw_matrix, rect, program->vertex_shader().matrix_location());
-}
-
 void GLRenderer::Finish() {
   TRACE_EVENT0("cc", "GLRenderer::Finish");
   GLC(gl_, gl_->Finish());
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index 4930204..ecadebb 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -167,12 +167,6 @@
       DrawingFrame* frame,
       const RenderPassDrawQuad* quad,
       ScopedResource* background_texture);
-  scoped_ptr<ScopedResource> ApplyInverseTransformForBackgroundFilters(
-      DrawingFrame* frame,
-      const RenderPassDrawQuad* quad,
-      const gfx::Transform& contents_device_transform,
-      skia::RefPtr<SkImage> backdrop_bitmap,
-      const gfx::Rect& backdrop_bounding_rect);
 
   void DrawRenderPassQuad(DrawingFrame* frame, const RenderPassDrawQuad* quad);
   void DrawSolidColorQuad(const DrawingFrame* frame,
@@ -208,12 +202,6 @@
                         int matrix_location);
   void SetUseProgram(unsigned program);
 
-  void CopyTextureToFramebuffer(const DrawingFrame* frame,
-                                int texture_id,
-                                const gfx::Rect& rect,
-                                const gfx::Transform& draw_matrix,
-                                bool flip_vertically);
-
   bool UseScopedTexture(DrawingFrame* frame,
                         const ScopedResource* resource,
                         const gfx::Rect& viewport_rect);
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index dc68675..2af953e 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -57,8 +57,11 @@
 
 static inline SkXfermode::Mode BlendModeToSkXfermode(BlendMode blend_mode) {
   switch (blend_mode) {
+    case BlendModeNone:
     case BlendModeNormal:
       return SkXfermode::kSrcOver_Mode;
+    case BlendModeScreen:
+      return SkXfermode::kScreen_Mode;
     case BlendModeOverlay:
       return SkXfermode::kOverlay_Mode;
     case BlendModeDarken:
@@ -1421,6 +1424,7 @@
   for (int i = 0; i < NumBlendModes; ++i) {
     BlendMode blend_mode = static_cast<BlendMode>(i);
     SkXfermode::Mode xfer_mode = BlendModeToSkXfermode(blend_mode);
+    settings_.force_blending_with_shaders = (blend_mode != BlendModeNone);
     // RenderPassProgram
     render_passes_in_draw_order_.clear();
     child_pass = AddRenderPass(&render_passes_in_draw_order_,
@@ -1690,7 +1694,7 @@
 
   // If use_aa incorrectly ignores clipping, it will use the
   // RenderPassProgramAA shader instead of the RenderPassProgram.
-  TestRenderPassProgram(TexCoordPrecisionMedium, BlendModeNormal);
+  TestRenderPassProgram(TexCoordPrecisionMedium, BlendModeNone);
 }
 
 TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h
index 0a0d456..04bd4a3 100644
--- a/cc/output/output_surface.h
+++ b/cc/output/output_surface.h
@@ -125,11 +125,6 @@
   // processing should be stopped, or lowered in priority.
   virtual void UpdateSmoothnessTakesPriority(bool prefer_smoothness) {}
 
-  // Requests a BeginFrame notification from the output surface. The
-  // notification will be delivered by calling
-  // OutputSurfaceClient::BeginFrame until the callback is disabled.
-  virtual void SetNeedsBeginFrame(bool enable) {}
-
   bool HasClient() { return !!client_; }
 
   // Get the class capable of informing cc of hardware overlay capability.
diff --git a/cc/output/output_surface_client.h b/cc/output/output_surface_client.h
index 99b174b..60750b4 100644
--- a/cc/output/output_surface_client.h
+++ b/cc/output/output_surface_client.h
@@ -9,7 +9,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
 #include "cc/base/cc_export.h"
-#include "cc/output/begin_frame_args.h"
 #include "cc/output/context_provider.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -33,7 +32,6 @@
   virtual void CommitVSyncParameters(base::TimeTicks timebase,
                                      base::TimeDelta interval) = 0;
   virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) = 0;
-  virtual void BeginFrame(const BeginFrameArgs& args) = 0;
   virtual void DidSwapBuffers() = 0;
   virtual void DidSwapBuffersComplete() = 0;
   virtual void ReclaimResources(const CompositorFrameAck* ack) = 0;
diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc
index b1f4149..4336f07 100644
--- a/cc/output/output_surface_unittest.cc
+++ b/cc/output/output_surface_unittest.cc
@@ -49,10 +49,6 @@
     CommitVSyncParameters(timebase, interval);
   }
 
-  void BeginFrameForTesting() {
-    client_->BeginFrame(CreateExpiredBeginFrameArgsForTesting());
-  }
-
   void DidSwapBuffersForTesting() { client_->DidSwapBuffers(); }
 
   void OnSwapBuffersCompleteForTesting() { client_->DidSwapBuffersComplete(); }
diff --git a/cc/output/program_binding.h b/cc/output/program_binding.h
index 722c782..a10d0ab 100644
--- a/cc/output/program_binding.h
+++ b/cc/output/program_binding.h
@@ -59,7 +59,7 @@
   void Initialize(ContextProvider* context_provider,
                   TexCoordPrecision precision,
                   SamplerType sampler,
-                  BlendMode blend_mode = BlendModeNormal) {
+                  BlendMode blend_mode = BlendModeNone) {
     DCHECK(context_provider);
     DCHECK(!initialized_);
 
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index a0ce823..d112ed1 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -1418,14 +1418,9 @@
 
   blue_quad->SetNew(blue_shared_state,
                     viewport,  // Intentionally bigger than clip.
-                    gfx::Rect(),
-                    viewport,
-                    gfx::RectF(viewport),
-                    viewport.size(),
-                    texture_format,
-                    viewport,
-                    1.f,
-                    PicturePileImpl::CreateFromOther(blue_pile.get()));
+                    gfx::Rect(), viewport, gfx::RectF(viewport),
+                    viewport.size(), texture_format, viewport, 1.f,
+                    blue_pile.get());
 
   // One viewport-filling green quad.
   scoped_refptr<FakePicturePileImpl> green_pile =
@@ -1441,16 +1436,9 @@
 
   PictureDrawQuad* green_quad =
       pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-  green_quad->SetNew(green_shared_state,
-                     viewport,
-                     gfx::Rect(),
-                     viewport,
-                     gfx::RectF(0.f, 0.f, 1.f, 1.f),
-                     viewport.size(),
-                     texture_format,
-                     viewport,
-                     1.f,
-                     PicturePileImpl::CreateFromOther(green_pile.get()));
+  green_quad->SetNew(green_shared_state, viewport, gfx::Rect(), viewport,
+                     gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(),
+                     texture_format, viewport, 1.f, green_pile.get());
 
   RenderPassList pass_list;
   pass_list.push_back(pass.Pass());
@@ -1487,16 +1475,9 @@
 
   PictureDrawQuad* green_quad =
       pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-  green_quad->SetNew(green_shared_state,
-                     viewport,
-                     gfx::Rect(),
-                     viewport,
-                     gfx::RectF(0, 0, 1, 1),
-                     viewport.size(),
-                     texture_format,
-                     viewport,
-                     1.f,
-                     PicturePileImpl::CreateFromOther(green_pile.get()));
+  green_quad->SetNew(green_shared_state, viewport, gfx::Rect(), viewport,
+                     gfx::RectF(0, 0, 1, 1), viewport.size(), texture_format,
+                     viewport, 1.f, green_pile.get());
 
   // One viewport-filling white quad.
   scoped_refptr<FakePicturePileImpl> white_pile =
@@ -1512,16 +1493,9 @@
 
   PictureDrawQuad* white_quad =
       pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-  white_quad->SetNew(white_shared_state,
-                     viewport,
-                     gfx::Rect(),
-                     viewport,
-                     gfx::RectF(0, 0, 1, 1),
-                     viewport.size(),
-                     texture_format,
-                     viewport,
-                     1.f,
-                     PicturePileImpl::CreateFromOther(white_pile.get()));
+  white_quad->SetNew(white_shared_state, viewport, gfx::Rect(), viewport,
+                     gfx::RectF(0, 0, 1, 1), viewport.size(), texture_format,
+                     viewport, 1.f, white_pile.get());
 
   RenderPassList pass_list;
   pass_list.push_back(pass.Pass());
@@ -1586,16 +1560,9 @@
       content_to_target_transform, viewport, pass.get());
 
   PictureDrawQuad* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-  quad->SetNew(shared_state,
-               viewport,
-               gfx::Rect(),
-               viewport,
-               gfx::RectF(0, 0, 2, 2),
-               viewport.size(),
-               texture_format,
-               viewport,
-               1.f,
-               PicturePileImpl::CreateFromOther(pile.get()));
+  quad->SetNew(shared_state, viewport, gfx::Rect(), viewport,
+               gfx::RectF(0, 0, 2, 2), viewport.size(), texture_format,
+               viewport, 1.f, pile.get());
 
   RenderPassList pass_list;
   pass_list.push_back(pass.Pass());
@@ -1643,29 +1610,17 @@
 
   PictureDrawQuad* green_quad1 =
       pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-  green_quad1->SetNew(top_right_green_shared_quad_state,
-                      green_rect1,
-                      gfx::Rect(),
-                      green_rect1,
-                      gfx::RectF(green_rect1.size()),
-                      green_rect1.size(),
-                      texture_format,
-                      green_rect1,
-                      1.f,
-                      PicturePileImpl::CreateFromOther(green_pile.get()));
+  green_quad1->SetNew(top_right_green_shared_quad_state, green_rect1,
+                      gfx::Rect(), green_rect1, gfx::RectF(green_rect1.size()),
+                      green_rect1.size(), texture_format, green_rect1, 1.f,
+                      green_pile.get());
 
   PictureDrawQuad* green_quad2 =
       pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-  green_quad2->SetNew(top_right_green_shared_quad_state,
-                      green_rect2,
-                      gfx::Rect(),
-                      green_rect2,
-                      gfx::RectF(green_rect2.size()),
-                      green_rect2.size(),
-                      texture_format,
-                      green_rect2,
-                      1.f,
-                      PicturePileImpl::CreateFromOther(green_pile.get()));
+  green_quad2->SetNew(top_right_green_shared_quad_state, green_rect2,
+                      gfx::Rect(), green_rect2, gfx::RectF(green_rect2.size()),
+                      green_rect2.size(), texture_format, green_rect2, 1.f,
+                      green_pile.get());
 
   // Add a green clipped checkerboard in the bottom right to help test
   // interleaving picture quad content and solid color content.
@@ -1731,16 +1686,10 @@
       content_to_target_transform, quad_content_rect, pass.get());
 
   PictureDrawQuad* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-  blue_quad->SetNew(blue_shared_state,
-                    quad_content_rect,
-                    gfx::Rect(),
-                    quad_content_rect,
-                    gfx::RectF(quad_content_rect),
-                    content_union_rect.size(),
-                    texture_format,
-                    content_union_rect,
-                    contents_scale,
-                    PicturePileImpl::CreateFromOther(pile.get()));
+  blue_quad->SetNew(blue_shared_state, quad_content_rect, gfx::Rect(),
+                    quad_content_rect, gfx::RectF(quad_content_rect),
+                    content_union_rect.size(), texture_format,
+                    content_union_rect, contents_scale, pile.get());
 
   // Fill left half of viewport with green.
   gfx::Transform half_green_content_to_target_transform;
@@ -1943,16 +1892,9 @@
       blue_content_to_target_transform, viewport, pass.get());
 
   PictureDrawQuad* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
-  blue_quad->SetNew(blue_shared_state,
-                    viewport,
-                    gfx::Rect(),
-                    viewport,
-                    gfx::RectF(0.f, 0.f, 1.f, 1.f),
-                    viewport.size(),
-                    texture_format,
-                    viewport,
-                    1.f,
-                    PicturePileImpl::CreateFromOther(blue_pile.get()));
+  blue_quad->SetNew(blue_shared_state, viewport, gfx::Rect(), viewport,
+                    gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(),
+                    texture_format, viewport, 1.f, blue_pile.get());
 
   RenderPassList pass_list;
   pass_list.push_back(pass.Pass());
diff --git a/cc/output/shader.cc b/cc/output/shader.cc
index b962d4a..e22e446 100644
--- a/cc/output/shader.cc
+++ b/cc/output/shader.cc
@@ -669,9 +669,9 @@
 }
 
 #define BLEND_MODE_UNIFORMS "s_backdropTexture", "backdropRect"
-#define UNUSED_BLEND_MODE_UNIFORMS (is_default_blend_mode() ? 2 : 0)
+#define UNUSED_BLEND_MODE_UNIFORMS (!has_blend_mode() ? 2 : 0)
 #define BLEND_MODE_SET_LOCATIONS(X, POS)                   \
-  if (!is_default_blend_mode()) {                          \
+  if (has_blend_mode()) {                                  \
     DCHECK_LT(static_cast<size_t>(POS) + 1, arraysize(X)); \
     backdrop_location_ = locations[POS];                   \
     backdrop_rect_location_ = locations[POS + 1];          \
@@ -680,7 +680,7 @@
 FragmentTexBlendMode::FragmentTexBlendMode()
     : backdrop_location_(-1),
       backdrop_rect_location_(-1),
-      blend_mode_(BlendModeNormal) {
+      blend_mode_(BlendModeNone) {
 }
 
 std::string FragmentTexBlendMode::SetBlendModeFunctions(
@@ -688,7 +688,7 @@
   if (shader_string.find("ApplyBlendMode") == std::string::npos)
     return shader_string;
 
-  if (is_default_blend_mode()) {
+  if (!has_blend_mode()) {
     return "#define ApplyBlendMode(X) (X)\n" + shader_string;
   }
 
@@ -902,6 +902,10 @@
 
 std::string FragmentTexBlendMode::GetBlendFunctionBodyForRGB() const {
   switch (blend_mode_) {
+    case BlendModeNormal:
+      return "result.rgb = src.rgb + dst.rgb * (1.0 - src.a);";
+    case BlendModeScreen:
+      return "result.rgb = src.rgb + (1.0 - src.rgb) * dst.rgb;";
     case BlendModeLighten:
       return "result.rgb = max((1.0 - src.a) * dst.rgb + src.rgb,"
              "                 (1.0 - dst.a) * src.rgb + dst.rgb);";
@@ -963,11 +967,11 @@
              "                           srcDstAlpha.a,"
              "                           srcDstAlpha.rgb);"
              "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
-    default:
+    case BlendModeNone:
+    case NumBlendModes:
       NOTREACHED();
-      // simple alpha compositing
-      return "result.rgb = src.rgb * src.a + dst.rgb * dst.a * (1 - src.a)";
   }
+  return "result = vec4(1.0, 0.0, 0.0, 1.0);";
 }
 
 FragmentTexAlphaBinding::FragmentTexAlphaBinding()
diff --git a/cc/output/shader.h b/cc/output/shader.h
index 0384366..8c1f264 100644
--- a/cc/output/shader.h
+++ b/cc/output/shader.h
@@ -39,7 +39,9 @@
 };
 
 enum BlendMode {
+  BlendModeNone,
   BlendModeNormal,
+  BlendModeScreen,
   BlendModeOverlay,
   BlendModeDarken,
   BlendModeLighten,
@@ -305,7 +307,7 @@
 
   BlendMode blend_mode() const { return blend_mode_; }
   void set_blend_mode(BlendMode blend_mode) { blend_mode_ = blend_mode; }
-  bool is_default_blend_mode() const { return blend_mode_ == BlendModeNormal; }
+  bool has_blend_mode() const { return blend_mode_ != BlendModeNone; }
 
  protected:
   FragmentTexBlendMode();
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index 06f1851..442cd8d 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -350,8 +350,8 @@
   TRACE_EVENT0("cc",
                "SoftwareRenderer::DrawPictureQuad");
 
-  quad->picture_pile->RasterDirect(current_canvas_, quad->content_rect,
-                                   quad->contents_scale);
+  quad->raster_source->PlaybackToSharedCanvas(
+      current_canvas_, quad->content_rect, quad->contents_scale);
 
   current_canvas_->setDrawFilter(NULL);
 }
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc
index d3753ca..5755ea8 100644
--- a/cc/quads/draw_quad_unittest.cc
+++ b/cc/quads/draw_quad_unittest.cc
@@ -670,18 +670,12 @@
   ResourceFormat texture_format = RGBA_8888;
   gfx::Rect content_rect(30, 40, 20, 30);
   float contents_scale = 3.141592f;
-  scoped_refptr<PicturePileImpl> picture_pile = PicturePileImpl::Create();
+  scoped_refptr<RasterSource> raster_source = PicturePileImpl::Create();
   CREATE_SHARED_STATE();
 
-  CREATE_QUAD_8_NEW(PictureDrawQuad,
-                    opaque_rect,
-                    visible_rect,
-                    tex_coord_rect,
-                    texture_size,
-                    texture_format,
-                    content_rect,
-                    contents_scale,
-                    picture_pile);
+  CREATE_QUAD_8_NEW(PictureDrawQuad, opaque_rect, visible_rect, tex_coord_rect,
+                    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);
@@ -690,22 +684,18 @@
   EXPECT_EQ(texture_format, copy_quad->texture_format);
   EXPECT_RECT_EQ(content_rect, copy_quad->content_rect);
   EXPECT_EQ(contents_scale, copy_quad->contents_scale);
-  EXPECT_EQ(picture_pile, copy_quad->picture_pile);
+  EXPECT_EQ(raster_source, copy_quad->raster_source);
 
-  CREATE_QUAD_6_ALL(PictureDrawQuad,
-                    tex_coord_rect,
-                    texture_size,
-                    texture_format,
-                    content_rect,
-                    contents_scale,
-                    picture_pile);
+  CREATE_QUAD_6_ALL(PictureDrawQuad, tex_coord_rect, texture_size,
+                    texture_format, content_rect, contents_scale,
+                    raster_source);
   EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
   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(contents_scale, copy_quad->contents_scale);
-  EXPECT_EQ(picture_pile, copy_quad->picture_pile);
+  EXPECT_EQ(raster_source, copy_quad->raster_source);
 }
 
 class DrawQuadIteratorTest : public testing::Test {
@@ -922,18 +912,12 @@
   ResourceFormat texture_format = RGBA_8888;
   gfx::Rect content_rect(30, 40, 20, 30);
   float contents_scale = 3.141592f;
-  scoped_refptr<PicturePileImpl> picture_pile = PicturePileImpl::Create();
+  scoped_refptr<PicturePileImpl> raster_source = PicturePileImpl::Create();
 
   CREATE_SHARED_STATE();
-  CREATE_QUAD_8_NEW(PictureDrawQuad,
-                    opaque_rect,
-                    visible_rect,
-                    tex_coord_rect,
-                    texture_size,
-                    texture_format,
-                    content_rect,
-                    contents_scale,
-                    picture_pile);
+  CREATE_QUAD_8_NEW(PictureDrawQuad, opaque_rect, visible_rect, tex_coord_rect,
+                    texture_size, texture_format, content_rect, contents_scale,
+                    raster_source);
   EXPECT_EQ(0, IterateAndCount(quad_new));
 }
 
diff --git a/cc/quads/picture_draw_quad.cc b/cc/quads/picture_draw_quad.cc
index af120a4..bf329c2 100644
--- a/cc/quads/picture_draw_quad.cc
+++ b/cc/quads/picture_draw_quad.cc
@@ -26,7 +26,7 @@
                              ResourceFormat texture_format,
                              const gfx::Rect& content_rect,
                              float contents_scale,
-                             scoped_refptr<PicturePileImpl> picture_pile) {
+                             scoped_refptr<RasterSource> raster_source) {
   ContentDrawQuadBase::SetNew(
       shared_quad_state,
       DrawQuad::PICTURE_CONTENT,
@@ -38,7 +38,7 @@
       !PlatformColor::SameComponentOrder(texture_format));
   this->content_rect = content_rect;
   this->contents_scale = contents_scale;
-  this->picture_pile = picture_pile;
+  this->raster_source = raster_source;
   this->texture_format = texture_format;
 }
 
@@ -52,7 +52,7 @@
                              ResourceFormat texture_format,
                              const gfx::Rect& content_rect,
                              float contents_scale,
-                             scoped_refptr<PicturePileImpl> picture_pile) {
+                             scoped_refptr<RasterSource> raster_source) {
   ContentDrawQuadBase::SetAll(shared_quad_state,
                               DrawQuad::PICTURE_CONTENT,
                               rect,
@@ -65,7 +65,7 @@
                                   texture_format));
   this->content_rect = content_rect;
   this->contents_scale = contents_scale;
-  this->picture_pile = picture_pile;
+  this->raster_source = raster_source;
   this->texture_format = texture_format;
 }
 
@@ -87,7 +87,7 @@
   value->EndArray();
   value->SetDouble("contents_scale", contents_scale);
   value->SetInteger("texture_format", texture_format);
-  // TODO(piman): picture_pile?
+  // TODO(piman): raster_source?
 }
 
 }  // namespace cc
diff --git a/cc/quads/picture_draw_quad.h b/cc/quads/picture_draw_quad.h
index 1bea1a2..62c9f18 100644
--- a/cc/quads/picture_draw_quad.h
+++ b/cc/quads/picture_draw_quad.h
@@ -9,7 +9,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
 #include "cc/quads/content_draw_quad_base.h"
-#include "cc/resources/picture_pile_impl.h"
+#include "cc/resources/raster_source.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/size.h"
@@ -31,7 +31,7 @@
               ResourceFormat texture_format,
               const gfx::Rect& content_rect,
               float contents_scale,
-              scoped_refptr<PicturePileImpl> picture_pile);
+              scoped_refptr<RasterSource> raster_source);
 
   void SetAll(const SharedQuadState* shared_quad_state,
               const gfx::Rect& rect,
@@ -43,11 +43,11 @@
               ResourceFormat texture_format,
               const gfx::Rect& content_rect,
               float contents_scale,
-              scoped_refptr<PicturePileImpl> picture_pile);
+              scoped_refptr<RasterSource> raster_source);
 
   gfx::Rect content_rect;
   float contents_scale;
-  scoped_refptr<PicturePileImpl> picture_pile;
+  scoped_refptr<RasterSource> raster_source;
   ResourceFormat texture_format;
 
   void IterateResources(const ResourceIteratorCallback& callback) override;
diff --git a/cc/resources/bitmap_content_layer_updater.cc b/cc/resources/bitmap_content_layer_updater.cc
index 63ba336..31a62c3 100644
--- a/cc/resources/bitmap_content_layer_updater.cc
+++ b/cc/resources/bitmap_content_layer_updater.cc
@@ -32,19 +32,17 @@
 
 scoped_refptr<BitmapContentLayerUpdater> BitmapContentLayerUpdater::Create(
     scoped_ptr<LayerPainter> painter,
-    RenderingStatsInstrumentation* stats_instrumentation,
     int layer_id) {
   return make_scoped_refptr(
       new BitmapContentLayerUpdater(painter.Pass(),
-                                    stats_instrumentation,
                                     layer_id));
 }
 
 BitmapContentLayerUpdater::BitmapContentLayerUpdater(
     scoped_ptr<LayerPainter> painter,
-    RenderingStatsInstrumentation* stats_instrumentation,
     int layer_id)
-    : ContentLayerUpdater(painter.Pass(), stats_instrumentation, layer_id) {}
+    : ContentLayerUpdater(painter.Pass(), layer_id) {
+}
 
 BitmapContentLayerUpdater::~BitmapContentLayerUpdater() {}
 
@@ -71,17 +69,11 @@
     DCHECK_EQ(paint_rect.height(), canvas_->getBaseLayerSize().height());
   }
 
-  base::TimeTicks start_time =
-      rendering_stats_instrumentation_->StartRecording();
   PaintContents(canvas_.get(),
                 content_size,
                 paint_rect,
                 contents_width_scale,
                 contents_height_scale);
-  base::TimeDelta duration =
-      rendering_stats_instrumentation_->EndRecording(start_time);
-  rendering_stats_instrumentation_->AddPaint(
-      duration, paint_rect.width() * paint_rect.height());
 }
 
 void BitmapContentLayerUpdater::UpdateTexture(ResourceUpdateQueue* queue,
diff --git a/cc/resources/bitmap_content_layer_updater.h b/cc/resources/bitmap_content_layer_updater.h
index 5ddc35f..3477600 100644
--- a/cc/resources/bitmap_content_layer_updater.h
+++ b/cc/resources/bitmap_content_layer_updater.h
@@ -42,7 +42,6 @@
 
   static scoped_refptr<BitmapContentLayerUpdater> Create(
       scoped_ptr<LayerPainter> painter,
-      RenderingStatsInstrumentation* stats_instrumenation,
       int layer_id);
 
   scoped_ptr<LayerUpdater::Resource> CreateResource(
@@ -63,7 +62,6 @@
  protected:
   BitmapContentLayerUpdater(
       scoped_ptr<LayerPainter> painter,
-      RenderingStatsInstrumentation* stats_instrumenation,
       int layer_id);
   ~BitmapContentLayerUpdater() override;
 
diff --git a/cc/resources/bitmap_skpicture_content_layer_updater.cc b/cc/resources/bitmap_skpicture_content_layer_updater.cc
index 5b8e5e4..a78a9df 100644
--- a/cc/resources/bitmap_skpicture_content_layer_updater.cc
+++ b/cc/resources/bitmap_skpicture_content_layer_updater.cc
@@ -53,9 +53,8 @@
     scoped_ptr<LayerPainter> painter,
     RenderingStatsInstrumentation* stats_instrumentation,
     int layer_id)
-    : SkPictureContentLayerUpdater(painter.Pass(),
-                                   stats_instrumentation,
-                                   layer_id) {}
+    : SkPictureContentLayerUpdater(painter.Pass(), layer_id) {
+}
 
 BitmapSkPictureContentLayerUpdater::~BitmapSkPictureContentLayerUpdater() {}
 
diff --git a/cc/resources/content_layer_updater.cc b/cc/resources/content_layer_updater.cc
index 971362f..206d76b 100644
--- a/cc/resources/content_layer_updater.cc
+++ b/cc/resources/content_layer_updater.cc
@@ -5,7 +5,6 @@
 #include "cc/resources/content_layer_updater.h"
 
 #include "base/debug/trace_event.h"
-#include "cc/debug/rendering_stats_instrumentation.h"
 #include "cc/resources/layer_painter.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkRect.h"
@@ -16,12 +15,9 @@
 
 namespace cc {
 
-ContentLayerUpdater::ContentLayerUpdater(
-    scoped_ptr<LayerPainter> painter,
-    RenderingStatsInstrumentation* stats_instrumentation,
-    int layer_id)
-    : rendering_stats_instrumentation_(stats_instrumentation),
-      layer_id_(layer_id),
+ContentLayerUpdater::ContentLayerUpdater(scoped_ptr<LayerPainter> painter,
+                                         int layer_id)
+    : layer_id_(layer_id),
       layer_is_opaque_(false),
       layer_fills_bounds_completely_(false),
       painter_(painter.Pass()),
@@ -30,11 +26,6 @@
 
 ContentLayerUpdater::~ContentLayerUpdater() {}
 
-void ContentLayerUpdater::set_rendering_stats_instrumentation(
-    RenderingStatsInstrumentation* rsi) {
-  rendering_stats_instrumentation_ = rsi;
-}
-
 void ContentLayerUpdater::PaintContents(SkCanvas* canvas,
                                         const gfx::Size& layer_content_size,
                                         const gfx::Rect& paint_rect,
diff --git a/cc/resources/content_layer_updater.h b/cc/resources/content_layer_updater.h
index 4ba18ba..0f26b82 100644
--- a/cc/resources/content_layer_updater.h
+++ b/cc/resources/content_layer_updater.h
@@ -21,15 +21,12 @@
 // their respective PaintContents implementations.
 class CC_EXPORT ContentLayerUpdater : public LayerUpdater {
  public:
-  void set_rendering_stats_instrumentation(RenderingStatsInstrumentation* rsi);
   void SetOpaque(bool opaque) override;
   void SetFillsBoundsCompletely(bool fills_bounds) override;
   void SetBackgroundColor(SkColor background_color) override;
 
  protected:
-  ContentLayerUpdater(scoped_ptr<LayerPainter> painter,
-                      RenderingStatsInstrumentation* stats_instrumentation,
-                      int layer_id);
+  ContentLayerUpdater(scoped_ptr<LayerPainter> painter, int layer_id);
   ~ContentLayerUpdater() override;
 
   // Paints the contents. |content_size| size of the underlying layer in
@@ -49,7 +46,6 @@
 
   SkColor background_color() const { return background_color_; }
 
-  RenderingStatsInstrumentation* rendering_stats_instrumentation_;
   int layer_id_;
 
   // True when it is known that all output pixels will be opaque.
diff --git a/cc/resources/gpu_raster_worker_pool.cc b/cc/resources/gpu_raster_worker_pool.cc
index 04724f1..c913970 100644
--- a/cc/resources/gpu_raster_worker_pool.cc
+++ b/cc/resources/gpu_raster_worker_pool.cc
@@ -40,7 +40,7 @@
     // Turn on distance fields for layers that have ever animated.
     bool use_distance_field_text =
         use_distance_field_text_ ||
-        raster_source->SuitableForDistanceFieldText();
+        raster_source->ShouldAttemptToUseDistanceFieldText();
     SkSurface* sk_surface = lock_.GetSkSurface(use_distance_field_text);
 
     if (!sk_surface)
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index d8885e7..04b18c3 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -167,18 +167,16 @@
   VerifyLiveTilesRect();
 }
 
-void PictureLayerTiling::UpdateTilesToCurrentPile(
+void PictureLayerTiling::UpdateTilesToCurrentRasterSource(
     const Region& layer_invalidation,
     const gfx::Size& new_layer_bounds) {
   DCHECK(!new_layer_bounds.IsEmpty());
 
-  gfx::Size tile_size = tiling_data_.max_texture_size();
+  gfx::Size content_bounds =
+      gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_));
+  gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
 
   if (new_layer_bounds != layer_bounds_) {
-    gfx::Size content_bounds =
-        gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_));
-
-    tile_size = client_->CalculateTileSize(content_bounds);
     if (tile_size.IsEmpty()) {
       layer_bounds_ = gfx::Size();
       content_bounds = gfx::Size();
@@ -699,15 +697,13 @@
   return current_occlusion_in_layer_space_.IsOccluded(tile_query_rect);
 }
 
-bool PictureLayerTiling::IsTileRequiredForActivation(const Tile* tile) const {
+bool PictureLayerTiling::IsTileRequiredForActivationIfVisible(
+    const Tile* tile) const {
   DCHECK_EQ(PENDING_TREE, client_->GetTree());
 
-  // Note that although this function will determine whether tile is required
-  // for activation assuming that it is in visible (ie in the viewport). That is
-  // to say, even if the tile is outside of the viewport, it will be treated as
-  // if it was inside (there are no explicit checks for this). Hence, this
-  // function is only called for visible tiles to ensure we don't block
-  // activation on tiles outside of the viewport.
+  // This function assumes that the tile is visible (i.e. in the viewport).  The
+  // caller needs to make sure that this condition is met to ensure we don't
+  // block activation on tiles outside of the viewport.
 
   // If we are not allowed to mark tiles as required for activation, then don't
   // do it.
@@ -744,6 +740,21 @@
   return true;
 }
 
+bool PictureLayerTiling::IsTileRequiredForDrawIfVisible(
+    const Tile* tile) const {
+  DCHECK_EQ(ACTIVE_TREE, client_->GetTree());
+
+  // This function assumes that the tile is visible (i.e. in the viewport).
+
+  if (resolution_ != HIGH_RESOLUTION)
+    return false;
+
+  if (IsTileOccluded(tile))
+    return false;
+
+  return true;
+}
+
 void PictureLayerTiling::UpdateTileAndTwinPriority(Tile* tile) const {
   UpdateTilePriority(tile);
 
@@ -756,6 +767,8 @@
     tile->set_is_occluded(twin_tree, false);
     if (twin_tree == PENDING_TREE)
       tile->set_required_for_activation(false);
+    else
+      tile->set_required_for_draw(false);
     return;
   }
 
@@ -766,22 +779,31 @@
   // TODO(vmpstr): This code should return the priority instead of setting it on
   // the tile. This should be a part of the change to move tile priority from
   // tiles into iterators.
+  TilePriority::PriorityBin max_tile_priority_bin =
+      client_->GetMaxTilePriorityBin();
   WhichTree tree = client_->GetTree();
 
   DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile);
   gfx::Rect tile_bounds =
       tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index());
 
-  if (current_visible_rect_.Intersects(tile_bounds)) {
+  if (max_tile_priority_bin <= TilePriority::NOW &&
+      current_visible_rect_.Intersects(tile_bounds)) {
     tile->SetPriority(tree, TilePriority(resolution_, TilePriority::NOW, 0));
-    if (tree == PENDING_TREE)
-      tile->set_required_for_activation(IsTileRequiredForActivation(tile));
+    if (tree == PENDING_TREE) {
+      tile->set_required_for_activation(
+          IsTileRequiredForActivationIfVisible(tile));
+    } else {
+      tile->set_required_for_draw(IsTileRequiredForDrawIfVisible(tile));
+    }
     tile->set_is_occluded(tree, IsTileOccluded(tile));
     return;
   }
 
   if (tree == PENDING_TREE)
     tile->set_required_for_activation(false);
+  else
+    tile->set_required_for_draw(false);
   tile->set_is_occluded(tree, false);
 
   DCHECK_GT(content_to_screen_scale_, 0.f);
@@ -789,8 +811,9 @@
       current_visible_rect_.ManhattanInternalDistance(tile_bounds) *
       content_to_screen_scale_;
 
-  if (current_soon_border_rect_.Intersects(tile_bounds) ||
-      current_skewport_rect_.Intersects(tile_bounds)) {
+  if (max_tile_priority_bin <= TilePriority::SOON &&
+      (current_soon_border_rect_.Intersects(tile_bounds) ||
+       current_skewport_rect_.Intersects(tile_bounds))) {
     tile->SetPriority(
         tree,
         TilePriority(resolution_, TilePriority::SOON, distance_to_visible));
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index 17da548..eb47b60 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -29,7 +29,7 @@
 namespace cc {
 
 class PictureLayerTiling;
-class PicturePileImpl;
+class RasterSource;
 
 class CC_EXPORT PictureLayerTilingClient {
  public:
@@ -48,6 +48,7 @@
       const PictureLayerTiling* tiling) const = 0;
   virtual PictureLayerTiling* GetRecycledTwinTiling(
       const PictureLayerTiling* tiling) = 0;
+  virtual TilePriority::PriorityBin GetMaxTilePriorityBin() const = 0;
   virtual size_t GetMaxTilesForInterestArea() const = 0;
   virtual float GetSkewportTargetTimeInSeconds() const = 0;
   virtual int GetSkewportExtrapolationLimitInContentPixels() const = 0;
@@ -144,8 +145,8 @@
       const gfx::Size& layer_bounds,
       PictureLayerTilingClient* client);
   gfx::Size layer_bounds() const { return layer_bounds_; }
-  void UpdateTilesToCurrentPile(const Region& layer_invalidation,
-                                const gfx::Size& new_layer_bounds);
+  void UpdateTilesToCurrentRasterSource(const Region& layer_invalidation,
+                                        const gfx::Size& new_layer_bounds);
   void CreateMissingTilesInLiveTilesRect();
   void RemoveTilesInRegion(const Region& layer_region);
 
@@ -205,7 +206,8 @@
   }
 
   bool IsTileOccluded(const Tile* tile) const;
-  bool IsTileRequiredForActivation(const Tile* tile) const;
+  bool IsTileRequiredForActivationIfVisible(const Tile* tile) const;
+  bool IsTileRequiredForDrawIfVisible(const Tile* tile) const;
 
   // Iterate over all tiles to fill content_rect.  Even if tiles are invalid
   // (i.e. no valid resource) this tiling should still iterate over them.
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index 8f91763..0d1443e 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -59,7 +59,7 @@
   void RunInvalidateTest(const std::string& test_name, const Region& region) {
     timer_.Reset();
     do {
-      picture_layer_tiling_->UpdateTilesToCurrentPile(
+      picture_layer_tiling_->UpdateTilesToCurrentRasterSource(
           region, picture_layer_tiling_->tiling_size());
       timer_.NextLap();
     } while (!timer_.HasTimeLimitExpired());
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc
index b2b86b5..a0000b6 100644
--- a/cc/resources/picture_layer_tiling_set.cc
+++ b/cc/resources/picture_layer_tiling_set.cc
@@ -69,8 +69,8 @@
     if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) {
       this_tiling->set_resolution(other.tilings_[i]->resolution());
 
-      this_tiling->UpdateTilesToCurrentPile(layer_invalidation,
-                                            new_layer_bounds);
+      this_tiling->UpdateTilesToCurrentRasterSource(layer_invalidation,
+                                                    new_layer_bounds);
       this_tiling->CreateMissingTilesInLiveTilesRect();
       if (this_tiling->resolution() == HIGH_RESOLUTION)
         have_high_res_tiling = true;
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index f793097..786f943 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -211,7 +211,7 @@
 
   Region invalidation =
       SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size));
-  tiling_->UpdateTilesToCurrentPile(invalidation, gfx::Size(200, 200));
+  tiling_->UpdateTilesToCurrentRasterSource(invalidation, gfx::Size(200, 200));
   EXPECT_FALSE(tiling_->TileAt(0, 0));
 }
 
@@ -266,8 +266,8 @@
   // Shrink the tiling so that the last tile row/column is entirely in the
   // border pixels of the interior tiles. That row/column is removed.
   Region invalidation;
-  tiling_->UpdateTilesToCurrentPile(invalidation,
-                                    gfx::Size(right + 1, bottom + 1));
+  tiling_->UpdateTilesToCurrentRasterSource(invalidation,
+                                            gfx::Size(right + 1, bottom + 1));
   EXPECT_EQ(2, tiling_->TilingDataForTesting().num_tiles_x());
   EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y());
 
@@ -284,8 +284,8 @@
 
   // Growing outside the current right/bottom tiles border pixels should create
   // the tiles again, even though the live rect has not changed size.
-  tiling_->UpdateTilesToCurrentPile(invalidation,
-                                    gfx::Size(right + 2, bottom + 2));
+  tiling_->UpdateTilesToCurrentRasterSource(invalidation,
+                                            gfx::Size(right + 2, bottom + 2));
   EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
   EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
 
@@ -421,7 +421,7 @@
 
   Region invalidation =
       SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size));
-  tiling_->UpdateTilesToCurrentPile(invalidation, gfx::Size(200, 200));
+  tiling_->UpdateTilesToCurrentRasterSource(invalidation, gfx::Size(200, 200));
   EXPECT_FALSE(tiling_->TileAt(0, 0));
 
   // The original tile was the same size after resize, but it would include new
@@ -2178,5 +2178,29 @@
   EXPECT_FALSE(recycle_tiling->TileAt(0, 0));
 }
 
+TEST_F(PictureLayerTilingIteratorTest, ResizeTilesAndUpdateToCurrent) {
+  // The tiling has four rows and three columns.
+  Initialize(gfx::Size(150, 100), 1, gfx::Size(250, 150));
+  tiling_->CreateAllTilesForTesting();
+  EXPECT_EQ(150, tiling_->TilingDataForTesting().max_texture_size().width());
+  EXPECT_EQ(100, tiling_->TilingDataForTesting().max_texture_size().height());
+  EXPECT_EQ(4u, tiling_->AllRefTilesForTesting().size());
+
+  client_.SetTileSize(gfx::Size(250, 200));
+  client_.set_tree(PENDING_TREE);
+
+  // Tile size in the tiling should still be 150x100.
+  EXPECT_EQ(150, tiling_->TilingDataForTesting().max_texture_size().width());
+  EXPECT_EQ(100, tiling_->TilingDataForTesting().max_texture_size().height());
+
+  Region invalidation;
+  tiling_->UpdateTilesToCurrentRasterSource(invalidation, gfx::Size(250, 150));
+
+  // Tile size in the tiling should be resized to 250x200.
+  EXPECT_EQ(250, tiling_->TilingDataForTesting().max_texture_size().width());
+  EXPECT_EQ(200, tiling_->TilingDataForTesting().max_texture_size().height());
+  EXPECT_EQ(0u, tiling_->AllRefTilesForTesting().size());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc
index 1ad673b..ab138ca 100644
--- a/cc/resources/picture_pile.cc
+++ b/cc/resources/picture_pile.cc
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "cc/base/region.h"
-#include "cc/debug/rendering_stats_instrumentation.h"
+#include "cc/resources/picture_pile_impl.h"
 #include "cc/resources/raster_worker_pool.h"
 #include "skia/ext/analysis_canvas.h"
 
@@ -22,6 +22,24 @@
 // operations.
 const int kOpCountThatIsOkToAnalyze = 10;
 
+// Dimensions of the tiles in this picture pile as well as the dimensions of
+// the base picture in each tile.
+const int kBasePictureSize = 512;
+const int kTileGridBorderPixels = 1;
+#ifdef NDEBUG
+const bool kDefaultClearCanvasSetting = false;
+#else
+const bool kDefaultClearCanvasSetting = true;
+#endif
+
+// Invalidation frequency settings. kInvalidationFrequencyThreshold is a value
+// between 0 and 1 meaning invalidation frequency between 0% and 100% that
+// indicates when to stop invalidating offscreen regions.
+// kFrequentInvalidationDistanceThreshold defines what it means to be
+// "offscreen" in terms of distance to visible in css pixels.
+const float kInvalidationFrequencyThreshold = 0.75f;
+const int kFrequentInvalidationDistanceThreshold = 512;
+
 // TODO(humper): The density threshold here is somewhat arbitrary; need a
 // way to set // this from the command line so we can write a benchmark
 // script and find a sweet spot.
@@ -149,8 +167,21 @@
 namespace cc {
 
 PicturePile::PicturePile()
-    : is_suitable_for_gpu_rasterization_(true),
-      pixel_record_distance_(kPixelDistanceToRecord) {
+    : min_contents_scale_(0),
+      slow_down_raster_scale_factor_for_debug_(0),
+      contents_opaque_(false),
+      contents_fill_bounds_completely_(false),
+      clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+      has_any_recordings_(false),
+      is_mask_(false),
+      is_solid_color_(false),
+      solid_color_(SK_ColorTRANSPARENT),
+      pixel_record_distance_(kPixelDistanceToRecord),
+      is_suitable_for_gpu_rasterization_(true) {
+  tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
+  tile_grid_info_.fTileInterval.setEmpty();
+  tile_grid_info_.fMargin.setEmpty();
+  tile_grid_info_.fOffset.setZero();
 }
 
 PicturePile::~PicturePile() {
@@ -165,8 +196,7 @@
     const gfx::Size& layer_size,
     const gfx::Rect& visible_layer_rect,
     int frame_number,
-    Picture::RecordingMode recording_mode,
-    RenderingStatsInstrumentation* stats_instrumentation) {
+    Picture::RecordingMode recording_mode) {
   background_color_ = background_color;
   contents_opaque_ = contents_opaque;
   contents_fill_bounds_completely_ = contents_fill_bounds_completely;
@@ -174,7 +204,7 @@
   bool updated = false;
 
   Region resize_invalidation;
-  gfx::Size old_tiling_size = tiling_size();
+  gfx::Size old_tiling_size = GetSize();
   if (old_tiling_size != layer_size) {
     tiling_.SetTilingSize(layer_size);
     updated = true;
@@ -183,26 +213,35 @@
   gfx::Rect interest_rect = visible_layer_rect;
   interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_);
   recorded_viewport_ = interest_rect;
-  recorded_viewport_.Intersect(gfx::Rect(tiling_size()));
+  recorded_viewport_.Intersect(gfx::Rect(GetSize()));
 
   gfx::Rect interest_rect_over_tiles =
       tiling_.ExpandRectToTileBounds(interest_rect);
 
+  gfx::Size min_tiling_size(
+      std::min(GetSize().width(), old_tiling_size.width()),
+      std::min(GetSize().height(), old_tiling_size.height()));
+  gfx::Size max_tiling_size(
+      std::max(GetSize().width(), old_tiling_size.width()),
+      std::max(GetSize().height(), old_tiling_size.height()));
+
   if (old_tiling_size != layer_size) {
     has_any_recordings_ = false;
 
-    // Drop recordings that are outside the new layer bounds or that changed
-    // size.
+    // Drop recordings that are outside the new or old layer bounds or that
+    // changed size.  Newly exposed areas are considered invalidated.
+    // Previously exposed areas that are now outside of bounds also need to
+    // be invalidated, as they may become part of raster when scale < 1.
     std::vector<PictureMapKey> to_erase;
     int min_toss_x = tiling_.num_tiles_x();
-    if (tiling_size().width() > old_tiling_size.width()) {
+    if (max_tiling_size.width() > min_tiling_size.width()) {
       min_toss_x =
-          tiling_.FirstBorderTileXIndexFromSrcCoord(old_tiling_size.width());
+          tiling_.FirstBorderTileXIndexFromSrcCoord(min_tiling_size.width());
     }
     int min_toss_y = tiling_.num_tiles_y();
-    if (tiling_size().height() > old_tiling_size.height()) {
+    if (max_tiling_size.height() > min_tiling_size.height()) {
       min_toss_y =
-          tiling_.FirstBorderTileYIndexFromSrcCoord(old_tiling_size.height());
+          tiling_.FirstBorderTileYIndexFromSrcCoord(min_tiling_size.height());
     }
     for (PictureMap::const_iterator it = picture_map_.begin();
          it != picture_map_.end();
@@ -221,20 +260,22 @@
     // If a recording is dropped and not re-recorded below, invalidate that
     // full recording to cause any raster tiles that would use it to be
     // dropped.
-    // If the recording will be replaced below, just invalidate newly exposed
-    // areas to force raster tiles that include the old recording to know
-    // there is new recording to display.
-    gfx::Rect old_tiling_rect_over_tiles =
-        tiling_.ExpandRectToTileBounds(gfx::Rect(old_tiling_size));
+    // If the recording will be replaced below, invalidate newly exposed
+    // areas and previously exposed areas to force raster tiles that include the
+    // old recording to know there is new recording to display.
+    gfx::Rect min_tiling_rect_over_tiles =
+        tiling_.ExpandRectToTileBounds(gfx::Rect(min_tiling_size));
     if (min_toss_x < tiling_.num_tiles_x()) {
       // The bounds which we want to invalidate are the tiles along the old
-      // edge of the pile. We'll call this bounding box the OLD EDGE RECT.
+      // edge of the pile when expanding, or the new edge of the pile when
+      // shrinking. In either case, it's the difference of the two, so we'll
+      // call this bounding box the DELTA EDGE RECT.
       //
-      // In the picture below, the old edge rect would be the bounding box
-      // of tiles {h,i,j}. |min_toss_x| would be equal to the horizontal index
-      // of the same tiles.
+      // In the picture below, the delta edge rect would be the bounding box of
+      // tiles {h,i,j}. |min_toss_x| would be equal to the horizontal index of
+      // the same tiles.
       //
-      //  old pile edge-v  new pile edge-v
+      //  min pile edge-v  max pile edge-v
       // ---------------+ - - - - - - - -+
       // mmppssvvyybbeeh|h               .
       // mmppssvvyybbeeh|h               .
@@ -242,33 +283,33 @@
       // nnqqttwwzzccffi|i               .
       // oorruuxxaaddggj|j               .
       // oorruuxxaaddggj|j               .
-      // ---------------+ - - - - - - - -+ <- old pile edge
+      // ---------------+ - - - - - - - -+ <- min pile edge
       //                                 .
-      //  - - - - - - - - - - - - - - - -+ <- new pile edge
+      //  - - - - - - - - - - - - - - - -+ <- max pile edge
       //
       // If you were to slide a vertical beam from the left edge of the
-      // old edge rect toward the right, it would either hit the right edge
-      // of the old edge rect, or the interest rect (expanded to the bounds
+      // delta edge rect toward the right, it would either hit the right edge
+      // of the delta edge rect, or the interest rect (expanded to the bounds
       // of the tiles it touches). The same is true for a beam parallel to
-      // any of the four edges, sliding accross the old edge rect. We use
+      // any of the four edges, sliding across the delta edge rect. We use
       // the union of these four rectangles generated by these beams to
-      // determine which part of the old edge rect is outside of the expanded
+      // determine which part of the delta edge rect is outside of the expanded
       // interest rect.
       //
-      // Case 1: Intersect rect is outside the old edge rect. It can be
+      // Case 1: Intersect rect is outside the delta edge rect. It can be
       // either on the left or the right. The |left_rect| and |right_rect|,
       // cover this case, one will be empty and one will cover the full
-      // old edge rect. In the picture below, |left_rect| would cover the
-      // old edge rect, and |right_rect| would be empty.
+      // delta edge rect. In the picture below, |left_rect| would cover the
+      // delta edge rect, and |right_rect| would be empty.
       // +----------------------+ |^^^^^^^^^^^^^^^|
-      // |===>   OLD EDGE RECT  | |               |
+      // |===> DELTA EDGE RECT  | |               |
       // |===>                  | | INTEREST RECT |
       // |===>                  | |               |
       // |===>                  | |               |
       // +----------------------+ |vvvvvvvvvvvvvvv|
       //
-      // Case 2: Interest rect is inside the old edge rect. It will always
-      // fill the entire old edge rect horizontally since the old edge rect
+      // Case 2: Interest rect is inside the delta edge rect. It will always
+      // fill the entire delta edge rect horizontally since the old edge rect
       // is a single tile wide, and the interest rect has been expanded to the
       // bounds of the tiles it touches. In this case the |left_rect| and
       // |right_rect| will be empty, but the case is handled by the |top_rect|
@@ -285,19 +326,19 @@
       // |                 |
       // +-----------------+
       // |                 |
-      // | OLD EDGE RECT   |
+      // | DELTA EDGE RECT |
       // +-----------------+
       //
       // Lastly, we need to consider tiles inside the expanded interest rect.
       // For those tiles, we want to invalidate exactly the newly exposed
-      // pixels. In the picture below the tiles in the old edge rect have been
-      // resized and the area covered by periods must be invalidated. The
+      // pixels. In the picture below the tiles in the delta edge rect have
+      // been resized and the area covered by periods must be invalidated. The
       // |exposed_rect| will cover exactly that area.
-      //           v-old pile edge
+      //           v-min pile edge
       // +---------+-------+
       // |         ........|
       // |         ........|
-      // |  OLD EDGE.RECT..|
+      // | DELTA EDGE.RECT.|
       // |         ........|
       // |         ........|
       // |         ........|
@@ -308,18 +349,18 @@
 
       int left = tiling_.TilePositionX(min_toss_x);
       int right = left + tiling_.TileSizeX(min_toss_x);
-      int top = old_tiling_rect_over_tiles.y();
-      int bottom = old_tiling_rect_over_tiles.bottom();
+      int top = min_tiling_rect_over_tiles.y();
+      int bottom = min_tiling_rect_over_tiles.bottom();
 
       int left_until = std::min(interest_rect_over_tiles.x(), right);
       int right_until = std::max(interest_rect_over_tiles.right(), left);
       int top_until = std::min(interest_rect_over_tiles.y(), bottom);
       int bottom_until = std::max(interest_rect_over_tiles.bottom(), top);
 
-      int exposed_left = old_tiling_size.width();
-      int exposed_left_until = tiling_size().width();
+      int exposed_left = min_tiling_size.width();
+      int exposed_left_until = max_tiling_size.width();
       int exposed_top = top;
-      int exposed_bottom = tiling_size().height();
+      int exposed_bottom = max_tiling_size.height();
       DCHECK_GE(exposed_left, left);
 
       gfx::Rect left_rect(left, top, left_until - left, bottom - top);
@@ -339,23 +380,23 @@
     }
     if (min_toss_y < tiling_.num_tiles_y()) {
       // The same thing occurs here as in the case above, but the invalidation
-      // rect is the bounding box around the bottom row of tiles in the old
+      // rect is the bounding box around the bottom row of tiles in the min
       // pile. This would be tiles {o,r,u,x,a,d,g,j} in the above picture.
 
       int top = tiling_.TilePositionY(min_toss_y);
       int bottom = top + tiling_.TileSizeY(min_toss_y);
-      int left = old_tiling_rect_over_tiles.x();
-      int right = old_tiling_rect_over_tiles.right();
+      int left = min_tiling_rect_over_tiles.x();
+      int right = min_tiling_rect_over_tiles.right();
 
       int top_until = std::min(interest_rect_over_tiles.y(), bottom);
       int bottom_until = std::max(interest_rect_over_tiles.bottom(), top);
       int left_until = std::min(interest_rect_over_tiles.x(), right);
       int right_until = std::max(interest_rect_over_tiles.right(), left);
 
-      int exposed_top = old_tiling_size.height();
-      int exposed_top_until = tiling_size().height();
+      int exposed_top = min_tiling_size.height();
+      int exposed_top_until = max_tiling_size.height();
       int exposed_left = left;
-      int exposed_right = tiling_size().width();
+      int exposed_right = max_tiling_size.width();
       DCHECK_GE(exposed_top, top);
 
       gfx::Rect left_rect(left, top, left_until - left, bottom - top);
@@ -378,7 +419,7 @@
   // Detect cases where the full pile is invalidated, in this situation we
   // can just drop/invalidate everything.
   if (invalidation->Contains(gfx::Rect(old_tiling_size)) ||
-      invalidation->Contains(gfx::Rect(tiling_size()))) {
+      invalidation->Contains(gfx::Rect(GetSize()))) {
     for (auto& it : picture_map_)
       updated = it.second.Invalidate(frame_number) || updated;
   } else {
@@ -489,9 +530,7 @@
     bool gather_pixel_refs = RasterWorkerPool::GetNumRasterThreads() > 1;
 
     {
-      base::TimeDelta best_duration = base::TimeDelta::Max();
       for (int i = 0; i < repeat_count; i++) {
-        base::TimeTicks start_time = stats_instrumentation->StartRecording();
         picture = Picture::Create(record_rect,
                                   painter,
                                   tile_grid_info_,
@@ -505,13 +544,7 @@
         // the pile after each invalidation.
         is_suitable_for_gpu_rasterization_ &=
             picture->IsSuitableForGpuRasterization();
-        base::TimeDelta duration =
-            stats_instrumentation->EndRecording(start_time);
-        best_duration = std::min(duration, best_duration);
       }
-      int recorded_pixel_count =
-          picture->LayerRect().width() * picture->LayerRect().height();
-      stats_instrumentation->AddRecord(best_duration, recorded_pixel_count);
     }
 
     bool found_tile_for_recorded_picture = false;
@@ -536,11 +569,93 @@
   return true;
 }
 
+gfx::Size PicturePile::GetSize() const {
+  return tiling_.tiling_size();
+}
+
 void PicturePile::SetEmptyBounds() {
   tiling_.SetTilingSize(gfx::Size());
   Clear();
 }
 
+void PicturePile::SetMinContentsScale(float min_contents_scale) {
+  DCHECK(min_contents_scale);
+  if (min_contents_scale_ == min_contents_scale)
+    return;
+
+  // Picture contents are played back scaled. When the final contents scale is
+  // less than 1 (i.e. low res), then multiple recorded pixels will be used
+  // to raster one final pixel.  To avoid splitting a final pixel across
+  // pictures (which would result in incorrect rasterization due to blending), a
+  // buffer margin is added so that any picture can be snapped to integral
+  // final pixels.
+  //
+  // For example, if a 1/4 contents scale is used, then that would be 3 buffer
+  // pixels, since that's the minimum number of pixels to add so that resulting
+  // content can be snapped to a four pixel aligned grid.
+  int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
+  buffer_pixels = std::max(0, buffer_pixels);
+  SetBufferPixels(buffer_pixels);
+  min_contents_scale_ = min_contents_scale;
+}
+
+// static
+void PicturePile::ComputeTileGridInfo(const gfx::Size& tile_grid_size,
+                                      SkTileGridFactory::TileGridInfo* info) {
+  DCHECK(info);
+  info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
+                          tile_grid_size.height() - 2 * kTileGridBorderPixels);
+  DCHECK_GT(info->fTileInterval.width(), 0);
+  DCHECK_GT(info->fTileInterval.height(), 0);
+  info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
+  // Offset the tile grid coordinate space to take into account the fact
+  // that the top-most and left-most tiles do not have top and left borders
+  // respectively.
+  info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
+}
+
+void PicturePile::SetTileGridSize(const gfx::Size& tile_grid_size) {
+  ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
+}
+
+void PicturePile::SetSlowdownRasterScaleFactor(int factor) {
+  slow_down_raster_scale_factor_for_debug_ = factor;
+}
+
+void PicturePile::SetIsMask(bool is_mask) {
+  is_mask_ = is_mask;
+}
+
+void PicturePile::SetUnsuitableForGpuRasterizationForTesting() {
+  is_suitable_for_gpu_rasterization_ = false;
+}
+
+bool PicturePile::IsSuitableForGpuRasterization() const {
+  return is_suitable_for_gpu_rasterization_;
+}
+
+scoped_refptr<RasterSource> PicturePile::CreateRasterSource() const {
+  return scoped_refptr<RasterSource>(
+      PicturePileImpl::CreateFromPicturePile(this));
+}
+
+SkTileGridFactory::TileGridInfo PicturePile::GetTileGridInfoForTesting() const {
+  return tile_grid_info_;
+}
+
+bool PicturePile::CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const {
+  bool include_borders = false;
+  for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
+       tile_iter; ++tile_iter) {
+    PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
+    if (map_iter == picture_map_.end())
+      return false;
+    if (!map_iter->second.GetPicture())
+      return false;
+  }
+  return true;
+}
+
 void PicturePile::DetermineIfSolidColor() {
   is_solid_color_ = false;
   solid_color_ = SK_ColorTRANSPARENT;
@@ -573,4 +688,81 @@
   is_solid_color_ = canvas.GetColorIfSolid(&solid_color_);
 }
 
+gfx::Rect PicturePile::PaddedRect(const PictureMapKey& key) const {
+  gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
+  return PadRect(tile);
+}
+
+gfx::Rect PicturePile::PadRect(const gfx::Rect& rect) const {
+  gfx::Rect padded_rect = rect;
+  padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(),
+                    -buffer_pixels());
+  return padded_rect;
+}
+
+void PicturePile::Clear() {
+  picture_map_.clear();
+  recorded_viewport_ = gfx::Rect();
+  has_any_recordings_ = false;
+  is_solid_color_ = false;
+}
+
+PicturePile::PictureInfo::PictureInfo() : last_frame_number_(0) {
+}
+
+PicturePile::PictureInfo::~PictureInfo() {
+}
+
+void PicturePile::PictureInfo::AdvanceInvalidationHistory(int frame_number) {
+  DCHECK_GE(frame_number, last_frame_number_);
+  if (frame_number == last_frame_number_)
+    return;
+
+  invalidation_history_ <<= (frame_number - last_frame_number_);
+  last_frame_number_ = frame_number;
+}
+
+bool PicturePile::PictureInfo::Invalidate(int frame_number) {
+  AdvanceInvalidationHistory(frame_number);
+  invalidation_history_.set(0);
+
+  bool did_invalidate = !!picture_.get();
+  picture_ = NULL;
+  return did_invalidate;
+}
+
+bool PicturePile::PictureInfo::NeedsRecording(int frame_number,
+                                              int distance_to_visible) {
+  AdvanceInvalidationHistory(frame_number);
+
+  // We only need recording if we don't have a picture. Furthermore, we only
+  // need a recording if we're within frequent invalidation distance threshold
+  // or the invalidation is not frequent enough (below invalidation frequency
+  // threshold).
+  return !picture_.get() &&
+         ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
+          (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
+}
+
+void PicturePile::SetBufferPixels(int new_buffer_pixels) {
+  if (new_buffer_pixels == buffer_pixels())
+    return;
+
+  Clear();
+  tiling_.SetBorderTexels(new_buffer_pixels);
+}
+
+void PicturePile::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
+  picture_ = picture;
+}
+
+const Picture* PicturePile::PictureInfo::GetPicture() const {
+  return picture_.get();
+}
+
+float PicturePile::PictureInfo::GetInvalidationFrequency() const {
+  return invalidation_history_.count() /
+         static_cast<float>(INVALIDATION_FRAMES_TRACKED);
+}
+
 }  // namespace cc
diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h
index 7cd2229..ffd9b52 100644
--- a/cc/resources/picture_pile.h
+++ b/cc/resources/picture_pile.h
@@ -5,25 +5,21 @@
 #ifndef CC_RESOURCES_PICTURE_PILE_H_
 #define CC_RESOURCES_PICTURE_PILE_H_
 
+#include <bitset>
+
 #include "base/memory/ref_counted.h"
-#include "cc/resources/picture_pile_base.h"
-#include "ui/gfx/geometry/rect.h"
+#include "cc/base/tiling_data.h"
+#include "cc/resources/recording_source.h"
 
 namespace cc {
 class PicturePileImpl;
-class Region;
-class RenderingStatsInstrumentation;
 
-class CC_EXPORT PicturePile : public PicturePileBase {
+class CC_EXPORT PicturePile : public RecordingSource {
  public:
   PicturePile();
   ~PicturePile() override;
 
-  // Re-record parts of the picture that are invalid.
-  // Invalidations are in layer space, and will be expanded to cover everything
-  // that was either recorded/changed or that has no recording, leaving out only
-  // pieces that we had a recording for and it was not changed.
-  // Return true iff the pile was modified.
+  // RecordingSource overrides.
   bool UpdateAndExpandInvalidation(
       ContentLayerClient* painter,
       Region* invalidation,
@@ -33,35 +29,92 @@
       const gfx::Size& layer_size,
       const gfx::Rect& visible_layer_rect,
       int frame_number,
-      Picture::RecordingMode recording_mode,
-      RenderingStatsInstrumentation* stats_instrumentation);
+      Picture::RecordingMode recording_mode) override;
+  gfx::Size GetSize() const final;
+  void SetEmptyBounds() override;
+  void SetMinContentsScale(float min_contents_scale) override;
+  void SetTileGridSize(const gfx::Size& tile_grid_size) override;
+  void SetSlowdownRasterScaleFactor(int factor) override;
+  void SetIsMask(bool is_mask) override;
+  bool IsSuitableForGpuRasterization() const override;
+  scoped_refptr<RasterSource> CreateRasterSource() const override;
+  void SetUnsuitableForGpuRasterizationForTesting() override;
+  SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const override;
 
-  void SetEmptyBounds();
+  static void ComputeTileGridInfo(const gfx::Size& tile_grid_size,
+                                  SkTileGridFactory::TileGridInfo* info);
 
-  void set_slow_down_raster_scale_factor(int factor) {
-    slow_down_raster_scale_factor_for_debug_ = factor;
-  }
+ protected:
+  class CC_EXPORT PictureInfo {
+   public:
+    enum { INVALIDATION_FRAMES_TRACKED = 32 };
 
-  void set_show_debug_picture_borders(bool show) {
-    show_debug_picture_borders_ = show;
-  }
+    PictureInfo();
+    ~PictureInfo();
 
-  bool is_suitable_for_gpu_rasterization() const {
-    return is_suitable_for_gpu_rasterization_;
-  }
-  void SetUnsuitableForGpuRasterizationForTesting() {
-    is_suitable_for_gpu_rasterization_ = false;
-  }
+    bool Invalidate(int frame_number);
+    bool NeedsRecording(int frame_number, int distance_to_visible);
+    void SetPicture(scoped_refptr<Picture> picture);
+    const Picture* GetPicture() const;
 
-  void SetPixelRecordDistanceForTesting(int d) { pixel_record_distance_ = d; }
+    float GetInvalidationFrequencyForTesting() const {
+      return GetInvalidationFrequency();
+    }
+
+   private:
+    void AdvanceInvalidationHistory(int frame_number);
+    float GetInvalidationFrequency() const;
+
+    int last_frame_number_;
+    scoped_refptr<const Picture> picture_;
+    std::bitset<INVALIDATION_FRAMES_TRACKED> invalidation_history_;
+  };
+
+  typedef std::pair<int, int> PictureMapKey;
+  typedef base::hash_map<PictureMapKey, PictureInfo> PictureMap;
+
+  // An internal CanRaster check that goes to the picture_map rather than
+  // using the recorded_viewport hint.
+  bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const;
+
+  void Clear();
+
+  gfx::Rect PaddedRect(const PictureMapKey& key) const;
+  gfx::Rect PadRect(const gfx::Rect& rect) const;
+
+  int buffer_pixels() const { return tiling_.border_texels(); }
+
+  // A picture pile is a tiled set of pictures. The picture map is a map of tile
+  // indices to picture infos.
+  PictureMap picture_map_;
+  TilingData tiling_;
+
+  // If non-empty, all pictures tiles inside this rect are recorded. There may
+  // be recordings outside this rect, but everything inside the rect is
+  // recorded.
+  gfx::Rect recorded_viewport_;
+  float min_contents_scale_;
+  SkTileGridFactory::TileGridInfo tile_grid_info_;
+  SkColor background_color_;
+  int slow_down_raster_scale_factor_for_debug_;
+  bool contents_opaque_;
+  bool contents_fill_bounds_completely_;
+  bool clear_canvas_with_debug_color_;
+  // A hint about whether there are any recordings. This may be a false
+  // positive.
+  bool has_any_recordings_;
+  bool is_mask_;
+  bool is_solid_color_;
+  SkColor solid_color_;
+  int pixel_record_distance_;
 
  private:
   friend class PicturePileImpl;
 
   void DetermineIfSolidColor();
+  void SetBufferPixels(int buffer_pixels);
 
   bool is_suitable_for_gpu_rasterization_;
-  int pixel_record_distance_;
 
   DISALLOW_COPY_AND_ASSIGN(PicturePile);
 };
diff --git a/cc/resources/picture_pile_base.cc b/cc/resources/picture_pile_base.cc
deleted file mode 100644
index a145b6c..0000000
--- a/cc/resources/picture_pile_base.cc
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/picture_pile_base.h"
-
-#include <algorithm>
-#include <set>
-#include <vector>
-
-#include "base/debug/trace_event_argument.h"
-#include "base/logging.h"
-#include "base/values.h"
-#include "cc/debug/traced_value.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-
-namespace {
-// Dimensions of the tiles in this picture pile as well as the dimensions of
-// the base picture in each tile.
-const int kBasePictureSize = 512;
-const int kTileGridBorderPixels = 1;
-#ifdef NDEBUG
-const bool kDefaultClearCanvasSetting = false;
-#else
-const bool kDefaultClearCanvasSetting = true;
-#endif
-
-// Invalidation frequency settings. kInvalidationFrequencyThreshold is a value
-// between 0 and 1 meaning invalidation frequency between 0% and 100% that
-// indicates when to stop invalidating offscreen regions.
-// kFrequentInvalidationDistanceThreshold defines what it means to be
-// "offscreen" in terms of distance to visible in css pixels.
-const float kInvalidationFrequencyThreshold = 0.75f;
-const int kFrequentInvalidationDistanceThreshold = 512;
-
-}  // namespace
-
-namespace cc {
-
-PicturePileBase::PicturePileBase()
-    : min_contents_scale_(0),
-      background_color_(SkColorSetARGBInline(0, 0, 0, 0)),
-      slow_down_raster_scale_factor_for_debug_(0),
-      contents_opaque_(false),
-      contents_fill_bounds_completely_(false),
-      show_debug_picture_borders_(false),
-      clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
-      has_any_recordings_(false),
-      is_mask_(false),
-      is_solid_color_(false),
-      solid_color_(SK_ColorTRANSPARENT) {
-  tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
-  tile_grid_info_.fTileInterval.setEmpty();
-  tile_grid_info_.fMargin.setEmpty();
-  tile_grid_info_.fOffset.setZero();
-}
-
-PicturePileBase::PicturePileBase(const PicturePileBase* other)
-    : picture_map_(other->picture_map_),
-      tiling_(other->tiling_),
-      recorded_viewport_(other->recorded_viewport_),
-      min_contents_scale_(other->min_contents_scale_),
-      tile_grid_info_(other->tile_grid_info_),
-      background_color_(other->background_color_),
-      slow_down_raster_scale_factor_for_debug_(
-          other->slow_down_raster_scale_factor_for_debug_),
-      contents_opaque_(other->contents_opaque_),
-      contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
-      show_debug_picture_borders_(other->show_debug_picture_borders_),
-      clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
-      has_any_recordings_(other->has_any_recordings_),
-      is_mask_(other->is_mask_),
-      is_solid_color_(other->is_solid_color_),
-      solid_color_(other->solid_color_) {
-}
-
-PicturePileBase::~PicturePileBase() {
-}
-
-void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
-  DCHECK(min_contents_scale);
-  if (min_contents_scale_ == min_contents_scale)
-    return;
-
-  // Picture contents are played back scaled. When the final contents scale is
-  // less than 1 (i.e. low res), then multiple recorded pixels will be used
-  // to raster one final pixel.  To avoid splitting a final pixel across
-  // pictures (which would result in incorrect rasterization due to blending), a
-  // buffer margin is added so that any picture can be snapped to integral
-  // final pixels.
-  //
-  // For example, if a 1/4 contents scale is used, then that would be 3 buffer
-  // pixels, since that's the minimum number of pixels to add so that resulting
-  // content can be snapped to a four pixel aligned grid.
-  int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
-  buffer_pixels = std::max(0, buffer_pixels);
-  SetBufferPixels(buffer_pixels);
-  min_contents_scale_ = min_contents_scale;
-}
-
-// static
-void PicturePileBase::ComputeTileGridInfo(
-    const gfx::Size& tile_grid_size,
-    SkTileGridFactory::TileGridInfo* info) {
-  DCHECK(info);
-  info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
-                          tile_grid_size.height() - 2 * kTileGridBorderPixels);
-  DCHECK_GT(info->fTileInterval.width(), 0);
-  DCHECK_GT(info->fTileInterval.height(), 0);
-  info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
-  // Offset the tile grid coordinate space to take into account the fact
-  // that the top-most and left-most tiles do not have top and left borders
-  // respectively.
-  info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
-}
-
-void PicturePileBase::SetTileGridSize(const gfx::Size& tile_grid_size) {
-  ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
-}
-
-void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
-  if (new_buffer_pixels == buffer_pixels())
-    return;
-
-  Clear();
-  tiling_.SetBorderTexels(new_buffer_pixels);
-}
-
-void PicturePileBase::Clear() {
-  picture_map_.clear();
-  recorded_viewport_ = gfx::Rect();
-  has_any_recordings_ = false;
-  is_solid_color_ = false;
-}
-
-bool PicturePileBase::HasRecordingAt(int x, int y) {
-  PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
-  if (found == picture_map_.end())
-    return false;
-  return !!found->second.GetPicture();
-}
-
-bool PicturePileBase::CanRaster(float contents_scale,
-                                const gfx::Rect& content_rect) const {
-  if (tiling_.tiling_size().IsEmpty())
-    return false;
-  gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
-      content_rect, 1.f / contents_scale);
-  layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
-
-  // Common case inside of viewport to avoid the slower map lookups.
-  if (recorded_viewport_.Contains(layer_rect)) {
-    // Sanity check that there are no false positives in recorded_viewport_.
-    DCHECK(CanRasterSlowTileCheck(layer_rect));
-    return true;
-  }
-
-  return CanRasterSlowTileCheck(layer_rect);
-}
-
-bool PicturePileBase::CanRasterSlowTileCheck(
-    const gfx::Rect& layer_rect) const {
-  bool include_borders = false;
-  for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
-       tile_iter;
-       ++tile_iter) {
-    PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
-    if (map_iter == picture_map_.end())
-      return false;
-    if (!map_iter->second.GetPicture())
-      return false;
-  }
-  return true;
-}
-
-gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) const {
-  gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
-  return PadRect(tile);
-}
-
-gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) const {
-  gfx::Rect padded_rect = rect;
-  padded_rect.Inset(
-      -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
-  return padded_rect;
-}
-
-void PicturePileBase::AsValueInto(base::debug::TracedValue* pictures) const {
-  gfx::Rect tiling_rect(tiling_.tiling_size());
-  std::set<const void*> appended_pictures;
-  bool include_borders = true;
-  for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
-       tile_iter;
-       ++tile_iter) {
-    PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
-    if (map_iter == picture_map_.end())
-      continue;
-
-    const Picture* picture = map_iter->second.GetPicture();
-    if (picture && (appended_pictures.count(picture) == 0)) {
-      appended_pictures.insert(picture);
-      TracedValue::AppendIDRef(picture, pictures);
-    }
-  }
-}
-
-PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {}
-
-PicturePileBase::PictureInfo::~PictureInfo() {}
-
-void PicturePileBase::PictureInfo::AdvanceInvalidationHistory(
-    int frame_number) {
-  DCHECK_GE(frame_number, last_frame_number_);
-  if (frame_number == last_frame_number_)
-    return;
-
-  invalidation_history_ <<= (frame_number - last_frame_number_);
-  last_frame_number_ = frame_number;
-}
-
-bool PicturePileBase::PictureInfo::Invalidate(int frame_number) {
-  AdvanceInvalidationHistory(frame_number);
-  invalidation_history_.set(0);
-
-  bool did_invalidate = !!picture_.get();
-  picture_ = NULL;
-  return did_invalidate;
-}
-
-bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number,
-                                                  int distance_to_visible) {
-  AdvanceInvalidationHistory(frame_number);
-
-  // We only need recording if we don't have a picture. Furthermore, we only
-  // need a recording if we're within frequent invalidation distance threshold
-  // or the invalidation is not frequent enough (below invalidation frequency
-  // threshold).
-  return !picture_.get() &&
-         ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
-          (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
-}
-
-void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
-  picture_ = picture;
-}
-
-const Picture* PicturePileBase::PictureInfo::GetPicture() const {
-  return picture_.get();
-}
-
-float PicturePileBase::PictureInfo::GetInvalidationFrequency() const {
-  return invalidation_history_.count() /
-         static_cast<float>(INVALIDATION_FRAMES_TRACKED);
-}
-
-}  // namespace cc
diff --git a/cc/resources/picture_pile_base.h b/cc/resources/picture_pile_base.h
deleted file mode 100644
index 71e5bad..0000000
--- a/cc/resources/picture_pile_base.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RESOURCES_PICTURE_PILE_BASE_H_
-#define CC_RESOURCES_PICTURE_PILE_BASE_H_
-
-#include <bitset>
-#include <list>
-#include <utility>
-
-#include "base/containers/hash_tables.h"
-#include "cc/base/cc_export.h"
-#include "cc/base/region.h"
-#include "cc/base/tiling_data.h"
-#include "cc/resources/picture.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace base {
-namespace debug {
-class TracedValue;
-}
-class Value;
-}
-
-namespace cc {
-
-class CC_EXPORT PicturePileBase {
- public:
-  PicturePileBase();
-  explicit PicturePileBase(const PicturePileBase* other);
-
-  gfx::Size tiling_size() const { return tiling_.tiling_size(); }
-  void SetMinContentsScale(float min_contents_scale);
-
-  // If non-empty, all pictures tiles inside this rect are recorded. There may
-  // be recordings outside this rect, but everything inside the rect is
-  // recorded.
-  gfx::Rect recorded_viewport() const { return recorded_viewport_; }
-
-  int num_tiles_x() const { return tiling_.num_tiles_x(); }
-  int num_tiles_y() const { return tiling_.num_tiles_y(); }
-  gfx::Rect tile_bounds(int x, int y) const { return tiling_.TileBounds(x, y); }
-  bool HasRecordingAt(int x, int y);
-  bool CanRaster(float contents_scale, const gfx::Rect& content_rect) const;
-
-  // If this pile contains any valid recordings. May have false positives.
-  bool HasRecordings() const { return has_any_recordings_; }
-
-  bool is_solid_color() const { return is_solid_color_; }
-  SkColor solid_color() const { return solid_color_; }
-
-  void set_is_mask(bool is_mask) { is_mask_ = is_mask; }
-  bool is_mask() const { return is_mask_; }
-
-  static void ComputeTileGridInfo(const gfx::Size& tile_grid_size,
-                                  SkTileGridFactory::TileGridInfo* info);
-
-  void SetTileGridSize(const gfx::Size& tile_grid_size);
-  TilingData& tiling() { return tiling_; }
-
-  void AsValueInto(base::debug::TracedValue* array) const;
-
-  SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const {
-    return tile_grid_info_;
-  }
-
- protected:
-  class CC_EXPORT PictureInfo {
-   public:
-    enum {
-      INVALIDATION_FRAMES_TRACKED = 32
-    };
-
-    PictureInfo();
-    ~PictureInfo();
-
-    bool Invalidate(int frame_number);
-    bool NeedsRecording(int frame_number, int distance_to_visible);
-    void SetPicture(scoped_refptr<Picture> picture);
-    const Picture* GetPicture() const;
-
-    float GetInvalidationFrequencyForTesting() const {
-      return GetInvalidationFrequency();
-    }
-
-   private:
-    void AdvanceInvalidationHistory(int frame_number);
-    float GetInvalidationFrequency() const;
-
-    int last_frame_number_;
-    scoped_refptr<const Picture> picture_;
-    std::bitset<INVALIDATION_FRAMES_TRACKED> invalidation_history_;
-  };
-
-  typedef std::pair<int, int> PictureMapKey;
-  typedef base::hash_map<PictureMapKey, PictureInfo> PictureMap;
-
-  virtual ~PicturePileBase();
-
-  int buffer_pixels() const { return tiling_.border_texels(); }
-  void Clear();
-
-  gfx::Rect PaddedRect(const PictureMapKey& key) const;
-  gfx::Rect PadRect(const gfx::Rect& rect) const;
-
-  // An internal CanRaster check that goes to the picture_map rather than
-  // using the recorded_viewport hint.
-  bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const;
-
-  // A picture pile is a tiled set of pictures. The picture map is a map of tile
-  // indices to picture infos.
-  PictureMap picture_map_;
-  TilingData tiling_;
-  gfx::Rect recorded_viewport_;
-  float min_contents_scale_;
-  SkTileGridFactory::TileGridInfo tile_grid_info_;
-  SkColor background_color_;
-  int slow_down_raster_scale_factor_for_debug_;
-  bool contents_opaque_;
-  bool contents_fill_bounds_completely_;
-  bool show_debug_picture_borders_;
-  bool clear_canvas_with_debug_color_;
-  // A hint about whether there are any recordings. This may be a false
-  // positive.
-  bool has_any_recordings_;
-  bool is_mask_;
-  bool is_solid_color_;
-  SkColor solid_color_;
-
- private:
-  void SetBufferPixels(int buffer_pixels);
-
-  DISALLOW_COPY_AND_ASSIGN(PicturePileBase);
-};
-
-}  // namespace cc
-
-#endif  // CC_RESOURCES_PICTURE_PILE_BASE_H_
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index 0ad746c..7ec9252 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -20,26 +20,49 @@
   return make_scoped_refptr(new PicturePileImpl);
 }
 
-scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther(
-    const PicturePileBase* other) {
+scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromPicturePile(
+    const PicturePile* other) {
   return make_scoped_refptr(new PicturePileImpl(other));
 }
 
 PicturePileImpl::PicturePileImpl()
-    : likely_to_be_used_for_transform_animation_(false) {
+    : background_color_(SK_ColorTRANSPARENT),
+      contents_opaque_(false),
+      contents_fill_bounds_completely_(false),
+      is_solid_color_(false),
+      solid_color_(SK_ColorTRANSPARENT),
+      has_any_recordings_(false),
+      is_mask_(false),
+      clear_canvas_with_debug_color_(false),
+      min_contents_scale_(0.f),
+      slow_down_raster_scale_factor_for_debug_(0),
+      should_attempt_to_use_distance_field_text_(false) {
 }
 
-PicturePileImpl::PicturePileImpl(const PicturePileBase* other)
-    : PicturePileBase(other),
-      likely_to_be_used_for_transform_animation_(false) {
+PicturePileImpl::PicturePileImpl(const PicturePile* other)
+    : picture_map_(other->picture_map_),
+      tiling_(other->tiling_),
+      background_color_(other->background_color_),
+      contents_opaque_(other->contents_opaque_),
+      contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
+      is_solid_color_(other->is_solid_color_),
+      solid_color_(other->solid_color_),
+      recorded_viewport_(other->recorded_viewport_),
+      has_any_recordings_(other->has_any_recordings_),
+      is_mask_(other->is_mask_),
+      clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
+      min_contents_scale_(other->min_contents_scale_),
+      slow_down_raster_scale_factor_for_debug_(
+          other->slow_down_raster_scale_factor_for_debug_),
+      should_attempt_to_use_distance_field_text_(false) {
 }
 
 PicturePileImpl::~PicturePileImpl() {
 }
 
-void PicturePileImpl::RasterDirect(SkCanvas* canvas,
-                                   const gfx::Rect& canvas_rect,
-                                   float contents_scale) const {
+void PicturePileImpl::PlaybackToSharedCanvas(SkCanvas* canvas,
+                                             const gfx::Rect& canvas_rect,
+                                             float contents_scale) const {
   RasterCommon(canvas,
                NULL,
                canvas_rect,
@@ -320,11 +343,88 @@
 
 bool PicturePileImpl::CoversRect(const gfx::Rect& content_rect,
                                  float contents_scale) const {
-  return CanRaster(contents_scale, content_rect);
+  if (tiling_.tiling_size().IsEmpty())
+    return false;
+  gfx::Rect layer_rect =
+      gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale);
+  layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
+
+  // Common case inside of viewport to avoid the slower map lookups.
+  if (recorded_viewport_.Contains(layer_rect)) {
+    // Sanity check that there are no false positives in recorded_viewport_.
+    DCHECK(CanRasterSlowTileCheck(layer_rect));
+    return true;
+  }
+
+  return CanRasterSlowTileCheck(layer_rect);
 }
 
-bool PicturePileImpl::SuitableForDistanceFieldText() const {
-  return likely_to_be_used_for_transform_animation_;
+gfx::Size PicturePileImpl::GetSize() const {
+  return tiling_.tiling_size();
+}
+
+bool PicturePileImpl::IsSolidColor() const {
+  return is_solid_color_;
+}
+
+SkColor PicturePileImpl::GetSolidColor() const {
+  DCHECK(IsSolidColor());
+  return solid_color_;
+}
+
+bool PicturePileImpl::HasRecordings() const {
+  return has_any_recordings_;
+}
+
+gfx::Rect PicturePileImpl::PaddedRect(const PictureMapKey& key) const {
+  gfx::Rect padded_rect = tiling_.TileBounds(key.first, key.second);
+  padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(),
+                    -buffer_pixels());
+  return padded_rect;
+}
+
+bool PicturePileImpl::CanRasterSlowTileCheck(
+    const gfx::Rect& layer_rect) const {
+  bool include_borders = false;
+  for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
+       tile_iter; ++tile_iter) {
+    PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
+    if (map_iter == picture_map_.end())
+      return false;
+    if (!map_iter->second.GetPicture())
+      return false;
+  }
+  return true;
+}
+
+void PicturePileImpl::SetShouldAttemptToUseDistanceFieldText() {
+  should_attempt_to_use_distance_field_text_ = true;
+}
+
+bool PicturePileImpl::ShouldAttemptToUseDistanceFieldText() const {
+  return should_attempt_to_use_distance_field_text_;
+}
+
+void PicturePileImpl::AsValueInto(base::debug::TracedValue* pictures) const {
+  gfx::Rect tiling_rect(tiling_.tiling_size());
+  std::set<const void*> appended_pictures;
+  bool include_borders = true;
+  for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
+       tile_iter; ++tile_iter) {
+    PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
+    if (map_iter == picture_map_.end())
+      continue;
+
+    const Picture* picture = map_iter->second.GetPicture();
+    if (picture && (appended_pictures.count(picture) == 0)) {
+      appended_pictures.insert(picture);
+      TracedValue::AppendIDRef(picture, pictures);
+    }
+  }
+}
+
+bool PicturePileImpl::IsMask() const {
+  return is_mask_;
 }
 
 PicturePileImpl::PixelRefIterator::PixelRefIterator(
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index 9f350a9..6986db4 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -13,7 +13,7 @@
 #include "base/time/time.h"
 #include "cc/base/cc_export.h"
 #include "cc/debug/rendering_stats_instrumentation.h"
-#include "cc/resources/picture_pile_base.h"
+#include "cc/resources/picture_pile.h"
 #include "cc/resources/raster_source.h"
 #include "skia/ext/analysis_canvas.h"
 #include "skia/ext/refptr.h"
@@ -21,12 +21,11 @@
 
 namespace cc {
 
-// TODO(vmpstr): Clean up PicturePileBase and make it a member.
-class CC_EXPORT PicturePileImpl : public PicturePileBase, public RasterSource {
+class CC_EXPORT PicturePileImpl : public RasterSource {
  public:
   static scoped_refptr<PicturePileImpl> Create();
-  static scoped_refptr<PicturePileImpl> CreateFromOther(
-      const PicturePileBase* other);
+  static scoped_refptr<PicturePileImpl> CreateFromPicturePile(
+      const PicturePile* other);
 
   // RasterSource overrides. See RasterSource header for full description.
   // When slow-down-raster-scale-factor is set to a value greater than 1, the
@@ -35,6 +34,9 @@
   void PlaybackToCanvas(SkCanvas* canvas,
                         const gfx::Rect& canvas_rect,
                         float contents_scale) const override;
+  void PlaybackToSharedCanvas(SkCanvas* canvas,
+                              const gfx::Rect& canvas_rect,
+                              float contents_scale) const override;
   void PerformSolidColorAnalysis(
       const gfx::Rect& content_rect,
       float contents_scale,
@@ -44,20 +46,18 @@
                        std::vector<SkPixelRef*>* pixel_refs) const override;
   bool CoversRect(const gfx::Rect& content_rect,
                   float contents_scale) const override;
-  bool SuitableForDistanceFieldText() const override;
-
-  // Raster into the canvas without applying clips.
-  void RasterDirect(SkCanvas* canvas,
-                    const gfx::Rect& canvas_rect,
-                    float contents_scale) const;
+  void SetShouldAttemptToUseDistanceFieldText() override;
+  bool ShouldAttemptToUseDistanceFieldText() const override;
+  gfx::Size GetSize() const override;
+  bool IsSolidColor() const override;
+  SkColor GetSolidColor() const override;
+  bool HasRecordings() const override;
+  bool IsMask() const override;
 
   // Tracing functionality.
-  void DidBeginTracing();
-  skia::RefPtr<SkPicture> GetFlattenedPicture();
-
-  void set_likely_to_be_used_for_transform_animation() {
-    likely_to_be_used_for_transform_animation_ = true;
-  }
+  void DidBeginTracing() override;
+  void AsValueInto(base::debug::TracedValue* array) const override;
+  skia::RefPtr<SkPicture> GetFlattenedPicture() override;
 
   // Iterator used to return SkPixelRefs from this picture pile.
   // Public for testing.
@@ -87,10 +87,31 @@
   friend class PicturePile;
   friend class PixelRefIterator;
 
+  // TODO(vmpstr): Change this when pictures are split from invalidation info.
+  using PictureMapKey = PicturePile::PictureMapKey;
+  using PictureMap = PicturePile::PictureMap;
+  using PictureInfo = PicturePile::PictureInfo;
+
   PicturePileImpl();
-  explicit PicturePileImpl(const PicturePileBase* other);
+  explicit PicturePileImpl(const PicturePile* other);
   ~PicturePileImpl() override;
 
+  int buffer_pixels() const { return tiling_.border_texels(); }
+
+  PictureMap picture_map_;
+  TilingData tiling_;
+  SkColor background_color_;
+  bool contents_opaque_;
+  bool contents_fill_bounds_completely_;
+  bool is_solid_color_;
+  SkColor solid_color_;
+  gfx::Rect recorded_viewport_;
+  bool has_any_recordings_;
+  bool is_mask_;
+  bool clear_canvas_with_debug_color_;
+  float min_contents_scale_;
+  int slow_down_raster_scale_factor_for_debug_;
+
  private:
   typedef std::map<const Picture*, Region> PictureRegionMap;
 
@@ -112,7 +133,13 @@
       float contents_scale,
       bool is_analysis) const;
 
-  bool likely_to_be_used_for_transform_animation_;
+  // An internal CanRaster check that goes to the picture_map rather than
+  // using the recorded_viewport hint.
+  bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const;
+
+  gfx::Rect PaddedRect(const PictureMapKey& key) const;
+
+  bool should_attempt_to_use_distance_field_text_;
 
   DISALLOW_COPY_AND_ASSIGN(PicturePileImpl);
 };
diff --git a/cc/resources/picture_pile_unittest.cc b/cc/resources/picture_pile_unittest.cc
index 24bed3e..25e0d12 100644
--- a/cc/resources/picture_pile_unittest.cc
+++ b/cc/resources/picture_pile_unittest.cc
@@ -7,7 +7,7 @@
 
 #include "cc/resources/picture_pile.h"
 #include "cc/test/fake_content_layer_client.h"
-#include "cc/test/fake_rendering_stats_instrumentation.h"
+#include "cc/test/fake_picture_pile.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
@@ -15,26 +15,6 @@
 namespace cc {
 namespace {
 
-class TestPicturePile : public PicturePile {
- public:
-  ~TestPicturePile() override {}
-
-  using PicturePile::buffer_pixels;
-  using PicturePile::CanRasterSlowTileCheck;
-  using PicturePile::Clear;
-
-  PictureMap& picture_map() { return picture_map_; }
-  const gfx::Rect& recorded_viewport() const { return recorded_viewport_; }
-
-  bool CanRasterLayerRect(const gfx::Rect& layer_rect) {
-    return CanRaster(1.f, layer_rect);
-  }
-
-  typedef PicturePile::PictureInfo PictureInfo;
-  typedef PicturePile::PictureMapKey PictureMapKey;
-  typedef PicturePile::PictureMap PictureMap;
-};
-
 class PicturePileTestBase {
  public:
   PicturePileTestBase()
@@ -56,36 +36,29 @@
     UpdateAndExpandInvalidation(&invalidation, tiling_size, viewport_rect);
   }
 
-  gfx::Size tiling_size() const { return pile_.tiling_size(); }
-  gfx::Rect tiling_rect() const { return gfx::Rect(pile_.tiling_size()); }
+  gfx::Size tiling_size() const { return pile_.GetSize(); }
+  gfx::Rect tiling_rect() const { return gfx::Rect(pile_.GetSize()); }
 
   bool UpdateAndExpandInvalidation(Region* invalidation,
                                    const gfx::Size& layer_size,
                                    const gfx::Rect& visible_layer_rect) {
     frame_number_++;
-    return pile_.UpdateAndExpandInvalidation(&client_,
-                                             invalidation,
-                                             background_color_,
-                                             contents_opaque_,
-                                             false,
-                                             layer_size,
-                                             visible_layer_rect,
-                                             frame_number_,
-                                             Picture::RECORD_NORMALLY,
-                                             &stats_instrumentation_);
+    return pile_.UpdateAndExpandInvalidation(
+        &client_, invalidation, background_color_, contents_opaque_, false,
+        layer_size, visible_layer_rect, frame_number_,
+        Picture::RECORD_NORMALLY);
   }
 
   bool UpdateWholePile() {
     Region invalidation = tiling_rect();
-    bool result = UpdateAndExpandInvalidation(
-        &invalidation, tiling_size(), tiling_rect());
+    bool result = UpdateAndExpandInvalidation(&invalidation, tiling_size(),
+                                              tiling_rect());
     EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString());
     return result;
   }
 
   FakeContentLayerClient client_;
-  FakeRenderingStatsInstrumentation stats_instrumentation_;
-  TestPicturePile pile_;
+  FakePicturePile pile_;
   SkColor background_color_;
   float min_scale_;
   int frame_number_;
@@ -99,7 +72,7 @@
 
 TEST_F(PicturePileTest, InvalidationOnTileBorderOutsideInterestRect) {
   // Don't expand the interest rect past what we invalidate.
-  pile_.SetPixelRecordDistanceForTesting(0);
+  pile_.SetPixelRecordDistance(0);
 
   gfx::Size tile_size(100, 100);
   pile_.tiling().SetMaxTextureSize(tile_size);
@@ -182,8 +155,8 @@
   EXPECT_EQ(1, pile_.tiling().num_tiles_x());
   EXPECT_EQ(1, pile_.tiling().num_tiles_y());
 
-  TestPicturePile::PictureInfo& picture_info =
-      pile_.picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
+  FakePicturePile::PictureInfo& picture_info =
+      pile_.picture_map().find(FakePicturePile::PictureMapKey(0, 0))->second;
   // We should have a picture.
   EXPECT_TRUE(!!picture_info.GetPicture());
   gfx::Rect picture_rect = gfx::ScaleToEnclosedRect(
@@ -204,14 +177,14 @@
   EXPECT_EQ(1, pile_.tiling().num_tiles_x());
   EXPECT_EQ(1, pile_.tiling().num_tiles_y());
 
-  TestPicturePile::PictureInfo& picture_info =
-      pile_.picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
+  FakePicturePile::PictureInfo& picture_info =
+      pile_.picture_map().find(FakePicturePile::PictureMapKey(0, 0))->second;
   EXPECT_TRUE(!!picture_info.GetPicture());
 
   int expected_inflation = pile_.buffer_pixels();
 
   const Picture* base_picture = picture_info.GetPicture();
-  gfx::Rect base_picture_rect(pile_.tiling_size());
+  gfx::Rect base_picture_rect(tiling_size());
   base_picture_rect.Inset(-expected_inflation, -expected_inflation);
   EXPECT_EQ(base_picture_rect.ToString(),
             base_picture->LayerRect().ToString());
@@ -219,7 +192,7 @@
 
 TEST_F(PicturePileTest, InvalidateOnTileBoundaryInflated) {
   gfx::Size new_tiling_size =
-      gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 2.f));
+      gfx::ToCeiledSize(gfx::ScaleSize(tiling_size(), 2.f));
   // This creates initial pictures.
   SetTilingSize(new_tiling_size);
 
@@ -247,20 +220,20 @@
 
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureInfo& picture_info =
+      FakePicturePile::PictureInfo& picture_info =
           pile_.picture_map()
-              .find(TestPicturePile::PictureMapKey(i, j))
+              .find(FakePicturePile::PictureMapKey(i, j))
               ->second;
 
       // Expect (1, 1) and (1, 0) to be invalidated once more
       // than the rest of the tiles.
       if (i == 1 && (j == 0 || j == 1)) {
         EXPECT_FLOAT_EQ(
-            2.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
+            2.0f / FakePicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
             picture_info.GetInvalidationFrequencyForTesting());
       } else {
         EXPECT_FLOAT_EQ(
-            1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
+            1.0f / FakePicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
             picture_info.GetInvalidationFrequencyForTesting());
       }
     }
@@ -273,7 +246,7 @@
   // Everything was invalidated once so far.
   for (auto& it : pile_.picture_map()) {
     EXPECT_FLOAT_EQ(
-        1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
+        1.0f / FakePicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
         it.second.GetInvalidationFrequencyForTesting());
   }
 
@@ -284,14 +257,14 @@
   // Everything was invalidated again.
   for (auto& it : pile_.picture_map()) {
     EXPECT_FLOAT_EQ(
-        2.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
+        2.0f / FakePicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
         it.second.GetInvalidationFrequencyForTesting());
   }
 }
 
 TEST_F(PicturePileTest, StopRecordingOffscreenInvalidations) {
   gfx::Size new_tiling_size =
-      gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 4.f));
+      gfx::ToCeiledSize(gfx::ScaleSize(tiling_size(), 4.f));
   SetTilingSize(new_tiling_size);
 
   gfx::Rect viewport(tiling_size().width(), 1);
@@ -304,9 +277,9 @@
   // Make sure we have a high invalidation frequency.
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureInfo& picture_info =
+      FakePicturePile::PictureInfo& picture_info =
           pile_.picture_map()
-              .find(TestPicturePile::PictureMapKey(i, j))
+              .find(FakePicturePile::PictureMapKey(i, j))
               ->second;
       EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting())
           << "i " << i << " j " << j;
@@ -320,9 +293,9 @@
 
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureInfo& picture_info =
+      FakePicturePile::PictureInfo& picture_info =
           pile_.picture_map()
-              .find(TestPicturePile::PictureMapKey(i, j))
+              .find(FakePicturePile::PictureMapKey(i, j))
               ->second;
       EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting());
 
@@ -349,15 +322,15 @@
 
   // Now update with no invalidation and full viewport
   Region empty_invalidation;
-  UpdateAndExpandInvalidation(
-      &empty_invalidation, tiling_size(), tiling_rect());
+  UpdateAndExpandInvalidation(&empty_invalidation, tiling_size(),
+                              tiling_rect());
   EXPECT_EQ(Region().ToString(), empty_invalidation.ToString());
 
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureInfo& picture_info =
+      FakePicturePile::PictureInfo& picture_info =
           pile_.picture_map()
-              .find(TestPicturePile::PictureMapKey(i, j))
+              .find(FakePicturePile::PictureMapKey(i, j))
               ->second;
       // Expect the invalidation frequency to be less than 1, since we just
       // updated with no invalidations.
@@ -388,7 +361,7 @@
   // tiles touching it, but is true for adjacent tiles, even if it
   // overlaps on borders (edge case).
   gfx::Size new_tiling_size =
-      gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 4.f));
+      gfx::ToCeiledSize(gfx::ScaleSize(tiling_size(), 4.f));
   SetTilingSize(new_tiling_size);
 
   gfx::Rect tile01_borders = pile_.tiling().TileBoundsWithBorder(0, 1);
@@ -422,10 +395,10 @@
 
   // Sanity check some pictures exist and others don't.
   EXPECT_TRUE(pile_.picture_map()
-                  .find(TestPicturePile::PictureMapKey(0, 1))
+                  .find(FakePicturePile::PictureMapKey(0, 1))
                   ->second.GetPicture());
   EXPECT_FALSE(pile_.picture_map()
-                   .find(TestPicturePile::PictureMapKey(0, 2))
+                   .find(FakePicturePile::PictureMapKey(0, 2))
                    ->second.GetPicture());
 
   EXPECT_TRUE(pile_.CanRasterLayerRect(tile01_noborders));
@@ -454,8 +427,8 @@
 
   // No invalidation, changing viewport.
   invalidation = Region();
-  UpdateAndExpandInvalidation(
-      &invalidation, tiling_size(), gfx::Rect(5, 5, 5, 5));
+  UpdateAndExpandInvalidation(&invalidation, tiling_size(),
+                              gfx::Rect(5, 5, 5, 5));
   EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty());
   EXPECT_EQ(Region().ToString(), invalidation.ToString());
 }
@@ -604,9 +577,9 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
@@ -616,14 +589,15 @@
       grow_down_tiling_size,
       CornerSinglePixelRect(corner, grow_down_tiling_size));
 
-  // We should have lost the recordings in the bottom row.
+  // We should have lost all of the recordings in the bottom row as none of them
+  // are in the current interest rect (which is either the above or below it).
   EXPECT_EQ(6, pile_.tiling().num_tiles_x());
   EXPECT_EQ(8, pile_.tiling().num_tiles_y());
   for (int i = 0; i < 6; ++i) {
     for (int j = 0; j < 6; ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_EQ(j < 5, it != map.end() && it->second.GetPicture());
     }
   }
@@ -645,20 +619,58 @@
                               base_tiling_size,
                               CornerSinglePixelRect(corner, base_tiling_size));
 
-  // We should have lost the recordings that are now outside the tiling only.
+  // When shrinking, we should have lost all the recordings in the bottom row
+  // not touching the interest rect.
   EXPECT_EQ(6, pile_.tiling().num_tiles_x());
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
-      EXPECT_EQ(j < 6, it != map.end() && it->second.GetPicture());
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
+      bool expect_tile;
+      switch (corner) {
+        case TOP_LEFT:
+        case TOP_RIGHT:
+          expect_tile = j < 5;
+          break;
+        case BOTTOM_LEFT:
+          // The interest rect in the bottom left tile means we'll record it.
+          expect_tile = j < 5 || (j == 5 && i == 0);
+          break;
+        case BOTTOM_RIGHT:
+          // The interest rect in the bottom right tile means we'll record it.
+          expect_tile = j < 5 || (j == 5 && i == 5);
+          break;
+      }
+      EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
     }
   }
 
-  // No invalidation when shrinking.
-  expected_invalidation.Clear();
+  // When shrinking, the previously exposed region is invalidated.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  // The whole bottom row of tiles (except any with the interest rect) are
+  // dropped.
+  gfx::Rect bottom_row_minus_existing_corner = gfx::UnionRects(
+      pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5));
+  switch (corner) {
+    case TOP_LEFT:
+    case TOP_RIGHT:
+      // No tiles are kept in the changed region because it doesn't
+      // intersect with the interest rect.
+      break;
+    case BOTTOM_LEFT:
+      bottom_row_minus_existing_corner.Subtract(
+          pile_.tiling().TileBounds(0, 5));
+      break;
+    case BOTTOM_RIGHT:
+      bottom_row_minus_existing_corner.Subtract(
+          pile_.tiling().TileBounds(5, 5));
+      break;
+  }
+
+  expected_invalidation.Union(bottom_row_minus_existing_corner);
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
@@ -668,14 +680,16 @@
       grow_right_tiling_size,
       CornerSinglePixelRect(corner, grow_right_tiling_size));
 
-  // We should have lost the recordings in the right column.
+  // We should have lost all of the recordings in the right column as none of
+  // them are in the current interest rect (which is either entirely left or
+  // right of it).
   EXPECT_EQ(8, pile_.tiling().num_tiles_x());
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < 6; ++i) {
     for (int j = 0; j < 6; ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_EQ(i < 5, it != map.end() && it->second.GetPicture());
     }
   }
@@ -697,20 +711,57 @@
                               base_tiling_size,
                               CornerSinglePixelRect(corner, base_tiling_size));
 
-  // We should have lost the recordings that are now outside the tiling only.
+  // When shrinking, we should have lost all the recordings in the right column
+  // not touching the interest rect.
   EXPECT_EQ(6, pile_.tiling().num_tiles_x());
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
-      EXPECT_EQ(i < 6, it != map.end() && it->second.GetPicture());
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
+      bool expect_tile;
+      switch (corner) {
+        case TOP_LEFT:
+        case BOTTOM_LEFT:
+          // No tiles are kept in the changed region because it doesn't
+          // intersect with the interest rect.
+          expect_tile = i < 5;
+          break;
+        case TOP_RIGHT:
+          // The interest rect in the top right tile means we'll record it.
+          expect_tile = i < 5 || (j == 0 && i == 5);
+          break;
+        case BOTTOM_RIGHT:
+          // The interest rect in the bottom right tile means we'll record it.
+          expect_tile = i < 5 || (j == 5 && i == 5);
+          break;
+      }
+      EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
     }
   }
 
-  // No invalidation when shrinking.
-  expected_invalidation.Clear();
+  // When shrinking, the previously exposed region is invalidated.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  // The whole right column of tiles (except for ones with the interest rect)
+  // are dropped.
+  gfx::Rect right_column_minus_existing_corner = gfx::UnionRects(
+      pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5));
+  switch (corner) {
+    case TOP_LEFT:
+    case BOTTOM_LEFT:
+      break;
+    case TOP_RIGHT:
+      right_column_minus_existing_corner.Subtract(
+          pile_.tiling().TileBounds(5, 0));
+      break;
+    case BOTTOM_RIGHT:
+      right_column_minus_existing_corner.Subtract(
+          pile_.tiling().TileBounds(5, 5));
+      break;
+  }
+  expected_invalidation.Union(right_column_minus_existing_corner);
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
@@ -725,9 +776,9 @@
   EXPECT_EQ(8, pile_.tiling().num_tiles_y());
   for (int i = 0; i < 6; ++i) {
     for (int j = 0; j < 6; ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_EQ(i < 5 && j < 5, it != map.end() && it->second.GetPicture());
     }
   }
@@ -735,7 +786,7 @@
   // We invalidated all new pixels in the recording.
   expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size),
                                           gfx::Rect(base_tiling_size));
-  // But the new pixels don't cover the whole right_column.
+  // But the new pixels don't cover the whole right column or bottom row.
   Region right_column_and_bottom_row =
       UnionRegions(gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
                                    pile_.tiling().TileBounds(5, 5)),
@@ -748,22 +799,66 @@
   invalidation.Clear();
 
   UpdateWholePile();
-  UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect());
+  UpdateAndExpandInvalidation(&invalidation, base_tiling_size,
+                              CornerSinglePixelRect(corner, base_tiling_size));
 
-  // We should have lost the recordings that are now outside the tiling only.
+  // We should have lost the recordings in the right column and bottom row,
+  // except where it intersects the interest rect.
   EXPECT_EQ(6, pile_.tiling().num_tiles_x());
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
-      EXPECT_EQ(i < 6 && j < 6, it != map.end() && it->second.GetPicture());
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
+      bool expect_tile;
+      switch (corner) {
+        case TOP_LEFT:
+          expect_tile = i < 5 && j < 5;
+          break;
+        case TOP_RIGHT:
+          // The interest rect in the top right tile means we'll record it.
+          expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5);
+          break;
+        case BOTTOM_LEFT:
+          // The interest rect in the bottom left tile means we'll record it.
+          expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0);
+          break;
+        case BOTTOM_RIGHT:
+          // The interest rect in the bottom right tile means we'll record it.
+          expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5);
+          break;
+      }
+      EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture())
+          << i << "," << j;
     }
   }
 
-  // No invalidation when shrinking.
-  expected_invalidation.Clear();
+  // We invalidated all previous pixels in the recording.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  // The whole right column and bottom row of tiles (except for ones with the
+  // interest rect) are dropped.
+  Region right_column_and_bottom_row_minus_existing_corner =
+      right_column_and_bottom_row;
+  switch (corner) {
+    case TOP_LEFT:
+      break;
+    case BOTTOM_LEFT:
+      right_column_and_bottom_row_minus_existing_corner.Subtract(
+          pile_.tiling().TileBounds(0, 5));
+      break;
+    case TOP_RIGHT:
+      right_column_and_bottom_row_minus_existing_corner.Subtract(
+          pile_.tiling().TileBounds(5, 0));
+      break;
+    case BOTTOM_RIGHT:
+      right_column_and_bottom_row_minus_existing_corner.Subtract(
+          pile_.tiling().TileBounds(5, 5));
+      break;
+  }
+  expected_invalidation.Union(
+      right_column_and_bottom_row_minus_existing_corner);
   EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 }
@@ -796,268 +891,235 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
 
-  UpdateAndExpandInvalidation(
-      &invalidation,
-      grow_down_tiling_size,
-      CornerSinglePixelRect(corner, grow_down_tiling_size));
+  // In this test (unlike the large resize test), as all growing and shrinking
+  // happens within tiles, the resulting invalidation is symmetrical, so use
+  // this enum to repeat the test both ways.
+  enum ChangeDirection { GROW, SHRINK, LAST_DIRECTION = SHRINK };
 
-  // We should have lost the recordings in the bottom row that do not intersect
-  // the interest rect.
-  EXPECT_EQ(6, pile_.tiling().num_tiles_x());
-  EXPECT_EQ(6, pile_.tiling().num_tiles_y());
-  for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
-    for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
-      bool expect_tile;
+  // Grow downward.
+  for (int dir = 0; dir <= LAST_DIRECTION; ++dir) {
+    gfx::Size new_tiling_size =
+        dir == GROW ? grow_down_tiling_size : base_tiling_size;
+    UpdateWholePile();
+    UpdateAndExpandInvalidation(&invalidation, new_tiling_size,
+                                CornerSinglePixelRect(corner, new_tiling_size));
+
+    // We should have lost the recordings in the bottom row that do not
+    // intersect the interest rect.
+    EXPECT_EQ(6, pile_.tiling().num_tiles_x());
+    EXPECT_EQ(6, pile_.tiling().num_tiles_y());
+    for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
+      for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
+        FakePicturePile::PictureMapKey key(i, j);
+        FakePicturePile::PictureMap& map = pile_.picture_map();
+        FakePicturePile::PictureMap::iterator it = map.find(key);
+        bool expect_tile;
+        switch (corner) {
+          case TOP_LEFT:
+          case TOP_RIGHT:
+            expect_tile = j < 5;
+            break;
+          case BOTTOM_LEFT:
+            // The interest rect in the bottom left tile means we'll record it.
+            expect_tile = j < 5 || (j == 5 && i == 0);
+            break;
+          case BOTTOM_RIGHT:
+            // The interest rect in the bottom right tile means we'll record it.
+            expect_tile = j < 5 || (j == 5 && i == 5);
+            break;
+        }
+        EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
+      }
+    }
+
+    // We invalidated the bottom row outside the new interest rect. The tile
+    // that insects the interest rect in invalidated only on its newly
+    // exposed or previously exposed pixels.
+    if (dir == GROW) {
+      // Only calculate the expected invalidation while growing, as the tile
+      // bounds post-growing is the newly exposed / previously exposed sizes.
+      // Post-shrinking, the tile bounds are smaller, so can't be used.
       switch (corner) {
         case TOP_LEFT:
         case TOP_RIGHT:
-          expect_tile = j < 5;
+          expected_invalidation = gfx::UnionRects(
+              pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5));
           break;
         case BOTTOM_LEFT:
-          // The interest rect in the bottom left tile means we'll record it.
-          expect_tile = j < 5 || (j == 5 && i == 0);
+          expected_invalidation = gfx::UnionRects(
+              pile_.tiling().TileBounds(1, 5), pile_.tiling().TileBounds(5, 5));
+          expected_invalidation.Union(SubtractRects(
+              pile_.tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size)));
           break;
         case BOTTOM_RIGHT:
-          // The interest rect in the bottom right tile means we'll record it.
-          expect_tile = j < 5 || (j == 5 && i == 5);
+          expected_invalidation = gfx::UnionRects(
+              pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(4, 5));
+          expected_invalidation.Union(SubtractRects(
+              pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
           break;
       }
-      EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
     }
+    EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
+    invalidation.Clear();
   }
 
-  // We invalidated the bottom row outside the new interest rect. The tile that
-  // insects the interest rect in invalidated only on its new pixels.
-  switch (corner) {
-    case TOP_LEFT:
-    case TOP_RIGHT:
-      expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(0, 5),
-                                              pile_.tiling().TileBounds(5, 5));
-      break;
-    case BOTTOM_LEFT:
-      expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(1, 5),
-                                              pile_.tiling().TileBounds(5, 5));
-      expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(0, 5),
-                                                gfx::Rect(base_tiling_size)));
-      break;
-    case BOTTOM_RIGHT:
-      expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(0, 5),
-                                              pile_.tiling().TileBounds(4, 5));
-      expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 5),
-                                                gfx::Rect(base_tiling_size)));
-      break;
-  }
-  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
-  invalidation.Clear();
+  // Grow right.
+  for (int dir = 0; dir <= LAST_DIRECTION; ++dir) {
+    gfx::Size new_tiling_size =
+        dir == GROW ? grow_right_tiling_size : base_tiling_size;
+    UpdateWholePile();
+    UpdateAndExpandInvalidation(&invalidation, new_tiling_size,
+                                CornerSinglePixelRect(corner, new_tiling_size));
 
-  UpdateWholePile();
-  UpdateAndExpandInvalidation(&invalidation,
-                              base_tiling_size,
-                              CornerSinglePixelRect(corner, base_tiling_size));
-
-  // We should have lost nothing.
-  EXPECT_EQ(6, pile_.tiling().num_tiles_x());
-  EXPECT_EQ(6, pile_.tiling().num_tiles_y());
-  for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
-    for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
-      EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+    // We should have lost the recordings in the right column.
+    EXPECT_EQ(6, pile_.tiling().num_tiles_x());
+    EXPECT_EQ(6, pile_.tiling().num_tiles_y());
+    for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
+      for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
+        FakePicturePile::PictureMapKey key(i, j);
+        FakePicturePile::PictureMap& map = pile_.picture_map();
+        FakePicturePile::PictureMap::iterator it = map.find(key);
+        bool expect_tile;
+        switch (corner) {
+          case TOP_LEFT:
+          case BOTTOM_LEFT:
+            expect_tile = i < 5;
+            break;
+          case TOP_RIGHT:
+            // The interest rect in the top right tile means we'll record it.
+            expect_tile = i < 5 || (j == 0 && i == 5);
+            break;
+          case BOTTOM_RIGHT:
+            // The interest rect in the bottom right tile means we'll record it.
+            expect_tile = i < 5 || (j == 5 && i == 5);
+            break;
+        }
+        EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
+      }
     }
-  }
 
-  // We invalidated nothing.
-  expected_invalidation.Clear();
-  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
-  invalidation.Clear();
-
-  UpdateWholePile();
-  UpdateAndExpandInvalidation(
-      &invalidation,
-      grow_right_tiling_size,
-      CornerSinglePixelRect(corner, grow_right_tiling_size));
-
-  // We should have lost the recordings in the right column.
-  EXPECT_EQ(6, pile_.tiling().num_tiles_x());
-  EXPECT_EQ(6, pile_.tiling().num_tiles_y());
-  for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
-    for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
-      bool expect_tile;
+    // We invalidated the right column outside the new interest rect. The tile
+    // that insects the interest rect in invalidated only on its new or
+    // previously exposed pixels.
+    if (dir == GROW) {
+      // Calculate the expected invalidation the first time through the loop.
       switch (corner) {
         case TOP_LEFT:
         case BOTTOM_LEFT:
-          expect_tile = i < 5;
+          expected_invalidation = gfx::UnionRects(
+              pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5));
           break;
         case TOP_RIGHT:
-          // The interest rect in the top right tile means we'll record it.
-          expect_tile = i < 5 || (j == 0 && i == 5);
+          expected_invalidation = gfx::UnionRects(
+              pile_.tiling().TileBounds(5, 1), pile_.tiling().TileBounds(5, 5));
+          expected_invalidation.Union(SubtractRects(
+              pile_.tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size)));
           break;
         case BOTTOM_RIGHT:
-          // The interest rect in the bottom right tile means we'll record it.
-          expect_tile = i < 5 || (j == 5 && i == 5);
+          expected_invalidation = gfx::UnionRects(
+              pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 4));
+          expected_invalidation.Union(SubtractRects(
+              pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
           break;
       }
-      EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
     }
+    EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
+    invalidation.Clear();
   }
 
-  // We invalidated the right column outside the new interest rect. The tile
-  // that insects the interest rect in invalidated only on its new pixels.
-  switch (corner) {
-    case TOP_LEFT:
-    case BOTTOM_LEFT:
-      expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
-                                              pile_.tiling().TileBounds(5, 5));
-      break;
-    case TOP_RIGHT:
-      expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 1),
-                                              pile_.tiling().TileBounds(5, 5));
-      expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 0),
-                                                gfx::Rect(base_tiling_size)));
-      break;
-    case BOTTOM_RIGHT:
-      expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
-                                              pile_.tiling().TileBounds(5, 4));
-      expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 5),
-                                                gfx::Rect(base_tiling_size)));
-      break;
-  }
-  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
-  invalidation.Clear();
+  // Grow both.
+  for (int dir = 0; dir <= LAST_DIRECTION; ++dir) {
+    gfx::Size new_tiling_size =
+        dir == GROW ? grow_both_tiling_size : base_tiling_size;
+    UpdateWholePile();
+    UpdateAndExpandInvalidation(&invalidation, new_tiling_size,
+                                CornerSinglePixelRect(corner, new_tiling_size));
 
-  UpdateWholePile();
-  UpdateAndExpandInvalidation(&invalidation,
-                              base_tiling_size,
-                              CornerSinglePixelRect(corner, base_tiling_size));
-
-  // We should have lost nothing.
-  EXPECT_EQ(6, pile_.tiling().num_tiles_x());
-  EXPECT_EQ(6, pile_.tiling().num_tiles_y());
-  for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
-    for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
-      EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+    // We should have lost the recordings in the right column and bottom row.
+    // The tile that insects the interest rect in invalidated only on its new
+    // or previously exposed pixels.
+    EXPECT_EQ(6, pile_.tiling().num_tiles_x());
+    EXPECT_EQ(6, pile_.tiling().num_tiles_y());
+    for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
+      for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
+        FakePicturePile::PictureMapKey key(i, j);
+        FakePicturePile::PictureMap& map = pile_.picture_map();
+        FakePicturePile::PictureMap::iterator it = map.find(key);
+        bool expect_tile;
+        switch (corner) {
+          case TOP_LEFT:
+            expect_tile = i < 5 && j < 5;
+            break;
+          case TOP_RIGHT:
+            // The interest rect in the top right tile means we'll record it.
+            expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5);
+            break;
+          case BOTTOM_LEFT:
+            // The interest rect in the bottom left tile means we'll record it.
+            expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0);
+            break;
+          case BOTTOM_RIGHT:
+            // The interest rect in the bottom right tile means we'll record it.
+            expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5);
+            break;
+        }
+        EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture())
+            << i << "," << j;
+      }
     }
-  }
 
-  // We invalidated nothing.
-  expected_invalidation.Clear();
-  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
-  invalidation.Clear();
-
-  UpdateWholePile();
-  UpdateAndExpandInvalidation(
-      &invalidation,
-      grow_both_tiling_size,
-      CornerSinglePixelRect(corner, grow_both_tiling_size));
-
-  // We should have lost the recordings in the right column and bottom row. The
-  // tile that insects the interest rect in invalidated only on its new pixels.
-  EXPECT_EQ(6, pile_.tiling().num_tiles_x());
-  EXPECT_EQ(6, pile_.tiling().num_tiles_y());
-  for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
-    for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
-      bool expect_tile;
+    // We invalidated the right column and the bottom row outside the new
+    // interest rect. The tile that insects the interest rect in invalidated
+    // only on its new or previous exposed pixels.
+    if (dir == GROW) {
+      // Calculate the expected invalidation the first time through the loop.
       switch (corner) {
         case TOP_LEFT:
-          expect_tile = i < 5 && j < 5;
+          expected_invalidation = gfx::UnionRects(
+              pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5));
+          expected_invalidation.Union(
+              gfx::UnionRects(pile_.tiling().TileBounds(0, 5),
+                              pile_.tiling().TileBounds(5, 5)));
           break;
         case TOP_RIGHT:
-          // The interest rect in the top right tile means we'll record it.
-          expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5);
+          expected_invalidation = gfx::UnionRects(
+              pile_.tiling().TileBounds(5, 1), pile_.tiling().TileBounds(5, 5));
+          expected_invalidation.Union(
+              gfx::UnionRects(pile_.tiling().TileBounds(0, 5),
+                              pile_.tiling().TileBounds(5, 5)));
+          expected_invalidation.Union(SubtractRects(
+              pile_.tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size)));
           break;
         case BOTTOM_LEFT:
-          // The interest rect in the bottom left tile means we'll record it.
-          expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0);
+          expected_invalidation = gfx::UnionRects(
+              pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5));
+          expected_invalidation.Union(
+              gfx::UnionRects(pile_.tiling().TileBounds(1, 5),
+                              pile_.tiling().TileBounds(5, 5)));
+          expected_invalidation.Union(SubtractRects(
+              pile_.tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size)));
           break;
         case BOTTOM_RIGHT:
-          // The interest rect in the bottom right tile means we'll record it.
-          expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5);
+          expected_invalidation = gfx::UnionRects(
+              pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 4));
+          expected_invalidation.Union(
+              gfx::UnionRects(pile_.tiling().TileBounds(0, 5),
+                              pile_.tiling().TileBounds(4, 5)));
+          expected_invalidation.Union(SubtractRegions(
+              pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
           break;
       }
-      EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture())
-          << i << "," << j;
     }
+    EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
+    invalidation.Clear();
   }
-
-  // We invalidated the right column and the bottom row outside the new interest
-  // rect. The tile that insects the interest rect in invalidated only on its
-  // new pixels.
-  switch (corner) {
-    case TOP_LEFT:
-      expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
-                                              pile_.tiling().TileBounds(5, 5));
-      expected_invalidation.Union(gfx::UnionRects(
-          pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5)));
-      break;
-    case TOP_RIGHT:
-      expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 1),
-                                              pile_.tiling().TileBounds(5, 5));
-      expected_invalidation.Union(gfx::UnionRects(
-          pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5)));
-      expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 0),
-                                                gfx::Rect(base_tiling_size)));
-      break;
-    case BOTTOM_LEFT:
-      expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
-                                              pile_.tiling().TileBounds(5, 5));
-      expected_invalidation.Union(gfx::UnionRects(
-          pile_.tiling().TileBounds(1, 5), pile_.tiling().TileBounds(5, 5)));
-      expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(0, 5),
-                                                gfx::Rect(base_tiling_size)));
-      break;
-    case BOTTOM_RIGHT:
-      expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
-                                              pile_.tiling().TileBounds(5, 4));
-      expected_invalidation.Union(gfx::UnionRects(
-          pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(4, 5)));
-      expected_invalidation.Union(SubtractRegions(
-          pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
-      break;
-  }
-  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
-  invalidation.Clear();
-
-  UpdateWholePile();
-  UpdateAndExpandInvalidation(&invalidation,
-                              base_tiling_size,
-                              CornerSinglePixelRect(corner, base_tiling_size));
-
-  // We should have lost nothing.
-  EXPECT_EQ(6, pile_.tiling().num_tiles_x());
-  EXPECT_EQ(6, pile_.tiling().num_tiles_y());
-  for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
-    for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
-      EXPECT_TRUE(it != map.end() && it->second.GetPicture());
-    }
-  }
-
-  // We invalidated nothing.
-  expected_invalidation.Clear();
-  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
-  invalidation.Clear();
 }
 
 INSTANTIATE_TEST_CASE_P(
@@ -1086,9 +1148,9 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
@@ -1101,9 +1163,9 @@
   EXPECT_EQ(8, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
@@ -1127,15 +1189,18 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
 
-  // No invalidation when shrinking.
-  EXPECT_EQ(Region().ToString(), invalidation.ToString());
+  // We invalidated the previously exposed pixels on the bottom row of tiles.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  EXPECT_TRUE(expected_invalidation.Contains(bottom_row_new_pixels));
+  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
   UpdateWholePile();
@@ -1147,9 +1212,9 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
@@ -1173,15 +1238,18 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
 
-  // No invalidation when shrinking.
-  EXPECT_EQ(Region().ToString(), invalidation.ToString());
+  // We invalidated the previously exposed pixels on the right column of tiles.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  EXPECT_TRUE(expected_invalidation.Contains(right_column_new_pixels));
+  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
   UpdateWholePile();
@@ -1193,9 +1261,9 @@
   EXPECT_EQ(8, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
@@ -1223,15 +1291,20 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
 
-  // No invalidation when shrinking.
-  EXPECT_EQ(Region().ToString(), invalidation.ToString());
+  // We invalidated the previously exposed pixels on the bottom row and right
+  // column of tiles.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  EXPECT_TRUE(
+      expected_invalidation.Contains(bottom_row_and_right_column_new_pixels));
+  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 }
 
@@ -1256,9 +1329,9 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
@@ -1271,9 +1344,9 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
@@ -1292,15 +1365,17 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
 
-  // No invalidation when shrinking.
-  EXPECT_EQ(Region().ToString(), invalidation.ToString());
+  // We invalidated the previously exposed pixels.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
   UpdateWholePile();
@@ -1312,9 +1387,9 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
@@ -1333,15 +1408,17 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
 
-  // No invalidation when shrinking.
-  EXPECT_EQ(Region().ToString(), invalidation.ToString());
+  // We invalidated the previously exposed pixels.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 
   UpdateWholePile();
@@ -1353,9 +1430,9 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
@@ -1374,15 +1451,17 @@
   EXPECT_EQ(6, pile_.tiling().num_tiles_y());
   for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
     for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
-      TestPicturePile::PictureMapKey key(i, j);
-      TestPicturePile::PictureMap& map = pile_.picture_map();
-      TestPicturePile::PictureMap::iterator it = map.find(key);
+      FakePicturePile::PictureMapKey key(i, j);
+      FakePicturePile::PictureMap& map = pile_.picture_map();
+      FakePicturePile::PictureMap::iterator it = map.find(key);
       EXPECT_TRUE(it != map.end() && it->second.GetPicture());
     }
   }
 
-  // No invalidation when shrinking.
-  EXPECT_EQ(Region().ToString(), invalidation.ToString());
+  // We invalidated the previously exposed pixels.
+  expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size),
+                                          gfx::Rect(base_tiling_size));
+  EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
   invalidation.Clear();
 }
 
@@ -1458,12 +1537,12 @@
 
 TEST_F(PicturePileTest, SetEmptyBounds) {
   EXPECT_TRUE(pile_.is_solid_color());
-  EXPECT_FALSE(pile_.tiling_size().IsEmpty());
+  EXPECT_FALSE(pile_.GetSize().IsEmpty());
   EXPECT_FALSE(pile_.picture_map().empty());
   EXPECT_TRUE(pile_.HasRecordings());
   pile_.SetEmptyBounds();
   EXPECT_FALSE(pile_.is_solid_color());
-  EXPECT_TRUE(pile_.tiling_size().IsEmpty());
+  EXPECT_TRUE(pile_.GetSize().IsEmpty());
   EXPECT_TRUE(pile_.picture_map().empty());
   EXPECT_FALSE(pile_.HasRecordings());
 }
diff --git a/cc/resources/raster_source.h b/cc/resources/raster_source.h
index 3e25408..f7ea271 100644
--- a/cc/resources/raster_source.h
+++ b/cc/resources/raster_source.h
@@ -9,9 +9,12 @@
 
 #include "base/memory/ref_counted.h"
 #include "cc/base/cc_export.h"
+#include "cc/debug/traced_value.h"
+#include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkColor.h"
 
 class SkCanvas;
+class SkPicture;
 
 namespace cc {
 
@@ -30,10 +33,19 @@
   // assumed that contents_scale has already been applied to this canvas.
   // Writes the total number of pixels rasterized and the time spent
   // rasterizing to the stats if the respective pointer is not nullptr.
+  // It is assumed that the canvas passed here will only be rasterized by
+  // this raster source via this call.
   virtual void PlaybackToCanvas(SkCanvas* canvas,
                                 const gfx::Rect& canvas_rect,
                                 float contents_scale) const = 0;
 
+  // Similar to above, except that the canvas passed here can (or was already)
+  // rasterized into by another raster source. That is, it is not safe to clear
+  // the canvas or discard its underlying memory.
+  virtual void PlaybackToSharedCanvas(SkCanvas* canvas,
+                                      const gfx::Rect& canvas_rect,
+                                      float contents_scale) const = 0;
+
   // Analyze to determine if the given rect at given scale is of solid color in
   // this raster source.
   virtual void PerformSolidColorAnalysis(
@@ -41,6 +53,16 @@
       float contents_scale,
       SolidColorAnalysis* analysis) const = 0;
 
+  // Returns true iff the whole raster source is of solid color.
+  virtual bool IsSolidColor() const = 0;
+
+  // Returns the color of the raster source if it is solid color. The results
+  // are unspecified if IsSolidColor returns false.
+  virtual SkColor GetSolidColor() const = 0;
+
+  // Returns the size of this raster source.
+  virtual gfx::Size GetSize() const = 0;
+
   // Populate the given list with all SkPixelRefs that may overlap the given
   // rect at given scale.
   virtual void GatherPixelRefs(const gfx::Rect& content_rect,
@@ -52,9 +74,24 @@
   virtual bool CoversRect(const gfx::Rect& content_rect,
                           float contents_scale) const = 0;
 
+  // Returns true if this raster source has anything to rasterize.
+  virtual bool HasRecordings() const = 0;
+
+  // Informs the raster source that it should attempt to use distance field text
+  // during rasterization.
+  virtual void SetShouldAttemptToUseDistanceFieldText() = 0;
+
   // Return true iff this raster source would benefit from using distance
   // field text.
-  virtual bool SuitableForDistanceFieldText() const = 0;
+  virtual bool ShouldAttemptToUseDistanceFieldText() const = 0;
+
+  // Tracing functionality.
+  virtual void DidBeginTracing() = 0;
+  virtual void AsValueInto(base::debug::TracedValue* array) const = 0;
+  virtual skia::RefPtr<SkPicture> GetFlattenedPicture() = 0;
+
+  // TODO(vmpstr): This should be a layer property.
+  virtual bool IsMask() const = 0;
 
  protected:
   friend class base::RefCountedThreadSafe<RasterSource>;
diff --git a/cc/resources/raster_worker_pool_perftest.cc b/cc/resources/raster_worker_pool_perftest.cc
index 0f7a845..fdec054 100644
--- a/cc/resources/raster_worker_pool_perftest.cc
+++ b/cc/resources/raster_worker_pool_perftest.cc
@@ -167,7 +167,7 @@
  public:
   typedef std::vector<scoped_refptr<RasterTask>> RasterTaskVector;
 
-  enum NamedTaskSet { REQUIRED_FOR_ACTIVATION = 0, ALL = 1 };
+  enum NamedTaskSet { ALL, REQUIRED_FOR_ACTIVATION, REQUIRED_FOR_DRAW };
 
   RasterWorkerPoolPerfTestBase()
       : context_provider_(make_scoped_refptr(new PerfContextProvider)),
diff --git a/cc/resources/raster_worker_pool_unittest.cc b/cc/resources/raster_worker_pool_unittest.cc
index 9aee8e7..775acda 100644
--- a/cc/resources/raster_worker_pool_unittest.cc
+++ b/cc/resources/raster_worker_pool_unittest.cc
@@ -121,7 +121,7 @@
 
   typedef std::vector<scoped_refptr<RasterTask>> RasterTaskVector;
 
-  enum NamedTaskSet { REQUIRED_FOR_ACTIVATION = 0, ALL = 1 };
+  enum NamedTaskSet { ALL, REQUIRED_FOR_ACTIVATION, REQUIRED_FOR_DRAW };
 
   RasterWorkerPoolTest()
       : context_provider_(TestContextProvider::Create()),
diff --git a/cc/resources/rasterizer.h b/cc/resources/rasterizer.h
index 526058c..db84c22 100644
--- a/cc/resources/rasterizer.h
+++ b/cc/resources/rasterizer.h
@@ -87,7 +87,11 @@
   ImageDecodeTask::Vector dependencies_;
 };
 
-static const size_t kNumberOfTaskSets = 2;
+// kNumberOfTaskSets must be greater or equal to the number of values in
+// TileManager::NamedTaskSet.
+// TODO(reveman): Use template specialization to make it easy for client code to
+// check at compile time that the number of supported task sets is correct.
+static const size_t kNumberOfTaskSets = 3;
 typedef size_t TaskSet;
 typedef std::bitset<kNumberOfTaskSets> TaskSetCollection;
 
diff --git a/cc/resources/recording_source.h b/cc/resources/recording_source.h
new file mode 100644
index 0000000..cbbeb70
--- /dev/null
+++ b/cc/resources/recording_source.h
@@ -0,0 +1,55 @@
+// 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_RECORDING_SOURCE_H_
+#define CC_RESOURCES_RECORDING_SOURCE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/resources/picture.h"
+#include "third_party/skia/include/core/SkBBHFactory.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace cc {
+class ContentLayerClient;
+class Region;
+class RasterSource;
+
+class CC_EXPORT RecordingSource {
+ public:
+  virtual ~RecordingSource() {}
+  // Re-record parts of the picture that are invalid.
+  // Invalidations are in layer space, and will be expanded to cover everything
+  // that was either recorded/changed or that has no recording, leaving out only
+  // pieces that we had a recording for and it was not changed.
+  // Return true iff the pile was modified.
+  virtual bool UpdateAndExpandInvalidation(
+      ContentLayerClient* painter,
+      Region* invalidation,
+      SkColor background_color,
+      bool contents_opaque,
+      bool contents_fill_bounds_completely,
+      const gfx::Size& layer_size,
+      const gfx::Rect& visible_layer_rect,
+      int frame_number,
+      Picture::RecordingMode recording_mode) = 0;
+
+  virtual gfx::Size GetSize() const = 0;
+  virtual void SetEmptyBounds() = 0;
+  virtual void SetMinContentsScale(float min_contents_scale) = 0;
+  virtual void SetTileGridSize(const gfx::Size& tile_grid_size) = 0;
+  virtual void SetSlowdownRasterScaleFactor(int factor) = 0;
+  virtual void SetIsMask(bool is_mask) = 0;
+  virtual bool IsSuitableForGpuRasterization() const = 0;
+
+  virtual scoped_refptr<RasterSource> CreateRasterSource() const = 0;
+
+  // TODO(hendrikw): Figure out how to remove this.
+  virtual void SetUnsuitableForGpuRasterizationForTesting() = 0;
+  virtual SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const = 0;
+};
+}
+
+#endif  // CC_RESOURCES_RECORDING_SOURCE_H_
diff --git a/cc/resources/skpicture_content_layer_updater.cc b/cc/resources/skpicture_content_layer_updater.cc
index bd524f2..3e6828f 100644
--- a/cc/resources/skpicture_content_layer_updater.cc
+++ b/cc/resources/skpicture_content_layer_updater.cc
@@ -16,9 +16,9 @@
 
 SkPictureContentLayerUpdater::SkPictureContentLayerUpdater(
     scoped_ptr<LayerPainter> painter,
-    RenderingStatsInstrumentation* stats_instrumentation,
     int layer_id)
-    : ContentLayerUpdater(painter.Pass(), stats_instrumentation, layer_id) {}
+    : ContentLayerUpdater(painter.Pass(), layer_id) {
+}
 
 SkPictureContentLayerUpdater::~SkPictureContentLayerUpdater() {}
 
@@ -33,17 +33,11 @@
       recorder.beginRecording(paint_rect.width(), paint_rect.height(), NULL, 0);
   DCHECK_EQ(paint_rect.width(), canvas->getBaseLayerSize().width());
   DCHECK_EQ(paint_rect.height(), canvas->getBaseLayerSize().height());
-  base::TimeTicks start_time =
-      rendering_stats_instrumentation_->StartRecording();
   PaintContents(canvas,
                 content_size,
                 paint_rect,
                 contents_width_scale,
                 contents_height_scale);
-  base::TimeDelta duration =
-      rendering_stats_instrumentation_->EndRecording(start_time);
-  rendering_stats_instrumentation_->AddRecord(
-      duration, paint_rect.width() * paint_rect.height());
   picture_ = skia::AdoptRef(recorder.endRecording());
 }
 
diff --git a/cc/resources/skpicture_content_layer_updater.h b/cc/resources/skpicture_content_layer_updater.h
index ec49aae..33480a8 100644
--- a/cc/resources/skpicture_content_layer_updater.h
+++ b/cc/resources/skpicture_content_layer_updater.h
@@ -21,7 +21,6 @@
  protected:
   SkPictureContentLayerUpdater(
       scoped_ptr<LayerPainter> painter,
-      RenderingStatsInstrumentation* stats_instrumentation,
       int layer_id);
   ~SkPictureContentLayerUpdater() override;
 
diff --git a/cc/resources/tile.cc b/cc/resources/tile.cc
index d6bd3c4..4cbc758 100644
--- a/cc/resources/tile.cc
+++ b/cc/resources/tile.cc
@@ -36,6 +36,7 @@
       tiling_i_index_(-1),
       tiling_j_index_(-1),
       required_for_activation_(false),
+      required_for_draw_(false),
       id_(s_next_id_++) {
   set_raster_source(raster_source);
   for (int i = 0; i < NUM_TREES; i++)
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index c641367..042d5ae 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -85,6 +85,10 @@
   void set_required_for_activation(bool is_required) {
     required_for_activation_ = is_required;
   }
+  bool required_for_draw() const { return required_for_draw_; }
+  void set_required_for_draw(bool is_required) {
+    required_for_draw_ = is_required;
+  }
 
   bool use_picture_analysis() const {
     return !!(flags_ & USE_PICTURE_ANALYSIS);
@@ -174,6 +178,7 @@
   int tiling_i_index_;
   int tiling_j_index_;
   bool required_for_activation_;
+  bool required_for_draw_;
 
   Id id_;
   static Id s_next_id_;
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 8b6a72a..1c7d4ca 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -175,6 +175,20 @@
   DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
 };
 
+const char* TaskSetName(TaskSet task_set) {
+  switch (task_set) {
+    case TileManager::ALL:
+      return "ALL";
+    case TileManager::REQUIRED_FOR_ACTIVATION:
+      return "REQUIRED_FOR_ACTIVATION";
+    case TileManager::REQUIRED_FOR_DRAW:
+      return "REQUIRED_FOR_DRAW";
+  }
+
+  NOTREACHED();
+  return "Invalid TaskSet";
+}
+
 }  // namespace
 
 RasterTaskCompletionStats::RasterTaskCompletionStats()
@@ -225,7 +239,10 @@
       ready_to_activate_check_notifier_(
           task_runner_.get(),
           base::Bind(&TileManager::CheckIfReadyToActivate,
-                     base::Unretained(this))) {
+                     base::Unretained(this))),
+      ready_to_draw_check_notifier_(task_runner_.get(),
+                                    base::Bind(&TileManager::CheckIfReadyToDraw,
+                                               base::Unretained(this))) {
   rasterizer_->SetClient(this);
 }
 
@@ -295,85 +312,91 @@
 }
 
 void TileManager::DidFinishRunningTasks(TaskSet task_set) {
-  if (task_set == ALL) {
-    TRACE_EVENT1("cc", "TileManager::DidFinishRunningTasks", "task_set", "ALL");
+  TRACE_EVENT1("cc", "TileManager::DidFinishRunningTasks", "task_set",
+               TaskSetName(task_set));
 
-    bool memory_usage_above_limit = resource_pool_->total_memory_usage_bytes() >
-                                    global_state_.soft_memory_limit_in_bytes;
+  switch (task_set) {
+    case ALL: {
+      bool memory_usage_above_limit =
+          resource_pool_->total_memory_usage_bytes() >
+          global_state_.soft_memory_limit_in_bytes;
 
-    // When OOM, keep re-assigning memory until we reach a steady state
-    // where top-priority tiles are initialized.
-    if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
-        !memory_usage_above_limit)
-      return;
+      // When OOM, keep re-assigning memory until we reach a steady state
+      // where top-priority tiles are initialized.
+      if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
+          !memory_usage_above_limit)
+        return;
 
-    rasterizer_->CheckForCompletedTasks();
-    did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
+      rasterizer_->CheckForCompletedTasks();
+      did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
 
-    TileVector tiles_that_need_to_be_rasterized;
-    AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
+      TileVector tiles_that_need_to_be_rasterized;
+      AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
 
-    // |tiles_that_need_to_be_rasterized| will be empty when we reach a
-    // steady memory state. Keep scheduling tasks until we reach this state.
-    if (!tiles_that_need_to_be_rasterized.empty()) {
-      ScheduleTasks(tiles_that_need_to_be_rasterized);
-      return;
-    }
-
-    FreeResourcesForReleasedTiles();
-
-    resource_pool_->ReduceResourceUsage();
-
-    // We don't reserve memory for required-for-activation tiles during
-    // accelerated gestures, so we just postpone activation when we don't
-    // have these tiles, and activate after the accelerated gesture.
-    // Likewise if we don't allow any tiles (as is the case when we're
-    // invisible), if we have tiles that aren't ready, then we shouldn't
-    // activate as activation can cause checkerboards.
-    bool allow_rasterize_on_demand =
-        global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
-        global_state_.memory_limit_policy != ALLOW_NOTHING;
-
-    // Use on-demand raster for any required-for-activation tiles that have not
-    // been been assigned memory after reaching a steady memory state. This
-    // ensures that we activate even when OOM. Note that we have to rebuilt the
-    // queue in case the last AssignGpuMemoryToTiles evicted some tiles that
-    // would otherwise not be picked up by the old raster queue.
-    client_->BuildRasterQueue(&raster_priority_queue_,
-                              global_state_.tree_priority);
-    bool ready_to_activate = true;
-    while (!raster_priority_queue_.IsEmpty()) {
-      Tile* tile = raster_priority_queue_.Top();
-      ManagedTileState& mts = tile->managed_state();
-
-      if (tile->required_for_activation() && !mts.draw_info.IsReadyToDraw()) {
-        // If we can't raster on demand, give up early (and don't activate).
-        if (!allow_rasterize_on_demand) {
-          ready_to_activate = false;
-          break;
-        }
-
-        mts.draw_info.set_rasterize_on_demand();
-        client_->NotifyTileStateChanged(tile);
+      // |tiles_that_need_to_be_rasterized| will be empty when we reach a
+      // steady memory state. Keep scheduling tasks until we reach this state.
+      if (!tiles_that_need_to_be_rasterized.empty()) {
+        ScheduleTasks(tiles_that_need_to_be_rasterized);
+        return;
       }
-      raster_priority_queue_.Pop();
-    }
 
-    if (ready_to_activate) {
-      DCHECK(IsReadyToActivate());
+      FreeResourcesForReleasedTiles();
+
+      resource_pool_->ReduceResourceUsage();
+
+      // We don't reserve memory for required-for-activation tiles during
+      // accelerated gestures, so we just postpone activation when we don't
+      // have these tiles, and activate after the accelerated gesture.
+      // Likewise if we don't allow any tiles (as is the case when we're
+      // invisible), if we have tiles that aren't ready, then we shouldn't
+      // activate as activation can cause checkerboards.
+      bool allow_rasterize_on_demand =
+          global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
+          global_state_.memory_limit_policy != ALLOW_NOTHING;
+
+      // Use on-demand raster for any required-for-activation tiles that have
+      // not
+      // been been assigned memory after reaching a steady memory state. This
+      // ensures that we activate even when OOM. Note that we have to rebuilt
+      // the
+      // queue in case the last AssignGpuMemoryToTiles evicted some tiles that
+      // would otherwise not be picked up by the old raster queue.
+      client_->BuildRasterQueue(&raster_priority_queue_,
+                                global_state_.tree_priority);
+      bool ready_to_activate = true;
+      while (!raster_priority_queue_.IsEmpty()) {
+        Tile* tile = raster_priority_queue_.Top();
+        ManagedTileState& mts = tile->managed_state();
+
+        if (tile->required_for_activation() && !mts.draw_info.IsReadyToDraw()) {
+          // If we can't raster on demand, give up early (and don't activate).
+          if (!allow_rasterize_on_demand) {
+            ready_to_activate = false;
+            break;
+          }
+
+          mts.draw_info.set_rasterize_on_demand();
+          client_->NotifyTileStateChanged(tile);
+        }
+        raster_priority_queue_.Pop();
+      }
+
+      if (ready_to_activate) {
+        DCHECK(IsReadyToActivate());
+        ready_to_activate_check_notifier_.Schedule();
+      }
+      raster_priority_queue_.Reset();
+      return;
+    }
+    case REQUIRED_FOR_ACTIVATION:
       ready_to_activate_check_notifier_.Schedule();
-    }
-    raster_priority_queue_.Reset();
-    return;
+      return;
+    case REQUIRED_FOR_DRAW:
+      ready_to_draw_check_notifier_.Schedule();
+      return;
   }
 
-  if (task_set == REQUIRED_FOR_ACTIVATION) {
-    TRACE_EVENT1("cc",
-                 "TileManager::DidFinishRunningTasks",
-                 "task_set",
-                 "REQUIRED_FOR_ACTIVATION");
-    ready_to_activate_check_notifier_.Schedule();
-  }
+  NOTREACHED();
 }
 
 void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) {
@@ -671,6 +694,8 @@
     TaskSetCollection task_sets;
     if (tile->required_for_activation())
       task_sets.set(REQUIRED_FOR_ACTIVATION);
+    if (tile->required_for_draw())
+      task_sets.set(REQUIRED_FOR_DRAW);
     task_sets.set(ALL);
     raster_queue_.items.push_back(
         RasterTaskQueue::Item(mts.raster_task.get(), task_sets));
@@ -840,10 +865,19 @@
   TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
   const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
 
-  for (std::vector<PictureLayerImpl*>::const_iterator it = layers.begin();
-       it != layers.end();
-       ++it) {
-    if (!(*it)->AllTilesRequiredForActivationAreReadyToDraw())
+  for (const auto& layer : layers) {
+    if (!layer->AllTilesRequiredForActivationAreReadyToDraw())
+      return false;
+  }
+
+  return true;
+}
+
+bool TileManager::IsReadyToDraw() const {
+  const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
+
+  for (const auto& layer : layers) {
+    if (!layer->AllTilesRequiredForDrawAreReadyToDraw())
       return false;
   }
 
@@ -860,6 +894,16 @@
     client_->NotifyReadyToActivate();
 }
 
+void TileManager::CheckIfReadyToDraw() {
+  TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
+
+  rasterizer_->CheckForCompletedTasks();
+  did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
+
+  if (IsReadyToDraw())
+    client_->NotifyReadyToDraw();
+}
+
 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
 }
 
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index f5bea38..92821e0 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -47,6 +47,9 @@
   // Called when all tiles marked as required for activation are ready to draw.
   virtual void NotifyReadyToActivate() = 0;
 
+  // Called when all tiles marked as required for draw are ready to draw.
+  virtual void NotifyReadyToDraw() = 0;
+
   // Called when the visible representation of a tile might have changed. Some
   // examples are:
   // - Tile version initialized.
@@ -87,8 +90,9 @@
                               public RefCountedManager<Tile> {
  public:
   enum NamedTaskSet {
-    REQUIRED_FOR_ACTIVATION = 0,
-    ALL = 1,
+    ALL,
+    REQUIRED_FOR_ACTIVATION,
+    REQUIRED_FOR_DRAW
     // Adding additional values requires increasing kNumberOfTaskSets in
     // rasterizer.h
   };
@@ -231,7 +235,9 @@
       MemoryUsage* usage);
   bool TilePriorityViolatesMemoryPolicy(const TilePriority& priority);
   bool IsReadyToActivate() const;
+  bool IsReadyToDraw() const;
   void CheckIfReadyToActivate();
+  void CheckIfReadyToDraw();
 
   TileManagerClient* client_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
@@ -272,6 +278,7 @@
   std::vector<scoped_refptr<RasterTask>> orphan_raster_tasks_;
 
   UniqueNotifier ready_to_activate_check_notifier_;
+  UniqueNotifier ready_to_draw_check_notifier_;
 
   RasterTilePriorityQueue raster_priority_queue_;
   EvictionTilePriorityQueue eviction_priority_queue_;
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 43c1031..7262926 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -159,7 +159,7 @@
     pending_tree->DetachLayerTree();
 
     scoped_ptr<FakePictureLayerImpl> pending_layer =
-        FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
+        FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, pile);
     pending_layer->SetDrawsContent(true);
     pending_tree->SetRootLayer(pending_layer.Pass());
 
@@ -361,8 +361,8 @@
         FakePicturePileImpl::CreateFilledPile(kDefaultTileSize, layer_bounds);
     while (static_cast<int>(layers.size()) < layer_count) {
       scoped_ptr<FakePictureLayerImpl> layer =
-          FakePictureLayerImpl::CreateWithPile(host_impl_.pending_tree(),
-                                               next_id, pile);
+          FakePictureLayerImpl::CreateWithRasterSource(
+              host_impl_.pending_tree(), next_id, pile);
       layer->SetBounds(layer_bounds);
       layers.push_back(layer.get());
       pending_root_layer_->AddChild(layer.Pass());
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 2f0735c..a253672 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -109,14 +109,14 @@
     if (old_pending_root) {
       pending_layer.reset(
           static_cast<FakePictureLayerImpl*>(old_pending_root.release()));
-      pending_layer->SetPile(pile);
+      pending_layer->SetRasterSource(pile);
     } else {
       pending_layer =
-          FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
+          FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, pile);
       pending_layer->SetDrawsContent(true);
     }
     // The bounds() just mirror the pile size.
-    pending_layer->SetBounds(pending_layer->pile()->tiling_size());
+    pending_layer->SetBounds(pending_layer->raster_source()->GetSize());
     pending_tree->SetRootLayer(pending_layer.Pass());
 
     pending_layer_ = static_cast<FakePictureLayerImpl*>(
@@ -193,9 +193,9 @@
 
   // Invalidate the pending tree.
   pending_layer_->set_invalidation(invalidation);
-  pending_layer_->HighResTiling()->UpdateTilesToCurrentPile(
+  pending_layer_->HighResTiling()->UpdateTilesToCurrentRasterSource(
       invalidation, gfx::Size(1000, 1000));
-  pending_layer_->LowResTiling()->UpdateTilesToCurrentPile(
+  pending_layer_->LowResTiling()->UpdateTilesToCurrentRasterSource(
       invalidation, gfx::Size(1000, 1000));
 
   active_layer_->ResetAllTilesPriorities();
@@ -344,8 +344,8 @@
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
   scoped_ptr<FakePictureLayerImpl> pending_child =
-      FakePictureLayerImpl::CreateWithPile(
-          host_impl_.pending_tree(), id_ + 1, pending_pile);
+      FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(),
+                                                   id_ + 1, pending_pile);
   pending_layer_->AddChild(pending_child.Pass());
   FakePictureLayerImpl* pending_child_raw = static_cast<FakePictureLayerImpl*>(
       host_impl_.pending_tree()->LayerById(id_ + 1));
@@ -441,9 +441,9 @@
 
   // Invalidate the pending tree.
   pending_layer_->set_invalidation(invalidation);
-  pending_layer_->HighResTiling()->UpdateTilesToCurrentPile(
+  pending_layer_->HighResTiling()->UpdateTilesToCurrentRasterSource(
       invalidation, gfx::Size(1000, 1000));
-  pending_layer_->LowResTiling()->UpdateTilesToCurrentPile(
+  pending_layer_->LowResTiling()->UpdateTilesToCurrentRasterSource(
       invalidation, gfx::Size(1000, 1000));
 
   active_layer_->ResetAllTilesPriorities();
@@ -566,8 +566,8 @@
   pending_layer_->CreateDefaultTilingsAndTiles();
 
   scoped_ptr<FakePictureLayerImpl> pending_child =
-      FakePictureLayerImpl::CreateWithPile(
-          host_impl_.pending_tree(), 2, pending_pile);
+      FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 2,
+                                                   pending_pile);
   pending_layer_->AddChild(pending_child.Pass());
 
   FakePictureLayerImpl* pending_child_layer =
@@ -669,6 +669,104 @@
   EXPECT_EQ(expected_occluded_count, occluded_count);
 }
 
+TEST_F(TileManagerTilePriorityQueueTest,
+       EvictionTilePriorityQueueWithTransparentLayer) {
+  gfx::Size tile_size(102, 102);
+  gfx::Size layer_bounds(1000, 1000);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupPendingTree(pending_pile);
+  pending_layer_->CreateDefaultTilingsAndTiles();
+
+  scoped_ptr<FakePictureLayerImpl> pending_child =
+      FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 2,
+                                                   pending_pile);
+  pending_layer_->AddChild(pending_child.Pass());
+
+  // Create a fully transparent child layer so that its tile priorities are not
+  // considered to be valid.
+  FakePictureLayerImpl* pending_child_layer =
+      static_cast<FakePictureLayerImpl*>(pending_layer_->children()[0]);
+  pending_child_layer->SetDrawsContent(true);
+  pending_child_layer->CreateDefaultTilingsAndTiles();
+  pending_child_layer->SetOpacity(0.0);
+  pending_child_layer->layer_tree_impl()->UpdateDrawProperties();
+  pending_child_layer->DoPostCommitInitializationIfNeeded();
+
+  // Renew all of the tile priorities.
+  gfx::Rect viewport(layer_bounds);
+  pending_layer_->HighResTiling()->ComputeTilePriorityRects(
+      PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+  pending_layer_->LowResTiling()->ComputeTilePriorityRects(
+      PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+  pending_child_layer->HighResTiling()->ComputeTilePriorityRects(
+      PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+  pending_child_layer->LowResTiling()->ComputeTilePriorityRects(
+      PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+
+  // Populate all tiles directly from the tilings.
+  std::set<Tile*> all_pending_tiles;
+  std::vector<Tile*> pending_high_res_tiles =
+      pending_layer_->HighResTiling()->AllTilesForTesting();
+  all_pending_tiles.insert(pending_high_res_tiles.begin(),
+                           pending_high_res_tiles.end());
+  EXPECT_EQ(16u, pending_high_res_tiles.size());
+
+  std::vector<Tile*> pending_low_res_tiles =
+      pending_layer_->LowResTiling()->AllTilesForTesting();
+  all_pending_tiles.insert(pending_low_res_tiles.begin(),
+                           pending_low_res_tiles.end());
+  EXPECT_EQ(1u, pending_low_res_tiles.size());
+
+  std::set<Tile*> all_pending_child_tiles;
+  std::vector<Tile*> pending_child_high_res_tiles =
+      pending_child_layer->HighResTiling()->AllTilesForTesting();
+  all_pending_child_tiles.insert(pending_child_high_res_tiles.begin(),
+                                 pending_child_high_res_tiles.end());
+  EXPECT_EQ(16u, pending_child_high_res_tiles.size());
+
+  std::vector<Tile*> pending_child_low_res_tiles =
+      pending_child_layer->LowResTiling()->AllTilesForTesting();
+  all_pending_child_tiles.insert(pending_child_low_res_tiles.begin(),
+                                 pending_child_low_res_tiles.end());
+  EXPECT_EQ(1u, pending_child_low_res_tiles.size());
+
+  std::set<Tile*> all_tiles = all_pending_tiles;
+  all_tiles.insert(all_pending_child_tiles.begin(),
+                   all_pending_child_tiles.end());
+
+  tile_manager()->InitializeTilesWithResourcesForTesting(
+      std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+  EXPECT_TRUE(pending_layer_->HasValidTilePriorities());
+  EXPECT_FALSE(pending_child_layer->HasValidTilePriorities());
+
+  // Verify that eviction queue returns tiles also from layers without valid
+  // tile priorities and that the tile priority bin of those tiles is (at most)
+  // EVENTUALLY.
+  TreePriority tree_priority = NEW_CONTENT_TAKES_PRIORITY;
+  std::set<Tile*> new_content_tiles;
+  size_t tile_count = 0;
+  EvictionTilePriorityQueue queue;
+  host_impl_.BuildEvictionQueue(&queue, tree_priority);
+  while (!queue.IsEmpty()) {
+    Tile* tile = queue.Top();
+    const TilePriority& pending_priority = tile->priority(PENDING_TREE);
+    EXPECT_NE(std::numeric_limits<float>::infinity(),
+              pending_priority.distance_to_visible);
+    if (all_pending_child_tiles.find(tile) != all_pending_child_tiles.end())
+      EXPECT_EQ(TilePriority::EVENTUALLY, pending_priority.priority_bin);
+    else
+      EXPECT_EQ(TilePriority::NOW, pending_priority.priority_bin);
+    new_content_tiles.insert(tile);
+    ++tile_count;
+    queue.Pop();
+  }
+  EXPECT_EQ(tile_count, new_content_tiles.size());
+  EXPECT_EQ(all_tiles, new_content_tiles);
+}
+
 TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueEmptyLayers) {
   SetupDefaultTrees(gfx::Size(1000, 1000));
 
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc
index 4a9f184..dd6cdbe 100644
--- a/cc/scheduler/begin_frame_source.cc
+++ b/cc/scheduler/begin_frame_source.cc
@@ -79,9 +79,9 @@
                "new state",
                needs_begin_frames);
   if (needs_begin_frames_ != needs_begin_frames) {
+    needs_begin_frames_ = needs_begin_frames;
     OnNeedsBeginFramesChange(needs_begin_frames);
   }
-  needs_begin_frames_ = needs_begin_frames;
 }
 
 void BeginFrameSourceMixIn::AddObserver(BeginFrameObserver* obs) {
diff --git a/cc/scheduler/begin_frame_source.h b/cc/scheduler/begin_frame_source.h
index 3d849a4..28359d3 100644
--- a/cc/scheduler/begin_frame_source.h
+++ b/cc/scheduler/begin_frame_source.h
@@ -117,6 +117,9 @@
   virtual void AddObserver(BeginFrameObserver* obs) = 0;
   virtual void RemoveObserver(BeginFrameObserver* obs) = 0;
 
+  // Tells the Source that client is ready to handle BeginFrames messages.
+  virtual void SetClientReady() = 0;
+
   // Tracing support - Recommend (but not required) to call this implementation
   // in any override.
   virtual void AsValueInto(base::debug::TracedValue* dict) const = 0;
@@ -137,8 +140,9 @@
   bool NeedsBeginFrames() const override;
   void SetNeedsBeginFrames(bool needs_begin_frames) override;
   void DidFinishFrame(size_t remaining_frames) override {}
-  void AddObserver(BeginFrameObserver* obs) override;
-  void RemoveObserver(BeginFrameObserver* obs) override;
+  void AddObserver(BeginFrameObserver* obs) final;
+  void RemoveObserver(BeginFrameObserver* obs) final;
+  void SetClientReady() override {}
 
   // Tracing support - Recommend (but not required) to call this implementation
   // in any override.
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 88c27c1..5c515b2 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -5,6 +5,7 @@
 #include "cc/scheduler/scheduler.h"
 
 #include <algorithm>
+
 #include "base/auto_reset.h"
 #include "base/debug/trace_event.h"
 #include "base/debug/trace_event_argument.h"
@@ -28,12 +29,14 @@
     scheduler->primary_frame_source_internal_ =
         BackToBackBeginFrameSource::Create(scheduler->task_runner_.get());
     return scheduler->primary_frame_source_internal_.get();
-  } else if (scheduler->settings_.begin_frame_scheduling_enabled) {
+  } else if (scheduler->settings_.use_external_begin_frame_source) {
     TRACE_EVENT1("cc",
                  "Scheduler::Scheduler()",
                  "PrimaryFrameSource",
-                 "SchedulerClient");
-    return scheduler->client_->ExternalBeginFrameSource();
+                 "ExternalBeginFrameSource");
+    DCHECK(scheduler->primary_frame_source_internal_)
+        << "Need external BeginFrameSource";
+    return scheduler->primary_frame_source_internal_.get();
   } else {
     TRACE_EVENT1("cc",
                  "Scheduler::Scheduler()",
@@ -62,9 +65,9 @@
                "SyntheticBeginFrameSource");
   DCHECK(!(scheduler->background_frame_source_internal_));
   scheduler->background_frame_source_internal_ =
-      SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(),
-                                        scheduler->Now(),
-                                        base::TimeDelta::FromSeconds(1));
+      SyntheticBeginFrameSource::Create(
+          scheduler->task_runner_.get(), scheduler->Now(),
+          scheduler->settings_.background_frame_interval);
   return scheduler->background_frame_source_internal_.get();
 }
 
@@ -74,11 +77,12 @@
     int layer_tree_host_id,
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     base::PowerMonitor* power_monitor,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source,
     SchedulerFrameSourcesConstructor* frame_sources_constructor)
     : frame_source_(),
       primary_frame_source_(NULL),
       background_frame_source_(NULL),
-      primary_frame_source_internal_(),
+      primary_frame_source_internal_(external_begin_frame_source.Pass()),
       background_frame_source_internal_(),
       vsync_observer_(NULL),
       settings_(scheduler_settings),
@@ -114,6 +118,7 @@
   primary_frame_source_ =
       frame_sources_constructor->ConstructPrimaryFrameSource(this);
   frame_source_->AddSource(primary_frame_source_);
+  primary_frame_source_->SetClientReady();
 
   // Background ticking frame source
   background_frame_source_ =
@@ -125,6 +130,8 @@
 
 Scheduler::~Scheduler() {
   TeardownPowerMonitoring();
+  if (frame_source_->NeedsBeginFrames())
+    frame_source_->SetNeedsBeginFrames(false);
 }
 
 base::TimeTicks Scheduler::Now() const {
@@ -197,6 +204,11 @@
   ProcessScheduledActions();
 }
 
+void Scheduler::NotifyReadyToDraw() {
+  // Empty for now, until we take action based on the notification as part of
+  // crbugs 352894, 383157, 421923.
+}
+
 void Scheduler::SetNeedsCommit() {
   state_machine_.SetNeedsCommit();
   ProcessScheduledActions();
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index f470d17..523c246 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -34,7 +34,6 @@
 
 class SchedulerClient {
  public:
-  virtual BeginFrameSource* ExternalBeginFrameSource() = 0;
   virtual void WillBeginImplFrame(const BeginFrameArgs& args) = 0;
   virtual void ScheduledActionSendBeginMainFrame() = 0;
   virtual DrawResult ScheduledActionDrawAndSwapIfPossible() = 0;
@@ -81,13 +80,15 @@
       const SchedulerSettings& scheduler_settings,
       int layer_tree_host_id,
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-      base::PowerMonitor* power_monitor) {
+      base::PowerMonitor* power_monitor,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source) {
     SchedulerFrameSourcesConstructor frame_sources_constructor;
     return make_scoped_ptr(new Scheduler(client,
                                          scheduler_settings,
                                          layer_tree_host_id,
                                          task_runner,
                                          power_monitor,
+                                         external_begin_frame_source.Pass(),
                                          &frame_sources_constructor));
   }
 
@@ -107,6 +108,7 @@
   void SetVisible(bool visible);
   void SetCanDraw(bool can_draw);
   void NotifyReadyToActivate();
+  void NotifyReadyToDraw();
 
   void SetNeedsCommit();
 
@@ -173,6 +175,7 @@
             int layer_tree_host_id,
             const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
             base::PowerMonitor* power_monitor,
+            scoped_ptr<BeginFrameSource> external_begin_frame_source,
             SchedulerFrameSourcesConstructor* frame_sources_constructor);
 
   // virtual for testing - Don't call these in the constructor or
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc
index ab9add0..84f0fcd 100644
--- a/cc/scheduler/scheduler_settings.cc
+++ b/cc/scheduler/scheduler_settings.cc
@@ -10,18 +10,22 @@
 namespace cc {
 
 SchedulerSettings::SchedulerSettings()
-    : begin_frame_scheduling_enabled(true),
+    : use_external_begin_frame_source(false),
+      forward_begin_frames_to_children(false),
       main_frame_before_activation_enabled(false),
       impl_side_painting(false),
       timeout_and_draw_when_animation_checkerboards(true),
       maximum_number_of_failed_draws_before_draw_is_forced_(3),
       using_synchronous_renderer_compositor(false),
       throttle_frame_production(true),
-      disable_hi_res_timer_tasks_on_battery(false) {
+      disable_hi_res_timer_tasks_on_battery(false),
+      background_frame_interval(base::TimeDelta::FromSeconds(1)) {
 }
 
 SchedulerSettings::SchedulerSettings(const LayerTreeSettings& settings)
-    : begin_frame_scheduling_enabled(settings.begin_frame_scheduling_enabled),
+    : use_external_begin_frame_source(settings.use_external_begin_frame_source),
+      forward_begin_frames_to_children(
+          settings.forward_begin_frames_to_children),
       main_frame_before_activation_enabled(
           settings.main_frame_before_activation_enabled),
       impl_side_painting(settings.impl_side_painting),
@@ -33,7 +37,9 @@
           settings.using_synchronous_renderer_compositor),
       throttle_frame_production(settings.throttle_frame_production),
       disable_hi_res_timer_tasks_on_battery(
-          settings.disable_hi_res_timer_tasks_on_battery) {
+          settings.disable_hi_res_timer_tasks_on_battery),
+      background_frame_interval(base::TimeDelta::FromSecondsD(
+          1.0 / settings.background_animation_rate)) {
 }
 
 SchedulerSettings::~SchedulerSettings() {}
@@ -42,8 +48,10 @@
 SchedulerSettings::AsValue() const {
   scoped_refptr<base::debug::TracedValue> state =
       new base::debug::TracedValue();
-  state->SetBoolean("begin_frame_scheduling_enabled",
-                    begin_frame_scheduling_enabled);
+  state->SetBoolean("use_external_begin_frame_source",
+                    use_external_begin_frame_source);
+  state->SetBoolean("forward_begin_frames_to_children",
+                    forward_begin_frames_to_children);
   state->SetBoolean("main_frame_before_activation_enabled",
                     main_frame_before_activation_enabled);
   state->SetBoolean("impl_side_painting", impl_side_painting);
@@ -56,6 +64,8 @@
   state->SetBoolean("throttle_frame_production", throttle_frame_production);
   state->SetBoolean("disable_hi_res_timer_tasks_on_battery",
                     disable_hi_res_timer_tasks_on_battery);
+  state->SetInteger("background_frame_interval",
+                    background_frame_interval.InMicroseconds());
   return state;
 }
 
diff --git a/cc/scheduler/scheduler_settings.h b/cc/scheduler/scheduler_settings.h
index 8607991..e3fd425 100644
--- a/cc/scheduler/scheduler_settings.h
+++ b/cc/scheduler/scheduler_settings.h
@@ -6,6 +6,7 @@
 #define CC_SCHEDULER_SCHEDULER_SETTINGS_H_
 
 #include "base/memory/ref_counted.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "cc/base/cc_export.h"
 
@@ -24,7 +25,8 @@
   explicit SchedulerSettings(const LayerTreeSettings& settings);
   ~SchedulerSettings();
 
-  bool begin_frame_scheduling_enabled;
+  bool use_external_begin_frame_source;
+  bool forward_begin_frames_to_children;
   bool main_frame_before_activation_enabled;
   bool impl_side_painting;
   bool timeout_and_draw_when_animation_checkerboards;
@@ -33,6 +35,8 @@
   bool throttle_frame_production;
   bool disable_hi_res_timer_tasks_on_battery;
 
+  base::TimeDelta background_frame_interval;
+
   scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
 };
 
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 2b8210d..94016f3 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -423,9 +423,6 @@
 }
 
 bool SchedulerStateMachine::ShouldAnimate() const {
-  if (!can_draw_)
-    return false;
-
   // If a commit occurred after our last call, we need to do animation again.
   if (HasAnimatedThisFrame() && !did_commit_after_animating_)
     return false;
@@ -765,29 +762,18 @@
   if (!HasInitializedOutputSurface())
     return false;
 
-  // If we can't draw, don't tick until we are notified that we can draw again.
-  if (!can_draw_)
-    return false;
-
   // The forced draw respects our normal draw scheduling, so we need to
   // request a BeginImplFrame for it.
   if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
     return true;
 
-  // There's no need to produce frames if we are not visible.
-  if (!visible_)
-    return false;
-
   // We need to draw a more complete frame than we did the last BeginImplFrame,
   // so request another BeginImplFrame in anticipation that we will have
   // additional visible tiles.
   if (swap_used_incomplete_tile_)
     return true;
 
-  if (needs_animate_)
-    return true;
-
-  return needs_redraw_;
+  return needs_animate_ || needs_redraw_;
 }
 
 // These are cases where we are very likely to draw soon, but might not
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index e3530c8..85160ed 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -703,6 +703,7 @@
   state.SetVisible(true);
   state.SetCanDraw(false);
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -711,6 +712,7 @@
   state.NotifyReadyToCommit();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
   state.OnBeginImplFrameDeadline();
+  EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 }
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 7da6267..91900a2 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -1,6 +1,7 @@
 // Copyright 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+
 #include "cc/scheduler/scheduler.h"
 
 #include <string>
@@ -47,13 +48,11 @@
 
 class FakeSchedulerClient : public SchedulerClient {
  public:
-  struct FakeBeginFrameSourceForFakeSchedulerClient
-      : public FakeBeginFrameSource {
-    FakeSchedulerClient* client_;
-
-    explicit FakeBeginFrameSourceForFakeSchedulerClient(
-        FakeSchedulerClient* client)
+  class FakeExternalBeginFrameSource : public BeginFrameSourceMixIn {
+   public:
+    explicit FakeExternalBeginFrameSource(FakeSchedulerClient* client)
         : client_(client) {}
+    virtual ~FakeExternalBeginFrameSource() {}
 
     void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
       if (needs_begin_frames) {
@@ -63,6 +62,13 @@
       }
       client_->states_.push_back(client_->scheduler_->AsValue());
     }
+
+    void TestOnBeginFrame(const BeginFrameArgs& args) {
+      return CallOnBeginFrame(args);
+    }
+
+   private:
+    FakeSchedulerClient* client_;
   };
 
   class FakePowerMonitorSource : public base::PowerMonitorSource {
@@ -86,7 +92,7 @@
         redraw_will_happen_if_update_visible_tiles_happens_(false),
         now_src_(TestNowSource::Create()),
         task_runner_(new OrderedSimpleTaskRunner(now_src_, true)),
-        fake_frame_source_(this),
+        fake_external_begin_frame_source_(nullptr),
         fake_power_monitor_source_(new FakePowerMonitorSource),
         power_monitor_(make_scoped_ptr<base::PowerMonitorSource>(
             fake_power_monitor_source_)),
@@ -108,8 +114,21 @@
   }
 
   TestScheduler* CreateScheduler(const SchedulerSettings& settings) {
-    scheduler_ = TestScheduler::Create(
-        now_src_, this, settings, 0, task_runner_, &power_monitor_);
+    scoped_ptr<FakeExternalBeginFrameSource> fake_external_begin_frame_source;
+    if (settings.use_external_begin_frame_source &&
+        settings.throttle_frame_production) {
+      fake_external_begin_frame_source.reset(
+          new FakeExternalBeginFrameSource(this));
+      fake_external_begin_frame_source_ =
+          fake_external_begin_frame_source.get();
+    }
+    scheduler_ = TestScheduler::Create(now_src_,
+                                       this,
+                                       settings,
+                                       0,
+                                       task_runner_,
+                                       &power_monitor_,
+                                       fake_external_begin_frame_source.Pass());
     DCHECK(scheduler_);
     return scheduler_.get();
   }
@@ -119,7 +138,10 @@
   void set_log_anticipated_draw_time_change(bool log) {
     log_anticipated_draw_time_change_ = log;
   }
-  bool needs_begin_frames() { return fake_frame_source_.NeedsBeginFrames(); }
+  bool needs_begin_frames() {
+    DCHECK(ExternalBeginFrame());
+    return fake_external_begin_frame_source_->NeedsBeginFrames();
+  }
   int num_draws() const { return num_draws_; }
   int num_actions_() const { return static_cast<int>(actions_.size()); }
   const char* Action(int i) const { return actions_[i]; }
@@ -129,11 +151,12 @@
   }
 
   bool ExternalBeginFrame() {
-    return scheduler_->settings().begin_frame_scheduling_enabled &&
+    return scheduler_->settings().use_external_begin_frame_source &&
            scheduler_->settings().throttle_frame_production;
   }
-  FakeBeginFrameSource* ExternalBeginFrameSource() override {
-    return &fake_frame_source_;
+
+  FakeExternalBeginFrameSource* fake_external_begin_frame_source() const {
+    return fake_external_begin_frame_source_;
   }
 
   base::PowerMonitor* PowerMonitor() { return &power_monitor_; }
@@ -145,12 +168,11 @@
   void AdvanceFrame() {
     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
                  "FakeSchedulerClient::AdvanceFrame");
-    // EXPECT_TRUE(needs_begin_frames());
     if (ExternalBeginFrame()) {
       // Creep the time forward so that any BeginFrameArgs is not equal to the
       // last one otherwise we violate the BeginFrameSource contract.
       now_src_->AdvanceNowMicroseconds(1);
-      fake_frame_source_.TestOnBeginFrame(
+      fake_external_begin_frame_source_->TestOnBeginFrame(
           CreateBeginFrameArgsForTesting(now_src_));
       EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
     }
@@ -288,7 +310,7 @@
   std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat>> states_;
   scoped_refptr<TestNowSource> now_src_;
   scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
-  FakeBeginFrameSourceForFakeSchedulerClient fake_frame_source_;
+  FakeExternalBeginFrameSource* fake_external_begin_frame_source_;
   FakePowerMonitorSource* fake_power_monitor_source_;
   base::PowerMonitor power_monitor_;
   scoped_ptr<TestScheduler> scheduler_;
@@ -327,14 +349,13 @@
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
   EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
-  // EXPECT_FALSE(client->needs_begin_frames());
 }
 
 TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
   FakeSchedulerClient client;
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -348,6 +369,7 @@
 TEST(SchedulerTest, RequestCommit) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -413,6 +435,7 @@
 TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -511,8 +534,9 @@
 // 2. the scheduler drawing twice inside a single tick
 TEST(SchedulerTest, RequestRedrawInsideDraw) {
   SchedulerClientThatsetNeedsDrawInsideDraw client;
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -548,8 +572,9 @@
 // Test that requesting redraw inside a failed draw doesn't lose the request.
 TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
   SchedulerClientThatsetNeedsDrawInsideDraw client;
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -626,8 +651,9 @@
 // happen inside a ScheduledActionDrawAndSwap
 TEST(SchedulerTest, RequestCommitInsideDraw) {
   SchedulerClientThatSetNeedsCommitInsideDraw client;
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -671,8 +697,9 @@
 // Tests that when a draw fails then the pending commit should not be dropped.
 TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
   SchedulerClientThatsetNeedsDrawInsideDraw client;
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -718,8 +745,9 @@
 
 TEST(SchedulerTest, NoSwapWhenDrawFails) {
   SchedulerClientThatSetNeedsCommitInsideDraw client;
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -760,8 +788,9 @@
 // Test manage tiles is independant of draws.
 TEST(SchedulerTest, ManageTiles) {
   SchedulerClientNeedsManageTilesInDraw client;
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -866,8 +895,9 @@
 // initiates it, then the state machine should not ManageTiles on that frame.
 TEST(SchedulerTest, ManageTilesOncePerFrame) {
   FakeSchedulerClient client;
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -986,6 +1016,7 @@
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
   scheduler_settings.impl_side_painting = true;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1045,8 +1076,9 @@
 
 TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
   SchedulerClientNeedsManageTilesInDraw client;
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -1096,8 +1128,9 @@
       base::TimeDelta::FromMilliseconds(
           begin_main_frame_to_commit_estimate_in_ms),
       base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
   scheduler->SetCanDraw(true);
@@ -1163,8 +1196,9 @@
       base::TimeDelta::FromMilliseconds(32),
       base::TimeDelta::FromMilliseconds(32));
   client.set_log_anticipated_draw_time_change(true);
-  SchedulerSettings default_scheduler_settings;
-  TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+  SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
+  TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
 
   scheduler->SetCanDraw(true);
   scheduler->SetCanStart();
@@ -1179,7 +1213,7 @@
 
   BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src());
   frame_args.interval = base::TimeDelta::FromMilliseconds(1000);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(frame_args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(frame_args);
 
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   client.task_runner().RunPendingTasks();  // Run posted deadline.
@@ -1192,7 +1226,7 @@
   // the NotifyReadyToCommit for now.
   EXPECT_FALSE(scheduler->CommitPending());
   scheduler->SetNeedsCommit();
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(frame_args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(frame_args);
   EXPECT_TRUE(scheduler->CommitPending());
 
   // Draw and swap the frame, but don't ack the swap to simulate the Browser
@@ -1235,6 +1269,7 @@
 TEST(SchedulerTest, BeginRetroFrame) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1251,7 +1286,7 @@
   // This is the first BeginFrame, which will be handled immediately.
   BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
   args.deadline += base::TimeDelta::FromHours(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
@@ -1260,9 +1295,9 @@
 
   // Queue BeginFrames while we are still handling the previous BeginFrame.
   args.frame_time += base::TimeDelta::FromSeconds(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   args.frame_time += base::TimeDelta::FromSeconds(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
 
   // If we don't swap on the deadline, we wait for the next BeginImplFrame.
   client.task_runner().RunPendingTasks();  // Run posted deadline.
@@ -1308,6 +1343,7 @@
 TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1328,7 +1364,7 @@
   // This is the first BeginFrame, which will be handled immediately.
   BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
   args.deadline += base::TimeDelta::FromHours(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
@@ -1338,7 +1374,7 @@
   // Queue BeginFrame while we are still handling the previous BeginFrame.
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   args.frame_time += base::TimeDelta::FromSeconds(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   EXPECT_NO_ACTION(client);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   client.Reset();
@@ -1369,7 +1405,7 @@
 
   // Queue BeginFrame while we are still handling the previous BeginFrame.
   args.frame_time += base::TimeDelta::FromSeconds(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   EXPECT_NO_ACTION(client);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
   EXPECT_TRUE(client.needs_begin_frames());
@@ -1395,12 +1431,12 @@
   client.Reset();
 }
 
-void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled,
+void BeginFramesNotFromClient(bool use_external_begin_frame_source,
                               bool throttle_frame_production) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
-  scheduler_settings.begin_frame_scheduling_enabled =
-      begin_frame_scheduling_enabled;
+  scheduler_settings.use_external_begin_frame_source =
+      use_external_begin_frame_source;
   scheduler_settings.throttle_frame_production = throttle_frame_production;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
@@ -1408,11 +1444,12 @@
   scheduler->SetCanDraw(true);
   InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
 
+  DCHECK(!client.fake_external_begin_frame_source());
+
   // SetNeedsCommit should begin the frame on the next BeginImplFrame
   // without calling SetNeedsBeginFrame.
   client.Reset();
   scheduler->SetNeedsCommit();
-  EXPECT_FALSE(client.needs_begin_frames());
   EXPECT_NO_ACTION(client);
   client.Reset();
 
@@ -1422,21 +1459,18 @@
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 
   // If we don't swap on the deadline, we wait for the next BeginFrame.
   client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_NO_ACTION(client);
   EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 
   // NotifyReadyToCommit should trigger the commit.
   scheduler->NotifyBeginMainFrameStarted();
   scheduler->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 
   // BeginImplFrame should prepare the draw.
@@ -1444,14 +1478,12 @@
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
   EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 
   // BeginImplFrame deadline should draw.
   client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
   EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 
   // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
@@ -1465,37 +1497,37 @@
   // when the BeginFrame is no longer needed.
   client.task_runner().RunPendingTasks();  // Run posted deadline.
   EXPECT_NO_ACTION(client);
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 }
 
 TEST(SchedulerTest, SyntheticBeginFrames) {
-  bool begin_frame_scheduling_enabled = false;
+  bool use_external_begin_frame_source = false;
   bool throttle_frame_production = true;
-  BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+  BeginFramesNotFromClient(use_external_begin_frame_source,
                            throttle_frame_production);
 }
 
 TEST(SchedulerTest, VSyncThrottlingDisabled) {
-  bool begin_frame_scheduling_enabled = true;
+  bool use_external_begin_frame_source = true;
   bool throttle_frame_production = false;
-  BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+  BeginFramesNotFromClient(use_external_begin_frame_source,
                            throttle_frame_production);
 }
 
 TEST(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) {
-  bool begin_frame_scheduling_enabled = false;
+  bool use_external_begin_frame_source = false;
   bool throttle_frame_production = false;
-  BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+  BeginFramesNotFromClient(use_external_begin_frame_source,
                            throttle_frame_production);
 }
 
-void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled,
-                                            bool throttle_frame_production) {
+void BeginFramesNotFromClient_SwapThrottled(
+    bool use_external_begin_frame_source,
+    bool throttle_frame_production) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
-  scheduler_settings.begin_frame_scheduling_enabled =
-      begin_frame_scheduling_enabled;
+  scheduler_settings.use_external_begin_frame_source =
+      use_external_begin_frame_source;
   scheduler_settings.throttle_frame_production = throttle_frame_production;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
@@ -1503,6 +1535,8 @@
   scheduler->SetCanDraw(true);
   InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
 
+  DCHECK(!client.fake_external_begin_frame_source());
+
   // To test swap ack throttling, this test disables automatic swap acks.
   scheduler->SetMaxSwapsPending(1);
   client.SetAutomaticSwapAck(false);
@@ -1510,7 +1544,6 @@
   // SetNeedsCommit should begin the frame on the next BeginImplFrame.
   client.Reset();
   scheduler->SetNeedsCommit();
-  EXPECT_FALSE(client.needs_begin_frames());
   EXPECT_NO_ACTION(client);
   client.Reset();
 
@@ -1519,14 +1552,12 @@
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 
   // NotifyReadyToCommit should trigger the pending commit and draw.
   scheduler->NotifyBeginMainFrameStarted();
   scheduler->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 
   // Swapping will put us into a swap throttled state.
@@ -1534,7 +1565,6 @@
   EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
   EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 
   // While swap throttled, BeginFrames should trigger BeginImplFrames,
@@ -1543,14 +1573,12 @@
   client.task_runner().RunPendingTasks();  // Run posted BeginFrame.
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 
   // Take us out of a swap throttled state.
   scheduler->DidSwapBuffersComplete();
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 
   // BeginImplFrame deadline should draw.
@@ -1559,35 +1587,35 @@
   EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
   EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
   EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-  EXPECT_FALSE(client.needs_begin_frames());
   client.Reset();
 }
 
 TEST(SchedulerTest, SyntheticBeginFrames_SwapThrottled) {
-  bool begin_frame_scheduling_enabled = false;
+  bool use_external_begin_frame_source = false;
   bool throttle_frame_production = true;
-  BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+  BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
                                          throttle_frame_production);
 }
 
 TEST(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) {
-  bool begin_frame_scheduling_enabled = true;
+  bool use_external_begin_frame_source = true;
   bool throttle_frame_production = false;
-  BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+  BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
                                          throttle_frame_production);
 }
 
 TEST(SchedulerTest,
      SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) {
-  bool begin_frame_scheduling_enabled = false;
+  bool use_external_begin_frame_source = false;
   bool throttle_frame_production = false;
-  BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+  BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
                                          throttle_frame_production);
 }
 
 TEST(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1605,6 +1633,7 @@
 TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1643,6 +1672,7 @@
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
   scheduler_settings.impl_side_painting = impl_side_painting;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1710,6 +1740,7 @@
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
   scheduler_settings.impl_side_painting = impl_side_painting;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1760,6 +1791,7 @@
 TEST(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsManageTiles) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1790,6 +1822,7 @@
 TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1806,7 +1839,7 @@
   client.Reset();
   BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
   args.deadline += base::TimeDelta::FromHours(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
@@ -1814,9 +1847,9 @@
 
   // Queue BeginFrames while we are still handling the previous BeginFrame.
   args.frame_time += base::TimeDelta::FromSeconds(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   args.frame_time += base::TimeDelta::FromSeconds(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
 
   // If we don't swap on the deadline, we wait for the next BeginImplFrame.
   client.Reset();
@@ -1848,6 +1881,7 @@
 TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1864,7 +1898,7 @@
   client.Reset();
   BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
   args.deadline += base::TimeDelta::FromHours(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
   EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
@@ -1872,9 +1906,9 @@
 
   // Queue BeginFrames while we are still handling the previous BeginFrame.
   args.frame_time += base::TimeDelta::FromSeconds(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
   args.frame_time += base::TimeDelta::FromSeconds(1);
-  client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+  client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
 
   // If we don't swap on the deadline, we wait for the next BeginImplFrame.
   client.Reset();
@@ -1921,7 +1955,6 @@
      StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
-  scheduler_settings.begin_frame_scheduling_enabled = false;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -1963,6 +1996,7 @@
   FakeSchedulerClient client;
   SchedulerSettings scheduler_settings;
   scheduler_settings.impl_side_painting = true;
+  scheduler_settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
   scheduler->SetCanStart();
   scheduler->SetVisible(true);
@@ -2063,6 +2097,7 @@
      SimulateWindowsLowResolutionTimerOnBattery_PrioritizeImplLatencyOff) {
   FakeSchedulerClient client;
   SchedulerSettings settings;
+  settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(settings);
 
   scheduler->SetCanStart();
@@ -2108,6 +2143,7 @@
   FakeSchedulerClient client;
   SchedulerSettings settings;
   settings.disable_hi_res_timer_tasks_on_battery = true;
+  settings.use_external_begin_frame_source = true;
   TestScheduler* scheduler = client.CreateScheduler(settings);
 
   scheduler->SetCanStart();
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index 5f80d64..5935534 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -63,7 +63,6 @@
   void CommitVSyncParameters(base::TimeTicks timebase,
                              base::TimeDelta interval) override;
   void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override {}
-  void BeginFrame(const BeginFrameArgs& args) override {}
   void DidSwapBuffers() override;
   void DidSwapBuffersComplete() override;
   void ReclaimResources(const CompositorFrameAck* ack) override {}
diff --git a/cc/test/animation_test_common.cc b/cc/test/animation_test_common.cc
index 5ab8942..fba3166 100644
--- a/cc/test/animation_test_common.cc
+++ b/cc/test/animation_test_common.cc
@@ -124,14 +124,16 @@
 }
 
 FakeFloatAnimationCurve::FakeFloatAnimationCurve()
-    : duration_(1.0) {}
+    : duration_(base::TimeDelta::FromSecondsD(1.0)) {
+}
 
 FakeFloatAnimationCurve::FakeFloatAnimationCurve(double duration)
-    : duration_(duration) {}
+    : duration_(base::TimeDelta::FromSecondsD(duration)) {
+}
 
 FakeFloatAnimationCurve::~FakeFloatAnimationCurve() {}
 
-double FakeFloatAnimationCurve::Duration() const {
+base::TimeDelta FakeFloatAnimationCurve::Duration() const {
   return duration_;
 }
 
@@ -144,11 +146,12 @@
 }
 
 FakeTransformTransition::FakeTransformTransition(double duration)
-    : duration_(duration) {}
+    : duration_(base::TimeDelta::FromSecondsD(duration)) {
+}
 
 FakeTransformTransition::~FakeTransformTransition() {}
 
-double FakeTransformTransition::Duration() const {
+base::TimeDelta FakeTransformTransition::Duration() const {
   return duration_;
 }
 
@@ -175,18 +178,18 @@
   return make_scoped_ptr(new FakeTransformTransition(*this));
 }
 
-
 FakeFloatTransition::FakeFloatTransition(double duration, float from, float to)
-    : duration_(duration), from_(from), to_(to) {}
+    : duration_(base::TimeDelta::FromSecondsD(duration)), from_(from), to_(to) {
+}
 
 FakeFloatTransition::~FakeFloatTransition() {}
 
-double FakeFloatTransition::Duration() const {
+base::TimeDelta FakeFloatTransition::Duration() const {
   return duration_;
 }
 
 float FakeFloatTransition::GetValue(double time) const {
-  time /= duration_;
+  time /= duration_.InSecondsF();
   if (time >= 1.0)
     time = 1.0;
   return (1.0 - time) * from_ + time * to_;
diff --git a/cc/test/animation_test_common.h b/cc/test/animation_test_common.h
index 328ae84..a69f0c9 100644
--- a/cc/test/animation_test_common.h
+++ b/cc/test/animation_test_common.h
@@ -26,12 +26,12 @@
   explicit FakeFloatAnimationCurve(double duration);
   ~FakeFloatAnimationCurve() override;
 
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   float GetValue(double now) const override;
   scoped_ptr<AnimationCurve> Clone() const override;
 
  private:
-  double duration_;
+  base::TimeDelta duration_;
 };
 
 class FakeTransformTransition : public TransformAnimationCurve {
@@ -39,7 +39,7 @@
   explicit FakeTransformTransition(double duration);
   ~FakeTransformTransition() override;
 
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   gfx::Transform GetValue(double time) const override;
   bool AnimatedBoundsForBox(const gfx::BoxF& box,
                             gfx::BoxF* bounds) const override;
@@ -51,7 +51,7 @@
   scoped_ptr<AnimationCurve> Clone() const override;
 
  private:
-  double duration_;
+  base::TimeDelta duration_;
 };
 
 class FakeFloatTransition : public FloatAnimationCurve {
@@ -59,13 +59,13 @@
   FakeFloatTransition(double duration, float from, float to);
   ~FakeFloatTransition() override;
 
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   float GetValue(double time) const override;
 
   scoped_ptr<AnimationCurve> Clone() const override;
 
  private:
-  double duration_;
+  base::TimeDelta duration_;
   float from_;
   float to_;
 };
diff --git a/cc/test/data/background_filter_blur_off_axis.png b/cc/test/data/background_filter_blur_off_axis.png
index 050ec54..5077171 100644
--- a/cc/test/data/background_filter_blur_off_axis.png
+++ b/cc/test/data/background_filter_blur_off_axis.png
Binary files differ
diff --git a/cc/test/data/background_filter_blur_outsets.png b/cc/test/data/background_filter_blur_outsets.png
index 9234496..3293ab8 100644
--- a/cc/test/data/background_filter_blur_outsets.png
+++ b/cc/test/data/background_filter_blur_outsets.png
Binary files differ
diff --git a/cc/test/data/blending_and_filter.png b/cc/test/data/blending_and_filter.png
index 07e7fea..f231475 100644
--- a/cc/test/data/blending_and_filter.png
+++ b/cc/test/data/blending_and_filter.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass.png b/cc/test/data/blending_render_pass.png
index 76fe369..9186864 100644
--- a/cc/test/data/blending_render_pass.png
+++ b/cc/test/data/blending_render_pass.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass_mask.png b/cc/test/data/blending_render_pass_mask.png
index 8b63f35..21d792a 100644
--- a/cc/test/data/blending_render_pass_mask.png
+++ b/cc/test/data/blending_render_pass_mask.png
Binary files differ
diff --git a/cc/test/data/blending_transparent.png b/cc/test/data/blending_transparent.png
index dc20808..f98607e 100644
--- a/cc/test/data/blending_transparent.png
+++ b/cc/test/data/blending_transparent.png
Binary files differ
diff --git a/cc/test/data/blending_with_root.png b/cc/test/data/blending_with_root.png
index 519c642..276df1d 100644
--- a/cc/test/data/blending_with_root.png
+++ b/cc/test/data/blending_with_root.png
Binary files differ
diff --git a/cc/test/data/filter_on_scaled_layer.png b/cc/test/data/filter_on_scaled_layer.png
new file mode 100644
index 0000000..83cb2c5
--- /dev/null
+++ b/cc/test/data/filter_on_scaled_layer.png
Binary files differ
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index d7b4704..3c44994 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -23,6 +23,7 @@
   void DidSwapBuffersCompleteOnImplThread() override {}
   void OnCanDrawStateChanged(bool can_draw) override {}
   void NotifyReadyToActivate() override {}
+  void NotifyReadyToDraw() override {}
   void SetNeedsRedrawOnImplThread() override {}
   void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) override {}
   void SetNeedsAnimateOnImplThread() override {}
diff --git a/cc/test/fake_output_surface.cc b/cc/test/fake_output_surface.cc
index df9c0f7..46efba0 100644
--- a/cc/test/fake_output_surface.cc
+++ b/cc/test/fake_output_surface.cc
@@ -20,9 +20,7 @@
     : OutputSurface(context_provider),
       client_(NULL),
       num_sent_frames_(0),
-      needs_begin_frame_(false),
-      has_external_stencil_test_(false),
-      fake_weak_ptr_factory_(this) {
+      has_external_stencil_test_(false) {
   if (delegated_rendering) {
     capabilities_.delegated_rendering = true;
     capabilities_.max_frames_pending = 1;
@@ -35,8 +33,7 @@
     : OutputSurface(software_device.Pass()),
       client_(NULL),
       num_sent_frames_(0),
-      has_external_stencil_test_(false),
-      fake_weak_ptr_factory_(this) {
+      has_external_stencil_test_(false) {
   if (delegated_rendering) {
     capabilities_.delegated_rendering = true;
     capabilities_.max_frames_pending = 1;
@@ -50,8 +47,7 @@
     : OutputSurface(context_provider, software_device.Pass()),
       client_(NULL),
       num_sent_frames_(0),
-      has_external_stencil_test_(false),
-      fake_weak_ptr_factory_(this) {
+      has_external_stencil_test_(false) {
   if (delegated_rendering) {
     capabilities_.delegated_rendering = true;
     capabilities_.max_frames_pending = 1;
@@ -82,24 +78,6 @@
   client_->DidSwapBuffers();
 }
 
-void FakeOutputSurface::SetNeedsBeginFrame(bool enable) {
-  needs_begin_frame_ = enable;
-  OutputSurface::SetNeedsBeginFrame(enable);
-
-  if (enable) {
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        base::Bind(&FakeOutputSurface::OnBeginFrame,
-                   fake_weak_ptr_factory_.GetWeakPtr()),
-        base::TimeDelta::FromMilliseconds(16));
-  }
-}
-
-void FakeOutputSurface::OnBeginFrame() {
-  client_->BeginFrame(CreateBeginFrameArgsForTesting());
-}
-
-
 bool FakeOutputSurface::BindToClient(OutputSurfaceClient* client) {
   if (OutputSurface::BindToClient(client)) {
     client_ = client;
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index 59c9a8c..f28fccc 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -94,9 +94,6 @@
 
   void SwapBuffers(CompositorFrame* frame) override;
 
-  void SetNeedsBeginFrame(bool enable) override;
-  bool needs_begin_frame() const { return needs_begin_frame_; }
-
   bool BindToClient(OutputSurfaceClient* client) override;
 
   using OutputSurface::ReleaseGL;
@@ -137,18 +134,13 @@
       scoped_ptr<SoftwareOutputDevice> software_device,
       bool delegated_rendering);
 
-  void OnBeginFrame();
-
   OutputSurfaceClient* client_;
   CompositorFrame last_sent_frame_;
   size_t num_sent_frames_;
-  bool needs_begin_frame_;
   bool has_external_stencil_test_;
   TransferableResourceArray resources_held_by_parent_;
   scoped_ptr<ManagedMemoryPolicy> memory_policy_to_set_at_bind_;
   gfx::Rect last_swap_rect_;
-
-  base::WeakPtrFactory<FakeOutputSurface> fake_weak_ptr_factory_;
 };
 
 }  // namespace cc
diff --git a/cc/test/fake_output_surface_client.cc b/cc/test/fake_output_surface_client.cc
index 77c7f8a..073a29f 100644
--- a/cc/test/fake_output_surface_client.cc
+++ b/cc/test/fake_output_surface_client.cc
@@ -16,10 +16,6 @@
     output_surface_->ReleaseContextProvider();
 }
 
-void FakeOutputSurfaceClient::BeginFrame(const BeginFrameArgs& args) {
-  begin_frame_count_++;
-}
-
 void FakeOutputSurfaceClient::DidSwapBuffers() {
   swap_count_++;
 }
diff --git a/cc/test/fake_output_surface_client.h b/cc/test/fake_output_surface_client.h
index a7620b6..310842d 100644
--- a/cc/test/fake_output_surface_client.h
+++ b/cc/test/fake_output_surface_client.h
@@ -16,7 +16,6 @@
  public:
   FakeOutputSurfaceClient()
       : output_surface_(NULL),
-        begin_frame_count_(0),
         swap_count_(0),
         deferred_initialize_called_(false),
         did_lose_output_surface_called_(false),
@@ -24,7 +23,6 @@
 
   explicit FakeOutputSurfaceClient(OutputSurface* output_surface)
       : output_surface_(output_surface),
-        begin_frame_count_(0),
         swap_count_(0),
         deferred_initialize_called_(false),
         did_lose_output_surface_called_(false),
@@ -35,7 +33,6 @@
   void CommitVSyncParameters(base::TimeTicks timebase,
                              base::TimeDelta interval) override {}
   void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override {}
-  void BeginFrame(const BeginFrameArgs& args) override;
   void DidSwapBuffers() override;
   void DidSwapBuffersComplete() override {}
   void ReclaimResources(const CompositorFrameAck* ack) override {}
@@ -50,7 +47,6 @@
   void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
   void SetTreeActivationCallback(const base::Closure&) override {}
 
-  int begin_frame_count() { return begin_frame_count_; }
   int swap_count() { return swap_count_; }
 
   bool deferred_initialize_called() {
@@ -65,7 +61,6 @@
 
  private:
   OutputSurface* output_surface_;
-  int begin_frame_count_;
   int swap_count_;
   bool deferred_initialize_called_;
   bool did_lose_output_surface_called_;
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index 73c1ae3..bf55ebf 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -10,31 +10,33 @@
 
 namespace cc {
 
-FakePictureLayerImpl::FakePictureLayerImpl(LayerTreeImpl* tree_impl,
-                                           int id,
-                                           scoped_refptr<PicturePileImpl> pile)
+FakePictureLayerImpl::FakePictureLayerImpl(
+    LayerTreeImpl* tree_impl,
+    int id,
+    scoped_refptr<RasterSource> raster_source)
     : PictureLayerImpl(tree_impl, id),
       append_quads_count_(0),
       did_become_active_call_count_(0),
       has_valid_tile_priorities_(false),
       use_set_valid_tile_priorities_flag_(false),
       release_resources_count_(0) {
-  pile_ = pile;
-  SetBounds(pile_->tiling_size());
-  SetContentBounds(pile_->tiling_size());
+  raster_source_ = raster_source;
+  SetBounds(raster_source_->GetSize());
+  SetContentBounds(raster_source_->GetSize());
 }
 
-FakePictureLayerImpl::FakePictureLayerImpl(LayerTreeImpl* tree_impl,
-                                           int id,
-                                           scoped_refptr<PicturePileImpl> pile,
-                                           const gfx::Size& layer_bounds)
+FakePictureLayerImpl::FakePictureLayerImpl(
+    LayerTreeImpl* tree_impl,
+    int id,
+    scoped_refptr<RasterSource> raster_source,
+    const gfx::Size& layer_bounds)
     : PictureLayerImpl(tree_impl, id),
       append_quads_count_(0),
       did_become_active_call_count_(0),
       has_valid_tile_priorities_(false),
       use_set_valid_tile_priorities_flag_(false),
       release_resources_count_(0) {
-  pile_ = pile;
+  raster_source_ = raster_source;
   SetBounds(layer_bounds);
   SetContentBounds(layer_bounds);
 }
@@ -97,12 +99,13 @@
   return result;
 }
 
-void FakePictureLayerImpl::SetPile(scoped_refptr<PicturePileImpl> pile) {
-  pile_.swap(pile);
+void FakePictureLayerImpl::SetRasterSource(
+    scoped_refptr<RasterSource> raster_source) {
+  raster_source_.swap(raster_source);
   if (tilings()) {
     for (size_t i = 0; i < num_tilings(); ++i) {
-      tilings()->tiling_at(i)->UpdateTilesToCurrentPile(Region(),
-                                                        pile_->tiling_size());
+      tilings()->tiling_at(i)->UpdateTilesToCurrentRasterSource(
+          Region(), raster_source_->GetSize());
     }
   }
 }
@@ -190,6 +193,65 @@
              : PictureLayerImpl::HasValidTilePriorities();
 }
 
+size_t FakePictureLayerImpl::CountTilesRequired(
+    TileRequirementCheck is_tile_required_callback) const {
+  if (!HasValidTilePriorities())
+    return 0;
+
+  if (!tilings_)
+    return 0;
+
+  if (visible_rect_for_tile_priority_.IsEmpty())
+    return 0;
+
+  gfx::Rect rect = GetViewportForTilePriorityInContentSpace();
+  rect.Intersect(visible_rect_for_tile_priority_);
+
+  size_t count = 0;
+
+  for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = tilings_->tiling_at(i);
+    if (tiling->resolution() != HIGH_RESOLUTION &&
+        tiling->resolution() != LOW_RESOLUTION)
+      continue;
+
+    for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
+         ++iter) {
+      const Tile* tile = *iter;
+      // A null tile (i.e. missing recording) can just be skipped.
+      // TODO(vmpstr): Verify this is true if we create tiles in raster
+      // iterators.
+      if (!tile)
+        continue;
+
+      // We can't check tile->required_for_activation, because that value might
+      // be out of date. It is updated in the raster/eviction iterators.
+      // TODO(vmpstr): Remove the comment once you can't access this information
+      // from the tile.
+      if ((tiling->*is_tile_required_callback)(tile))
+        ++count;
+    }
+  }
+
+  return count;
+}
+
+size_t FakePictureLayerImpl::CountTilesRequiredForActivation() const {
+  if (!layer_tree_impl()->IsPendingTree())
+    return 0;
+
+  return CountTilesRequired(
+      &PictureLayerTiling::IsTileRequiredForActivationIfVisible);
+}
+
+size_t FakePictureLayerImpl::CountTilesRequiredForDraw() const {
+  if (!layer_tree_impl()->IsActiveTree())
+    return 0;
+
+  return CountTilesRequired(
+      &PictureLayerTiling::IsTileRequiredForDrawIfVisible);
+}
+
 void FakePictureLayerImpl::ReleaseResources() {
   PictureLayerImpl::ReleaseResources();
   ++release_resources_count_;
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index 4223811..b10b357 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -17,20 +17,23 @@
     return make_scoped_ptr(new FakePictureLayerImpl(tree_impl, id));
   }
 
-  // Create layer from a pile that covers the entire layer.
-  static scoped_ptr<FakePictureLayerImpl> CreateWithPile(
-      LayerTreeImpl* tree_impl, int id, scoped_refptr<PicturePileImpl> pile) {
-    return make_scoped_ptr(new FakePictureLayerImpl(tree_impl, id, pile));
-  }
-
-  // Create layer from a pile that only covers part of the layer.
-  static scoped_ptr<FakePictureLayerImpl> CreateWithPartialPile(
+  // Create layer from a raster source that covers the entire layer.
+  static scoped_ptr<FakePictureLayerImpl> CreateWithRasterSource(
       LayerTreeImpl* tree_impl,
       int id,
-      scoped_refptr<PicturePileImpl> pile,
+      scoped_refptr<RasterSource> raster_source) {
+    return make_scoped_ptr(
+        new FakePictureLayerImpl(tree_impl, id, raster_source));
+  }
+
+  // Create layer from a raster source that only covers part of the layer.
+  static scoped_ptr<FakePictureLayerImpl> CreateWithPartialRasterSource(
+      LayerTreeImpl* tree_impl,
+      int id,
+      scoped_refptr<RasterSource> raster_source,
       const gfx::Size& layer_bounds) {
     return make_scoped_ptr(
-        new FakePictureLayerImpl(tree_impl, id, pile, layer_bounds));
+        new FakePictureLayerImpl(tree_impl, id, raster_source, layer_bounds));
   }
 
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
@@ -50,6 +53,11 @@
     use_set_valid_tile_priorities_flag_ = true;
   }
 
+  size_t CountTilesRequired(
+      TileRequirementCheck is_tile_required_callback) const;
+  size_t CountTilesRequiredForActivation() const;
+  size_t CountTilesRequiredForDraw() const;
+
   using PictureLayerImpl::AddTiling;
   using PictureLayerImpl::CleanUpTilingsOnActiveLayer;
   using PictureLayerImpl::CanHaveTilings;
@@ -58,7 +66,7 @@
   using PictureLayerImpl::GetViewportForTilePriorityInContentSpace;
   using PictureLayerImpl::SanityCheckTilingState;
   using PictureLayerImpl::GetRecycledTwinLayer;
-  using PictureLayerImpl::UpdatePile;
+  using PictureLayerImpl::UpdateRasterSource;
 
   using PictureLayerImpl::UpdateIdealScales;
   using PictureLayerImpl::MaximumTilingContentsScale;
@@ -82,8 +90,8 @@
   size_t num_tilings() const { return tilings_->num_tilings(); }
 
   PictureLayerTilingSet* tilings() { return tilings_.get(); }
-  PicturePileImpl* pile() { return pile_.get(); }
-  void SetPile(scoped_refptr<PicturePileImpl> pile);
+  RasterSource* raster_source() { return raster_source_.get(); }
+  void SetRasterSource(scoped_refptr<RasterSource> raster_source);
   size_t append_quads_count() { return append_quads_count_; }
 
   const Region& invalidation() const { return invalidation_; }
@@ -113,13 +121,12 @@
   }
 
  protected:
-  FakePictureLayerImpl(
-      LayerTreeImpl* tree_impl,
-      int id,
-      scoped_refptr<PicturePileImpl> pile);
   FakePictureLayerImpl(LayerTreeImpl* tree_impl,
                        int id,
-                       scoped_refptr<PicturePileImpl> pile,
+                       scoped_refptr<RasterSource> raster_source);
+  FakePictureLayerImpl(LayerTreeImpl* tree_impl,
+                       int id,
+                       scoped_refptr<RasterSource> raster_source,
                        const gfx::Size& layer_bounds);
   FakePictureLayerImpl(LayerTreeImpl* tree_impl, int id);
 
diff --git a/cc/test/fake_picture_layer_tiling_client.cc b/cc/test/fake_picture_layer_tiling_client.cc
index 2149ff4..a218a21 100644
--- a/cc/test/fake_picture_layer_tiling_client.cc
+++ b/cc/test/fake_picture_layer_tiling_client.cc
@@ -17,6 +17,7 @@
       twin_tiling_(NULL),
       recycled_twin_tiling_(NULL),
       allow_create_tile_(true),
+      max_tile_priority_bin_(TilePriority::NOW),
       max_tiles_for_interest_area_(10000),
       skewport_target_time_in_seconds_(1.0f),
       skewport_extrapolation_limit_in_content_pixels_(2000) {
@@ -32,6 +33,7 @@
       twin_tiling_(NULL),
       recycled_twin_tiling_(NULL),
       allow_create_tile_(true),
+      max_tile_priority_bin_(TilePriority::NOW),
       max_tiles_for_interest_area_(10000),
       skewport_target_time_in_seconds_(1.0f) {
 }
@@ -60,6 +62,11 @@
   return tile_size_;
 }
 
+TilePriority::PriorityBin FakePictureLayerTilingClient::GetMaxTilePriorityBin()
+    const {
+  return max_tile_priority_bin_;
+}
+
 size_t FakePictureLayerTilingClient::GetMaxTilesForInterestArea() const {
   return max_tiles_for_interest_area_;
 }
diff --git a/cc/test/fake_picture_layer_tiling_client.h b/cc/test/fake_picture_layer_tiling_client.h
index 3df4ca4..c8cc4e2 100644
--- a/cc/test/fake_picture_layer_tiling_client.h
+++ b/cc/test/fake_picture_layer_tiling_client.h
@@ -25,6 +25,7 @@
                                  const gfx::Rect& rect) override;
   RasterSource* GetRasterSource() override;
   gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override;
+  TilePriority::PriorityBin GetMaxTilePriorityBin() const override;
   size_t GetMaxTilesForInterestArea() const override;
   float GetSkewportTargetTimeInSeconds() const override;
   int GetSkewportExtrapolationLimitInContentPixels() const override;
@@ -47,6 +48,9 @@
   void set_text_rect(const gfx::Rect& rect) { text_rect_ = rect; }
   void set_allow_create_tile(bool allow) { allow_create_tile_ = allow; }
   void set_invalidation(const Region& region) { invalidation_ = region; }
+  void set_max_tile_priority_bin(TilePriority::PriorityBin bin) {
+    max_tile_priority_bin_ = bin;
+  }
   void set_max_tiles_for_interest_area(size_t area) {
     max_tiles_for_interest_area_ = area;
   }
@@ -73,6 +77,7 @@
   gfx::Rect text_rect_;
   bool allow_create_tile_;
   Region invalidation_;
+  TilePriority::PriorityBin max_tile_priority_bin_;
   size_t max_tiles_for_interest_area_;
   float skewport_target_time_in_seconds_;
   int skewport_extrapolation_limit_in_content_pixels_;
diff --git a/cc/test/fake_picture_pile.h b/cc/test/fake_picture_pile.h
new file mode 100644
index 0000000..e486e3b
--- /dev/null
+++ b/cc/test/fake_picture_pile.h
@@ -0,0 +1,53 @@
+// 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_TEST_FAKE_PICTURE_PILE_H_
+#define CC_TEST_FAKE_PICTURE_PILE_H_
+
+#include "cc/resources/picture_pile.h"
+
+namespace cc {
+
+class FakePicturePile : public PicturePile {
+ public:
+  ~FakePicturePile() override {}
+
+  using PicturePile::buffer_pixels;
+  using PicturePile::CanRasterSlowTileCheck;
+  using PicturePile::Clear;
+
+  PictureMap& picture_map() { return picture_map_; }
+  const gfx::Rect& recorded_viewport() const { return recorded_viewport_; }
+
+  bool CanRasterLayerRect(gfx::Rect layer_rect) {
+    layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
+    if (recorded_viewport_.Contains(layer_rect))
+      return true;
+    return CanRasterSlowTileCheck(layer_rect);
+  }
+
+  bool HasRecordings() const { return has_any_recordings_; }
+
+  void SetRecordedViewport(const gfx::Rect& viewport) {
+    recorded_viewport_ = viewport;
+  }
+
+  void SetHasAnyRecordings(bool has_recordings) {
+    has_any_recordings_ = has_recordings;
+  }
+
+  TilingData& tiling() { return tiling_; }
+
+  bool is_solid_color() const { return is_solid_color_; }
+  SkColor solid_color() const { return solid_color_; }
+
+  void SetPixelRecordDistance(int d) { pixel_record_distance_ = d; }
+
+  typedef PicturePile::PictureInfo PictureInfo;
+  typedef PicturePile::PictureMapKey PictureMapKey;
+  typedef PicturePile::PictureMap PictureMap;
+};
+}  // namespace cc
+
+#endif  // CC_TEST_FAKE_PICTURE_PILE_H_
diff --git a/cc/test/fake_picture_pile_impl.cc b/cc/test/fake_picture_pile_impl.cc
index 32a6589..3d31c12 100644
--- a/cc/test/fake_picture_pile_impl.cc
+++ b/cc/test/fake_picture_pile_impl.cc
@@ -4,9 +4,12 @@
 
 #include "cc/test/fake_picture_pile_impl.h"
 
+#include <algorithm>
 #include <limits>
 #include <utility>
 
+#include "cc/resources/picture_pile.h"
+#include "cc/test/fake_picture_pile.h"
 #include "cc/test/impl_side_painting_settings.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -14,62 +17,71 @@
 
 FakePicturePileImpl::FakePicturePileImpl() {}
 
+FakePicturePileImpl::FakePicturePileImpl(const PicturePile* other)
+    : PicturePileImpl(other),
+      tile_grid_info_(other->GetTileGridInfoForTesting()) {
+}
+
 FakePicturePileImpl::~FakePicturePileImpl() {}
 
 scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateFilledPile(
     const gfx::Size& tile_size,
     const gfx::Size& layer_bounds) {
-  scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl());
-  pile->tiling().SetTilingSize(layer_bounds);
-  pile->tiling().SetMaxTextureSize(tile_size);
-  pile->SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
-  pile->recorded_viewport_ = gfx::Rect(layer_bounds);
-  pile->has_any_recordings_ = true;
-  for (int x = 0; x < pile->tiling().num_tiles_x(); ++x) {
-    for (int y = 0; y < pile->tiling().num_tiles_y(); ++y)
-      pile->AddRecordingAt(x, y);
+  FakePicturePile pile;
+  pile.tiling().SetTilingSize(layer_bounds);
+  pile.tiling().SetMaxTextureSize(tile_size);
+  pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
+  pile.SetRecordedViewport(gfx::Rect(layer_bounds));
+  pile.SetHasAnyRecordings(true);
+
+  auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile));
+  for (int x = 0; x < pile_impl->tiling().num_tiles_x(); ++x) {
+    for (int y = 0; y < pile_impl->tiling().num_tiles_y(); ++y)
+      pile_impl->AddRecordingAt(x, y);
   }
-  return pile;
+  return pile_impl;
 }
 
 scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateEmptyPile(
     const gfx::Size& tile_size,
     const gfx::Size& layer_bounds) {
-  scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl());
-  pile->tiling().SetTilingSize(layer_bounds);
-  pile->tiling().SetMaxTextureSize(tile_size);
-  pile->SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
-  pile->recorded_viewport_ = gfx::Rect();
-  pile->has_any_recordings_ = false;
-  return pile;
+  FakePicturePile pile;
+  pile.tiling().SetTilingSize(layer_bounds);
+  pile.tiling().SetMaxTextureSize(tile_size);
+  pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
+  pile.SetRecordedViewport(gfx::Rect());
+  pile.SetHasAnyRecordings(false);
+  return make_scoped_refptr(new FakePicturePileImpl(&pile));
 }
 
 scoped_refptr<FakePicturePileImpl>
 FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
     const gfx::Size& tile_size,
     const gfx::Size& layer_bounds) {
-  scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl());
-  pile->tiling().SetTilingSize(layer_bounds);
-  pile->tiling().SetMaxTextureSize(tile_size);
-  pile->SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
+  FakePicturePile pile;
+  pile.tiling().SetTilingSize(layer_bounds);
+  pile.tiling().SetMaxTextureSize(tile_size);
+  pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
   // This simulates a false positive for this flag.
-  pile->recorded_viewport_ = gfx::Rect();
-  pile->has_any_recordings_ = true;
-  return pile;
+  pile.SetRecordedViewport(gfx::Rect());
+  pile.SetHasAnyRecordings(true);
+  return make_scoped_refptr(new FakePicturePileImpl(&pile));
 }
 
 scoped_refptr<FakePicturePileImpl>
 FakePicturePileImpl::CreateInfiniteFilledPile() {
-  scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl());
+  FakePicturePile pile;
   gfx::Size size(std::numeric_limits<int>::max(),
                  std::numeric_limits<int>::max());
-  pile->tiling().SetTilingSize(size);
-  pile->tiling().SetMaxTextureSize(size);
-  pile->SetTileGridSize(size);
-  pile->recorded_viewport_ = gfx::Rect(size);
-  pile->has_any_recordings_ = true;
-  pile->AddRecordingAt(0, 0);
-  return pile;
+  pile.tiling().SetTilingSize(size);
+  pile.tiling().SetMaxTextureSize(size);
+  pile.SetTileGridSize(size);
+  pile.SetRecordedViewport(gfx::Rect(size));
+  pile.SetHasAnyRecordings(true);
+
+  auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile));
+  pile_impl->AddRecordingAt(0, 0);
+  return pile_impl;
 }
 
 void FakePicturePileImpl::AddRecordingAt(int x, int y) {
@@ -103,6 +115,13 @@
   EXPECT_FALSE(HasRecordingAt(x, y));
 }
 
+bool FakePicturePileImpl::HasRecordingAt(int x, int y) const {
+  PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
+  if (found == picture_map_.end())
+    return false;
+  return !!found->second.GetPicture();
+}
+
 void FakePicturePileImpl::RerecordPile() {
   for (int y = 0; y < num_tiles_y(); ++y) {
     for (int x = 0; x < num_tiles_x(); ++x) {
@@ -112,4 +131,37 @@
   }
 }
 
+void FakePicturePileImpl::SetMinContentsScale(float min_contents_scale) {
+  if (min_contents_scale_ == min_contents_scale)
+    return;
+
+  // Picture contents are played back scaled. When the final contents scale is
+  // less than 1 (i.e. low res), then multiple recorded pixels will be used
+  // to raster one final pixel.  To avoid splitting a final pixel across
+  // pictures (which would result in incorrect rasterization due to blending), a
+  // buffer margin is added so that any picture can be snapped to integral
+  // final pixels.
+  //
+  // For example, if a 1/4 contents scale is used, then that would be 3 buffer
+  // pixels, since that's the minimum number of pixels to add so that resulting
+  // content can be snapped to a four pixel aligned grid.
+  int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
+  buffer_pixels = std::max(0, buffer_pixels);
+  SetBufferPixels(buffer_pixels);
+  min_contents_scale_ = min_contents_scale;
+}
+
+void FakePicturePileImpl::SetBufferPixels(int new_buffer_pixels) {
+  if (new_buffer_pixels == buffer_pixels())
+    return;
+
+  Clear();
+  tiling_.SetBorderTexels(new_buffer_pixels);
+}
+
+void FakePicturePileImpl::Clear() {
+  picture_map_.clear();
+  recorded_viewport_ = gfx::Rect();
+}
+
 }  // namespace cc
diff --git a/cc/test/fake_picture_pile_impl.h b/cc/test/fake_picture_pile_impl.h
index 10c769a..f1a9d31 100644
--- a/cc/test/fake_picture_pile_impl.h
+++ b/cc/test/fake_picture_pile_impl.h
@@ -72,12 +72,24 @@
     is_solid_color_ = is_solid_color;
   }
 
+  bool HasRecordingAt(int x, int y) const;
+  void SetIsMask(bool mask) { is_mask_ = mask; }
+
+  int num_tiles_x() const { return tiling_.num_tiles_x(); }
+  int num_tiles_y() const { return tiling_.num_tiles_y(); }
+
+  void SetMinContentsScale(float scale);
+  void SetBufferPixels(int new_buffer_pixels);
+  void Clear();
+
  protected:
   FakePicturePileImpl();
+  explicit FakePicturePileImpl(const PicturePile* other);
   ~FakePicturePileImpl() override;
 
   FakeContentLayerClient client_;
   SkPaint default_paint_;
+  SkTileGridFactory::TileGridInfo tile_grid_info_;
 };
 
 }  // namespace cc
diff --git a/cc/test/fake_tile_manager_client.h b/cc/test/fake_tile_manager_client.h
index 4b42468..94cfca6 100644
--- a/cc/test/fake_tile_manager_client.h
+++ b/cc/test/fake_tile_manager_client.h
@@ -19,6 +19,7 @@
   // TileManagerClient implementation.
   const std::vector<PictureLayerImpl*>& GetPictureLayers() const override;
   void NotifyReadyToActivate() override {}
+  void NotifyReadyToDraw() override {}
   void NotifyTileStateChanged(const Tile* tile) override {}
   void BuildRasterQueue(RasterTilePriorityQueue* queue,
                         TreePriority tree_priority) override {}
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index d1d1962..373959d 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -15,6 +15,7 @@
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/test/animation_test_common.h"
+#include "cc/test/begin_frame_args_test.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/test_context_provider.h"
@@ -53,9 +54,51 @@
       raster_worker_pool, resource_pool, staging_resource_pool);
 }
 
-base::TimeDelta TestHooks::LowFrequencyAnimationInterval() const {
-  return base::TimeDelta::FromMilliseconds(16);
-}
+class ExternalBeginFrameSourceForTest
+    : public BeginFrameSourceMixIn,
+      public NON_EXPORTED_BASE(base::NonThreadSafe) {
+ public:
+  explicit ExternalBeginFrameSourceForTest(double refresh_rate)
+      : milliseconds_per_frame_(1000.0 / refresh_rate),
+        is_ready_(false),
+        weak_ptr_factory_(this) {
+    DetachFromThread();
+  }
+
+  virtual ~ExternalBeginFrameSourceForTest() {
+    DCHECK(CalledOnValidThread());
+  }
+
+  virtual void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
+    DCHECK(CalledOnValidThread());
+    if (needs_begin_frames) {
+      base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&ExternalBeginFrameSourceForTest::TestOnBeginFrame,
+                   weak_ptr_factory_.GetWeakPtr()),
+        base::TimeDelta::FromMilliseconds(milliseconds_per_frame_));
+    }
+  }
+
+  virtual void SetClientReady() override {
+    DCHECK(CalledOnValidThread());
+    is_ready_ = true;
+  }
+
+  bool is_ready() const {
+    return is_ready_;
+  }
+
+  void TestOnBeginFrame() {
+    DCHECK(CalledOnValidThread());
+    CallOnBeginFrame(CreateBeginFrameArgsForTesting());
+  }
+
+ private:
+  double milliseconds_per_frame_;
+  bool is_ready_;
+  base::WeakPtrFactory<ExternalBeginFrameSourceForTest> weak_ptr_factory_;
+};
 
 // Adapts ThreadProxy for test. Injects test hooks for testing.
 class ThreadProxyForTest : public ThreadProxy {
@@ -64,9 +107,14 @@
       TestHooks* test_hooks,
       LayerTreeHost* host,
       scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
+      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source) {
     return make_scoped_ptr(new ThreadProxyForTest(
-        test_hooks, host, main_task_runner, impl_task_runner));
+        test_hooks,
+        host,
+        main_task_runner,
+        impl_task_runner,
+        external_begin_frame_source.Pass()));
   }
 
   ~ThreadProxyForTest() override {}
@@ -109,8 +157,11 @@
       TestHooks* test_hooks,
       LayerTreeHost* host,
       scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
-      : ThreadProxy(host, main_task_runner, impl_task_runner),
+      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source)
+      : ThreadProxy(host, main_task_runner,
+                    impl_task_runner,
+                    external_begin_frame_source.Pass()),
         test_hooks_(test_hooks) {}
 };
 
@@ -214,10 +265,17 @@
   }
 
   void NotifyReadyToActivate() override {
-    if (block_notify_ready_to_activate_for_testing_)
+    if (block_notify_ready_to_activate_for_testing_) {
       notify_ready_to_activate_was_blocked_ = true;
-    else
+    } else {
       client_->NotifyReadyToActivate();
+      test_hooks_->NotifyReadyToActivateOnThread(this);
+    }
+  }
+
+  void NotifyReadyToDraw() override {
+    client_->NotifyReadyToDraw();
+    test_hooks_->NotifyReadyToDrawOnThread(this);
   }
 
   void BlockNotifyReadyToActivateForTesting(bool block) override {
@@ -269,10 +327,6 @@
     test_hooks_->UpdateAnimationState(this, has_unfinished_animation);
   }
 
-  base::TimeDelta LowFrequencyAnimationInterval() const override {
-    return test_hooks_->LowFrequencyAnimationInterval();
-  }
-
  private:
   TestHooks* test_hooks_;
   bool block_notify_ready_to_activate_for_testing_;
@@ -361,7 +415,8 @@
       LayerTreeHostClientForTesting* client,
       const LayerTreeSettings& settings,
       scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
+      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source) {
     scoped_ptr<LayerTreeHostForTesting> layer_tree_host(
         new LayerTreeHostForTesting(test_hooks, client, settings));
     if (impl_task_runner.get()) {
@@ -369,10 +424,14 @@
           ThreadProxyForTest::Create(test_hooks,
                                      layer_tree_host.get(),
                                      main_task_runner,
-                                     impl_task_runner));
+                                     impl_task_runner,
+                                     external_begin_frame_source.Pass()));
     } else {
       layer_tree_host->InitializeForTesting(SingleThreadProxy::Create(
-          layer_tree_host.get(), client, main_task_runner));
+          layer_tree_host.get(),
+          client,
+          main_task_runner,
+          external_begin_frame_source.Pass()));
     }
     return layer_tree_host.Pass();
   }
@@ -417,6 +476,7 @@
 
 LayerTreeTest::LayerTreeTest()
     : output_surface_(nullptr),
+      external_begin_frame_source_(nullptr),
       beginning_(false),
       end_when_begin_returns_(false),
       timed_out_(false),
@@ -546,13 +606,22 @@
 void LayerTreeTest::DoBeginTest() {
   client_ = LayerTreeHostClientForTesting::Create(this);
 
+  scoped_ptr<ExternalBeginFrameSourceForTest> external_begin_frame_source;
+  if (settings_.use_external_begin_frame_source &&
+      settings_.throttle_frame_production) {
+    external_begin_frame_source.reset(
+        new ExternalBeginFrameSourceForTest(settings_.refresh_rate));
+    external_begin_frame_source_ = external_begin_frame_source.get();
+  }
+
   DCHECK(!impl_thread_ || impl_thread_->message_loop_proxy().get());
   layer_tree_host_ = LayerTreeHostForTesting::Create(
       this,
       client_.get(),
       settings_,
       base::MessageLoopProxy::current(),
-      impl_thread_ ? impl_thread_->message_loop_proxy() : NULL);
+      impl_thread_ ? impl_thread_->message_loop_proxy() : NULL,
+      external_begin_frame_source.Pass());
   ASSERT_TRUE(layer_tree_host_);
 
   started_ = true;
@@ -675,6 +744,7 @@
   // Spend less time waiting for BeginFrame because the output is
   // mocked out.
   settings_.refresh_rate = 200.0;
+  settings_.background_animation_rate = 200.0;
   settings_.impl_side_painting = impl_side_painting;
   InitializeSettings(&settings_);
 
@@ -720,6 +790,12 @@
               output_surface->capabilities().delegated_rendering);
   }
   output_surface_ = output_surface.get();
+
+  if (settings_.use_external_begin_frame_source &&
+      settings_.throttle_frame_production) {
+    DCHECK(external_begin_frame_source_);
+    DCHECK(external_begin_frame_source_->is_ready());
+  }
   return output_surface.Pass();
 }
 
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 36d669c..531e28d 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -17,6 +17,7 @@
 }
 
 namespace cc {
+class ExternalBeginFrameSourceForTest;
 class FakeLayerTreeHostClient;
 class FakeOutputSurface;
 class LayerImpl;
@@ -57,6 +58,8 @@
   virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) {}
   virtual void SwapBuffersCompleteOnThread(LayerTreeHostImpl* host_impl) {}
   virtual void UpdateVisibleTilesOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void NotifyReadyToActivateOnThread(LayerTreeHostImpl* host_impl) {}
+  virtual void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) {}
   virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
                              base::TimeTicks monotonic_time) {}
   virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl,
@@ -84,7 +87,6 @@
   virtual void DidDeferCommit() {}
   virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl,
                                        bool visible) {}
-  virtual base::TimeDelta LowFrequencyAnimationInterval() const;
   virtual void ScheduleComposite() {}
 
   // Hooks for SchedulerClient.
@@ -209,6 +211,7 @@
   scoped_ptr<LayerTreeHostClientForTesting> client_;
   scoped_ptr<LayerTreeHost> layer_tree_host_;
   FakeOutputSurface* output_surface_;
+  ExternalBeginFrameSourceForTest* external_begin_frame_source_;
 
   bool beginning_;
   bool end_when_begin_returns_;
@@ -236,12 +239,15 @@
   }                                                                           \
   class SingleThreadDirectNoImplNeedsSemicolon##TEST_FIXTURE_NAME {}
 
-#define SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME)             \
-  SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME);           \
+#define SINGLE_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)        \
   TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DirectRenderer_ImplSidePaint) { \
     RunTest(false, false, true);                                            \
   }                                                                         \
-  class SingleThreadDirectNeedsSemicolon##TEST_FIXTURE_NAME {}
+  class SingleThreadDirectImplNeedsSemicolon##TEST_FIXTURE_NAME {}
+
+#define SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME)   \
+  SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
+  SINGLE_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
 
 #define SINGLE_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME) \
   TEST_F(TEST_FIXTURE_NAME,                                                \
@@ -250,34 +256,44 @@
   }                                                                        \
   class SingleThreadDelegatingNoImplNeedsSemicolon##TEST_FIXTURE_NAME {}
 
+#define SINGLE_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME) \
+  TEST_F(TEST_FIXTURE_NAME,                                              \
+         RunSingleThread_DelegatingRenderer_ImplSidePaint) {             \
+    RunTest(false, true, true);                                          \
+  }                                                                      \
+  class SingleThreadDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {}
+
 #define SINGLE_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)   \
   SINGLE_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
-  TEST_F(TEST_FIXTURE_NAME,                                           \
-         RunSingleThread_DelegatingRenderer_ImplSidePaint) {          \
-    RunTest(false, true, true);                                       \
-  }                                                                   \
-  class SingleThreadDelegatingNeedsSemicolon##TEST_FIXTURE_NAME {}
-
-#define SINGLE_THREAD_TEST_F(TEST_FIXTURE_NAME)            \
-  SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME); \
-  SINGLE_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)
+  SINGLE_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
 
 #define SINGLE_THREAD_NOIMPL_TEST_F(TEST_FIXTURE_NAME)            \
   SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
   SINGLE_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)
 
+#define SINGLE_THREAD_IMPL_TEST_F(TEST_FIXTURE_NAME)            \
+  SINGLE_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME); \
+  SINGLE_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
+
+#define SINGLE_THREAD_TEST_F(TEST_FIXTURE_NAME)            \
+  SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME); \
+  SINGLE_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)
+
 #define MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)        \
   TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DirectRenderer_MainThreadPaint) { \
     RunTest(true, false, false);                                             \
   }                                                                          \
   class MultiThreadDirectNoImplNeedsSemicolon##TEST_FIXTURE_NAME {}
 
-#define MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME)             \
-  MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME);           \
+#define MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)        \
   TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DirectRenderer_ImplSidePaint) { \
     RunTest(true, false, true);                                            \
   }                                                                        \
-  class MultiThreadDirectNeedsSemicolon##TEST_FIXTURE_NAME {}
+  class MultiThreadDirectImplNeedsSemicolon##TEST_FIXTURE_NAME {}
+
+#define MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME)   \
+  MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
+  MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
 
 #define MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME) \
   TEST_F(TEST_FIXTURE_NAME,                                               \
@@ -286,17 +302,24 @@
   }                                                                       \
   class MultiThreadDelegatingNoImplNeedsSemicolon##TEST_FIXTURE_NAME {}
 
-#define MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)             \
-  MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME);           \
+#define MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)        \
   TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DelegatingRenderer_ImplSidePaint) { \
     RunTest(true, true, true);                                                 \
   }                                                                            \
-  class MultiThreadDelegatingNeedsSemicolon##TEST_FIXTURE_NAME {}
+  class MultiThreadDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {}
+
+#define MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)   \
+  MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
+  MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
 
 #define MULTI_THREAD_NOIMPL_TEST_F(TEST_FIXTURE_NAME)            \
   MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
   MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)
 
+#define MULTI_THREAD_IMPL_TEST_F(TEST_FIXTURE_NAME)            \
+  MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME); \
+  MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
+
 #define MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME)            \
   MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME); \
   MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)
@@ -306,6 +329,10 @@
   SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
   MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)
 
+#define SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME) \
+  SINGLE_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME);                \
+  MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
+
 #define SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
   SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME);                \
   MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME)
@@ -315,6 +342,11 @@
   SINGLE_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
   MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)
 
+#define SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(    \
+    TEST_FIXTURE_NAME)                                              \
+  SINGLE_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME); \
+  MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
+
 #define SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
   SINGLE_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME);                \
   MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)
@@ -323,6 +355,10 @@
   SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
   SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)
 
+#define SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(TEST_FIXTURE_NAME)            \
+  SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME); \
+  SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
+
 #define SINGLE_AND_MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME)            \
   SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME); \
   SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)
diff --git a/cc/test/scheduler_test_common.cc b/cc/test/scheduler_test_common.cc
index ef4cefd..61ef0cf 100644
--- a/cc/test/scheduler_test_common.cc
+++ b/cc/test/scheduler_test_common.cc
@@ -84,7 +84,7 @@
     scheduler->primary_frame_source_internal_ =
         TestBackToBackBeginFrameSource::Create(now_src_, test_task_runner_);
     return scheduler->primary_frame_source_internal_.get();
-  } else if (scheduler->settings_.begin_frame_scheduling_enabled) {
+  } else if (scheduler->settings_.use_external_begin_frame_source) {
     return SchedulerFrameSourcesConstructor::ConstructPrimaryFrameSource(
         scheduler);
   } else {
@@ -128,12 +128,14 @@
     int layer_tree_host_id,
     const scoped_refptr<OrderedSimpleTaskRunner>& test_task_runner,
     base::PowerMonitor* power_monitor,
-    TestSchedulerFrameSourcesConstructor* frame_sources_constructor)
+    TestSchedulerFrameSourcesConstructor* frame_sources_constructor,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source)
     : Scheduler(client,
                 scheduler_settings,
                 layer_tree_host_id,
                 test_task_runner,
                 power_monitor,
+                external_begin_frame_source.Pass(),
                 frame_sources_constructor),
       now_src_(now_src) {
 }
diff --git a/cc/test/scheduler_test_common.h b/cc/test/scheduler_test_common.h
index d9cb3cf..ea6b2ef 100644
--- a/cc/test/scheduler_test_common.h
+++ b/cc/test/scheduler_test_common.h
@@ -162,16 +162,19 @@
       const SchedulerSettings& scheduler_settings,
       int layer_tree_host_id,
       const scoped_refptr<OrderedSimpleTaskRunner>& task_runner,
-      base::PowerMonitor* power_monitor) {
+      base::PowerMonitor* power_monitor,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source) {
     TestSchedulerFrameSourcesConstructor frame_sources_constructor(
         task_runner.get(), now_src.get());
-    return make_scoped_ptr(new TestScheduler(now_src,
-                                             client,
-                                             scheduler_settings,
-                                             layer_tree_host_id,
-                                             task_runner,
-                                             power_monitor,
-                                             &frame_sources_constructor));
+    return make_scoped_ptr(new TestScheduler(
+                                   now_src,
+                                   client,
+                                   scheduler_settings,
+                                   layer_tree_host_id,
+                                   task_runner,
+                                   power_monitor,
+                                   &frame_sources_constructor,
+                                   external_begin_frame_source.Pass()));
   }
 
   // Extra test helper functionality
@@ -195,7 +198,8 @@
       int layer_tree_host_id,
       const scoped_refptr<OrderedSimpleTaskRunner>& test_task_runner,
       base::PowerMonitor* power_monitor,
-      TestSchedulerFrameSourcesConstructor* frame_sources_constructor);
+      TestSchedulerFrameSourcesConstructor* frame_sources_constructor,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
 
   scoped_refptr<TestNowSource> now_src_;
 };
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index af7eb5b..f85d4e7 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -32,6 +32,7 @@
 #include "cc/layers/render_surface.h"
 #include "cc/resources/prioritized_resource_manager.h"
 #include "cc/resources/ui_resource_request.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_host_impl.h"
@@ -71,12 +72,15 @@
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     const LayerTreeSettings& settings,
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
   DCHECK(main_task_runner.get());
   DCHECK(impl_task_runner.get());
   scoped_ptr<LayerTreeHost> layer_tree_host(new LayerTreeHost(
       client, shared_bitmap_manager, gpu_memory_buffer_manager, settings));
-  layer_tree_host->InitializeThreaded(main_task_runner, impl_task_runner);
+  layer_tree_host->InitializeThreaded(main_task_runner,
+                                      impl_task_runner,
+                                      external_begin_frame_source.Pass());
   return layer_tree_host.Pass();
 }
 
@@ -86,11 +90,13 @@
     SharedBitmapManager* shared_bitmap_manager,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     const LayerTreeSettings& settings,
-    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
   scoped_ptr<LayerTreeHost> layer_tree_host(new LayerTreeHost(
       client, shared_bitmap_manager, gpu_memory_buffer_manager, settings));
   layer_tree_host->InitializeSingleThreaded(single_thread_client,
-                                            main_task_runner);
+                                            main_task_runner,
+                                            external_begin_frame_source.Pass());
   return layer_tree_host.Pass();
 }
 
@@ -139,16 +145,23 @@
 
 void LayerTreeHost::InitializeThreaded(
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
-  InitializeProxy(
-      ThreadProxy::Create(this, main_task_runner, impl_task_runner));
+    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  InitializeProxy(ThreadProxy::Create(this,
+                                      main_task_runner,
+                                      impl_task_runner,
+                                      external_begin_frame_source.Pass()));
 }
 
 void LayerTreeHost::InitializeSingleThreaded(
     LayerTreeHostSingleThreadClient* single_thread_client,
-    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
   InitializeProxy(
-      SingleThreadProxy::Create(this, single_thread_client, main_task_runner));
+      SingleThreadProxy::Create(this,
+                                single_thread_client,
+                                main_task_runner,
+                                external_begin_frame_source.Pass()));
 }
 
 void LayerTreeHost::InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing) {
@@ -960,7 +973,6 @@
 size_t LayerTreeHost::CalculateMemoryForRenderSurfaces(
     const RenderSurfaceLayerList& update_list) {
   size_t readback_bytes = 0;
-  size_t max_background_texture_bytes = 0;
   size_t contents_texture_bytes = 0;
 
   // Start iteration at 1 to skip the root surface as it does not have a texture
@@ -974,17 +986,16 @@
                                   RGBA_8888);
     contents_texture_bytes += bytes;
 
-    if (render_surface_layer->background_filters().IsEmpty())
+    if (render_surface_layer->background_filters().IsEmpty() &&
+        render_surface_layer->uses_default_blend_mode())
       continue;
 
-    if (bytes > max_background_texture_bytes)
-      max_background_texture_bytes = bytes;
     if (!readback_bytes) {
       readback_bytes = Resource::MemorySizeBytes(device_viewport_size_,
                                                  RGBA_8888);
     }
   }
-  return readback_bytes + max_background_texture_bytes + contents_texture_bytes;
+  return readback_bytes + contents_texture_bytes;
 }
 
 void LayerTreeHost::PaintMasksForRenderSurface(Layer* render_surface_layer,
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index a56a6cd..7820cc2 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -48,6 +48,7 @@
 
 namespace cc {
 class AnimationRegistrar;
+class BeginFrameSource;
 class HeadsUpDisplayLayer;
 class Layer;
 class LayerTreeHostImpl;
@@ -92,7 +93,8 @@
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       const LayerTreeSettings& settings,
       scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
 
   static scoped_ptr<LayerTreeHost> CreateSingleThreaded(
       LayerTreeHostClient* client,
@@ -100,7 +102,8 @@
       SharedBitmapManager* shared_bitmap_manager,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       const LayerTreeSettings& settings,
-      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
   virtual ~LayerTreeHost();
 
   void SetLayerTreeHostClientReady();
@@ -318,10 +321,12 @@
                 const LayerTreeSettings& settings);
   void InitializeThreaded(
       scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
   void InitializeSingleThreaded(
       LayerTreeHostSingleThreadClient* single_thread_client,
-      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
   void InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing);
   void SetOutputSurfaceLostForTesting(bool is_lost) {
     output_surface_lost_ = is_lost;
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index fd15b52..0ff6608 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -1883,6 +1883,7 @@
     render_surface->SetDrawOpacityIsAnimating(animating_opacity_to_target);
     animating_opacity_to_target = false;
     layer_draw_properties.opacity = 1.f;
+    layer_draw_properties.blend_mode = SkXfermode::kSrcOver_Mode;
     layer_draw_properties.opacity_is_animating = animating_opacity_to_target;
     layer_draw_properties.screen_space_opacity_is_animating =
         animating_opacity_to_screen;
@@ -2007,6 +2008,7 @@
     layer_draw_properties.screen_space_transform_is_animating =
         animating_transform_to_screen;
     layer_draw_properties.opacity = accumulated_draw_opacity;
+    layer_draw_properties.blend_mode = layer->blend_mode();
     layer_draw_properties.opacity_is_animating = animating_opacity_to_target;
     layer_draw_properties.screen_space_opacity_is_animating =
         animating_opacity_to_screen;
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index e0436ba..b40f66d 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -1392,6 +1392,36 @@
   EXPECT_EQ(gfx::Rect(), parent->drawable_content_rect());
 }
 
+TEST_F(LayerTreeHostCommonTest, RenderSurfaceForBlendMode) {
+  scoped_refptr<Layer> parent = Layer::Create();
+  scoped_refptr<LayerWithForcedDrawsContent> child =
+      make_scoped_refptr(new LayerWithForcedDrawsContent());
+
+  scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+  host->SetRootLayer(parent);
+
+  const gfx::Transform identity_matrix;
+  const SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode;
+  SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(),
+                               gfx::PointF(), gfx::Size(10, 10), true, false);
+
+  parent->AddChild(child);
+  child->SetBlendMode(blend_mode);
+
+  RenderSurfaceLayerList render_surface_layer_list;
+  LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+      parent.get(), parent->bounds(), &render_surface_layer_list);
+  LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+  // Since the child layer has a blend mode other than normal, it should get
+  // its own render surface. Also, layer's draw_properties should contain the
+  // default blend mode, since the render surface becomes responsible for
+  // applying the blend mode.
+  ASSERT_TRUE(child->render_surface());
+  EXPECT_EQ(1U, child->render_surface()->layer_list().size());
+  EXPECT_EQ(SkXfermode::kSrcOver_Mode, child->draw_properties().blend_mode);
+}
+
 TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) {
   scoped_refptr<Layer> parent = Layer::Create();
   scoped_refptr<Layer> render_surface1 = Layer::Create();
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index d2041ac..696da7a 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -29,6 +29,7 @@
 #include "cc/debug/rendering_stats_instrumentation.h"
 #include "cc/debug/traced_value.h"
 #include "cc/input/page_scale_animation.h"
+#include "cc/input/scroll_elasticity_helper.h"
 #include "cc/input/top_controls_manager.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/heads_up_display_layer_impl.h"
@@ -173,77 +174,6 @@
 
 }  // namespace
 
-class LayerTreeHostImplTimeSourceAdapter : public TimeSourceClient {
- public:
-  static scoped_ptr<LayerTreeHostImplTimeSourceAdapter> Create(
-      LayerTreeHostImpl* layer_tree_host_impl,
-      scoped_refptr<DelayBasedTimeSource> time_source) {
-    return make_scoped_ptr(
-        new LayerTreeHostImplTimeSourceAdapter(layer_tree_host_impl,
-                                               time_source));
-  }
-  ~LayerTreeHostImplTimeSourceAdapter() override {
-    time_source_->SetClient(NULL);
-    time_source_->SetActive(false);
-  }
-
-  void OnTimerTick() override {
-    // In single threaded mode we attempt to simulate changing the current
-    // thread by maintaining a fake thread id. When we switch from one
-    // thread to another, we construct DebugScopedSetXXXThread objects that
-    // update the thread id. This lets DCHECKS that ensure we're on the
-    // right thread to work correctly in single threaded mode. The problem
-    // here is that the timer tasks are run via the message loop, and when
-    // they run, we've had no chance to construct a DebugScopedSetXXXThread
-    // object. The result is that we report that we're running on the main
-    // thread. In multi-threaded mode, this timer is run on the compositor
-    // thread, so to keep this consistent in single-threaded mode, we'll
-    // construct a DebugScopedSetImplThread object. There is no need to do
-    // this in multi-threaded mode since the real thread id's will be
-    // correct. In fact, setting fake thread id's interferes with the real
-    // thread id's and causes breakage.
-    scoped_ptr<DebugScopedSetImplThread> set_impl_thread;
-    if (!layer_tree_host_impl_->proxy()->HasImplThread()) {
-      set_impl_thread.reset(
-          new DebugScopedSetImplThread(layer_tree_host_impl_->proxy()));
-    }
-
-    layer_tree_host_impl_->Animate(
-        layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
-    layer_tree_host_impl_->UpdateBackgroundAnimateTicking(true);
-    bool start_ready_animations = true;
-    layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
-
-    if (layer_tree_host_impl_->pending_tree()) {
-      layer_tree_host_impl_->pending_tree()->UpdateDrawProperties();
-      layer_tree_host_impl_->ManageTiles();
-    }
-
-    layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame();
-  }
-
-  void SetActive(bool active) {
-    if (active != time_source_->Active())
-      time_source_->SetActive(active);
-  }
-
-  bool Active() const { return time_source_->Active(); }
-
- private:
-  LayerTreeHostImplTimeSourceAdapter(
-      LayerTreeHostImpl* layer_tree_host_impl,
-      scoped_refptr<DelayBasedTimeSource> time_source)
-      : layer_tree_host_impl_(layer_tree_host_impl),
-        time_source_(time_source) {
-    time_source_->SetClient(this);
-  }
-
-  LayerTreeHostImpl* layer_tree_host_impl_;
-  scoped_refptr<DelayBasedTimeSource> time_source_;
-
-  DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImplTimeSourceAdapter);
-};
-
 LayerTreeHostImpl::FrameData::FrameData()
     : contains_incomplete_tile(false), has_no_damage(false) {}
 
@@ -274,8 +204,7 @@
     SharedBitmapManager* shared_bitmap_manager,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     int id)
-    : BeginFrameSourceMixIn(),
-      client_(client),
+    : client_(client),
       proxy_(proxy),
       use_gpu_rasterization_(false),
       input_handler_client_(NULL),
@@ -352,6 +281,8 @@
     input_handler_client_->WillShutdown();
     input_handler_client_ = NULL;
   }
+  if (scroll_elasticity_helper_)
+    scroll_elasticity_helper_.reset();
 
   // The layer trees must be destroyed before the layer tree host. We've
   // made a contract with our animation controllers that the registrar
@@ -521,6 +452,12 @@
       new LatencyInfoSwapPromiseMonitor(latency, NULL, this));
 }
 
+ScrollElasticityHelper* LayerTreeHostImpl::CreateScrollElasticityHelper() {
+  DCHECK(!scroll_elasticity_helper_);
+  scroll_elasticity_helper_.reset(new ScrollElasticityHelper(this));
+  return scroll_elasticity_helper_.get();
+}
+
 void LayerTreeHostImpl::QueueSwapPromiseForMainThreadScrollUpdate(
     scoped_ptr<SwapPromise> swap_promise) {
   swap_promises_for_main_thread_scroll_update_.push_back(swap_promise.Pass());
@@ -974,28 +911,6 @@
     input_handler_client_->MainThreadHasStoppedFlinging();
 }
 
-void LayerTreeHostImpl::UpdateBackgroundAnimateTicking(
-    bool should_background_tick) {
-  DCHECK(proxy_->IsImplThread());
-  if (should_background_tick)
-    DCHECK(active_tree_->root_layer());
-
-  bool enabled = should_background_tick && needs_animate_layers();
-
-  // Lazily create the time_source adapter so that we can vary the interval for
-  // testing.
-  if (!time_source_client_adapter_) {
-    time_source_client_adapter_ = LayerTreeHostImplTimeSourceAdapter::Create(
-        this,
-        DelayBasedTimeSource::Create(
-            LowFrequencyAnimationInterval(),
-            proxy_->HasImplThread() ? proxy_->ImplThreadTaskRunner()
-                                    : proxy_->MainThreadTaskRunner()));
-  }
-
-  time_source_client_adapter_->SetActive(enabled);
-}
-
 void LayerTreeHostImpl::DidAnimateScrollOffset() {
   client_->SetNeedsCommitOnImplThread();
   client_->RenewTreePriority();
@@ -1271,7 +1186,8 @@
 }
 
 void LayerTreeHostImpl::GetPictureLayerImplPairs(
-    std::vector<PictureLayerImpl::Pair>* layer_pairs) const {
+    std::vector<PictureLayerImpl::Pair>* layer_pairs,
+    bool need_valid_tile_priorities) const {
   DCHECK(layer_pairs->empty());
   for (std::vector<PictureLayerImpl*>::const_iterator it =
            picture_layers_.begin();
@@ -1279,24 +1195,25 @@
        ++it) {
     PictureLayerImpl* layer = *it;
 
-    // TODO(vmpstr): Iterators and should handle this instead. crbug.com/381704
-    if (!layer->HasValidTilePriorities())
+    if (!layer->IsOnActiveOrPendingTree() ||
+        (need_valid_tile_priorities && !layer->HasValidTilePriorities()))
       continue;
 
     PictureLayerImpl* twin_layer = layer->GetPendingOrActiveTwinLayer();
 
     // Ignore the twin layer when tile priorities are invalid.
-    // TODO(vmpstr): Iterators should handle this instead. crbug.com/381704
-    if (twin_layer && !twin_layer->HasValidTilePriorities())
+    if (need_valid_tile_priorities && twin_layer &&
+        !twin_layer->HasValidTilePriorities())
       twin_layer = NULL;
 
     // If the current tree is ACTIVE_TREE, then always generate a layer_pair.
     // If current tree is PENDING_TREE, then only generate a layer_pair if
     // there is no twin layer.
     if (layer->GetTree() == ACTIVE_TREE) {
-      DCHECK(!twin_layer || twin_layer->GetTree() == PENDING_TREE);
+      DCHECK_IMPLIES(twin_layer, twin_layer->GetTree() == PENDING_TREE);
       layer_pairs->push_back(PictureLayerImpl::Pair(layer, twin_layer));
     } else if (!twin_layer) {
+      DCHECK(layer->GetTree() == PENDING_TREE);
       layer_pairs->push_back(PictureLayerImpl::Pair(NULL, layer));
     }
   }
@@ -1306,7 +1223,7 @@
                                          TreePriority tree_priority) {
   TRACE_EVENT0("cc", "LayerTreeHostImpl::BuildRasterQueue");
   picture_layer_pairs_.clear();
-  GetPictureLayerImplPairs(&picture_layer_pairs_);
+  GetPictureLayerImplPairs(&picture_layer_pairs_, true);
   queue->Build(picture_layer_pairs_, tree_priority);
 }
 
@@ -1314,7 +1231,7 @@
                                            TreePriority tree_priority) {
   TRACE_EVENT0("cc", "LayerTreeHostImpl::BuildEvictionQueue");
   picture_layer_pairs_.clear();
-  GetPictureLayerImplPairs(&picture_layer_pairs_);
+  GetPictureLayerImplPairs(&picture_layer_pairs_, false);
   queue->Build(picture_layer_pairs_, tree_priority);
 }
 
@@ -1327,6 +1244,10 @@
   client_->NotifyReadyToActivate();
 }
 
+void LayerTreeHostImpl::NotifyReadyToDraw() {
+  client_->NotifyReadyToDraw();
+}
+
 void LayerTreeHostImpl::NotifyTileStateChanged(const Tile* tile) {
   TRACE_EVENT0("cc", "LayerTreeHostImpl::NotifyTileStateChanged");
 
@@ -1437,10 +1358,6 @@
   client_->SetNeedsRedrawRectOnImplThread(damage_rect);
 }
 
-void LayerTreeHostImpl::BeginFrame(const BeginFrameArgs& args) {
-  CallOnBeginFrame(args);
-}
-
 void LayerTreeHostImpl::DidSwapBuffers() {
   client_->DidSwapBuffersOnImplThread();
 }
@@ -1543,7 +1460,8 @@
   if (!settings_.impl_side_painting && debug_state_.continuous_painting) {
     const RenderingStats& stats =
         rendering_stats_instrumentation_->GetRenderingStats();
-    paint_time_counter_->SavePaintTime(stats.main_stats.paint_time);
+    paint_time_counter_->SavePaintTime(
+        stats.begin_main_frame_to_commit_duration.GetLastTimeDelta());
   }
 
   bool is_new_trace;
@@ -1678,13 +1596,6 @@
   return true;
 }
 
-void LayerTreeHostImpl::OnNeedsBeginFramesChange(bool enable) {
-  if (output_surface_)
-    output_surface_->SetNeedsBeginFrame(enable);
-  else
-    DCHECK(!enable);
-}
-
 void LayerTreeHostImpl::WillBeginImplFrame(const BeginFrameArgs& args) {
   // Sample the frame time now. This time will be used for updating animations
   // when we draw.
@@ -1883,13 +1794,10 @@
     // TODO(hendrikw): This requires a different metric when we commit directly
     // to the active tree.  See crbug.com/429311.
     paint_time_counter_->SavePaintTime(
-        stats.impl_stats.commit_to_activate_duration.GetLastTimeDelta() +
-        stats.impl_stats.draw_duration.GetLastTimeDelta());
+        stats.commit_to_activate_duration.GetLastTimeDelta() +
+        stats.draw_duration.GetLastTimeDelta());
   }
 
-  if (time_source_client_adapter_ && time_source_client_adapter_->Active())
-    DCHECK(active_tree_->root_layer());
-
   scoped_ptr<PageScaleAnimation> page_scale_animation =
       active_tree_->TakePageScaleAnimation();
   if (page_scale_animation) {
@@ -2195,7 +2103,7 @@
 
   // TODO(brianderson): Don't use a hard-coded parent draw time.
   base::TimeDelta parent_draw_time =
-      (!settings_.begin_frame_scheduling_enabled &&
+      (!settings_.use_external_begin_frame_source &&
        output_surface_->capabilities().adjust_deadline_for_parent)
           ? BeginFrameArgs::DefaultEstimatedParentDrawTime()
           : base::TimeDelta();
@@ -2472,9 +2380,10 @@
     new_target.SetToMax(gfx::ScrollOffset());
     new_target.SetToMin(layer_impl->MaxScrollOffset());
 
-    curve->UpdateTarget(animation->TrimTimeToCurrentIteration(
-                            CurrentBeginFrameArgs().frame_time),
-                        new_target);
+    curve->UpdateTarget(
+        animation->TrimTimeToCurrentIteration(
+                       CurrentBeginFrameArgs().frame_time).InSecondsF(),
+        new_target);
 
     return ScrollStarted;
   }
@@ -2628,21 +2537,19 @@
       CurrentlyScrollingLayer() != OuterViewportScrollLayer())
     return false;
 
-  if (InnerViewportScrollLayer()->MaxScrollOffset().y() > 0)
-    return true;
-
-  if (OuterViewportScrollLayer() &&
-      OuterViewportScrollLayer()->MaxScrollOffset().y() > 0)
+  if (active_tree()->TotalScrollOffset().y() <
+      active_tree()->TotalMaxScrollOffset().y())
     return true;
 
   return false;
 }
 
-bool LayerTreeHostImpl::ScrollBy(const gfx::Point& viewport_point,
-                                 const gfx::Vector2dF& scroll_delta) {
+InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
+    const gfx::Point& viewport_point,
+    const gfx::Vector2dF& scroll_delta) {
   TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBy");
   if (!CurrentlyScrollingLayer())
-    return false;
+    return InputHandlerScrollResult();
 
   gfx::Vector2dF pending_delta = scroll_delta;
   gfx::Vector2dF unused_root_delta;
@@ -2763,15 +2670,14 @@
     accumulated_root_overscroll_.set_x(0);
   if (did_scroll_y)
     accumulated_root_overscroll_.set_y(0);
-
   accumulated_root_overscroll_ += unused_root_delta;
-  bool did_overscroll = !unused_root_delta.IsZero();
-  if (did_overscroll && input_handler_client_) {
-    input_handler_client_->DidOverscroll(
-        viewport_point, accumulated_root_overscroll_, unused_root_delta);
-  }
 
-  return did_scroll_content || did_scroll_top_controls;
+  InputHandlerScrollResult scroll_result;
+  scroll_result.did_scroll = did_scroll_content || did_scroll_top_controls;
+  scroll_result.did_overscroll_root = !unused_root_delta.IsZero();
+  scroll_result.accumulated_root_overscroll = accumulated_root_overscroll_;
+  scroll_result.unused_scroll_delta = unused_root_delta;
+  return scroll_result;
 }
 
 // This implements scrolling by page as described here:
@@ -3197,10 +3103,8 @@
        iter != copy.end();
        ++iter)
     (*iter).second->ActivateAnimations();
-}
 
-base::TimeDelta LayerTreeHostImpl::LowFrequencyAnimationInterval() const {
-  return base::TimeDelta::FromSeconds(1);
+  SetNeedsAnimate();
 }
 
 std::string LayerTreeHostImpl::LayerTreeAsJson() const {
@@ -3287,10 +3191,6 @@
                                 BeginFrameArgs::DefaultInterval());
 }
 
-void LayerTreeHostImpl::AsValueInto(base::debug::TracedValue* value) const {
-  return AsValueWithFrameInto(NULL, value);
-}
-
 scoped_refptr<base::debug::ConvertableToTraceFormat>
 LayerTreeHostImpl::AsValue() const {
   return AsValueWithFrame(NULL);
@@ -3304,6 +3204,10 @@
   return state;
 }
 
+void LayerTreeHostImpl::AsValueInto(base::debug::TracedValue* value) const {
+  return AsValueWithFrameInto(NULL, value);
+}
+
 void LayerTreeHostImpl::AsValueWithFrameInto(
     FrameData* frame,
     base::debug::TracedValue* state) const {
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 157fe00..24cb730 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -31,7 +31,6 @@
 #include "cc/quads/render_pass.h"
 #include "cc/resources/resource_provider.h"
 #include "cc/resources/tile_manager.h"
-#include "cc/scheduler/begin_frame_source.h"
 #include "cc/scheduler/draw_result.h"
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -45,7 +44,6 @@
 class EvictionTilePriorityQueue;
 class FrameRateCounter;
 class LayerImpl;
-class LayerTreeHostImplTimeSourceAdapter;
 class LayerTreeImpl;
 class MemoryHistory;
 class PageScaleAnimation;
@@ -56,6 +54,7 @@
 class RenderPassDrawQuad;
 class RenderingStatsInstrumentation;
 class ResourcePool;
+class ScrollElasticityHelper;
 class ScrollbarLayerImplBase;
 class TextureMailboxDeleter;
 class TopControlsManager;
@@ -76,6 +75,7 @@
   virtual void DidSwapBuffersCompleteOnImplThread() = 0;
   virtual void OnCanDrawStateChanged(bool can_draw) = 0;
   virtual void NotifyReadyToActivate() = 0;
+  virtual void NotifyReadyToDraw() = 0;
   // Please call these 3 functions through
   // LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and
   // SetNeedsAnimate().
@@ -112,7 +112,6 @@
       public OutputSurfaceClient,
       public TopControlsManagerClient,
       public ScrollbarAnimationControllerClient,
-      public BeginFrameSourceMixIn,
       public base::SupportsWeakPtr<LayerTreeHostImpl> {
  public:
   static scoped_ptr<LayerTreeHostImpl> Create(
@@ -125,9 +124,6 @@
       int id);
   ~LayerTreeHostImpl() override;
 
-  // BeginFrameSourceMixIn implementation
-  void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
-
   // InputHandler implementation
   void BindToClient(InputHandlerClient* client) override;
   InputHandler::ScrollStatus ScrollBegin(
@@ -136,8 +132,9 @@
   InputHandler::ScrollStatus ScrollAnimated(
       const gfx::Point& viewport_point,
       const gfx::Vector2dF& scroll_delta) override;
-  bool ScrollBy(const gfx::Point& viewport_point,
-                const gfx::Vector2dF& scroll_delta) override;
+  InputHandlerScrollResult ScrollBy(
+      const gfx::Point& viewport_point,
+      const gfx::Vector2dF& scroll_delta) override;
   bool ScrollVerticallyByPage(const gfx::Point& viewport_point,
                               ScrollDirection direction) override;
   void SetRootLayerScrollOffsetDelegate(
@@ -156,6 +153,7 @@
   bool HaveTouchEventHandlersAt(const gfx::Point& viewport_port) override;
   scoped_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
       ui::LatencyInfo* latency) override;
+  ScrollElasticityHelper* CreateScrollElasticityHelper() override;
 
   // TopControlsManagerClient implementation.
   void SetControlsTopOffset(float offset) override;
@@ -188,7 +186,6 @@
   virtual void UpdateAnimationState(bool start_ready_animations);
   void ActivateAnimations();
   void MainThreadHasStoppedFlinging();
-  void UpdateBackgroundAnimateTicking(bool should_background_tick);
   void DidAnimateScrollOffset();
   void SetViewportDamage(const gfx::Rect& damage_rect);
 
@@ -234,6 +231,7 @@
   // TileManagerClient implementation.
   const std::vector<PictureLayerImpl*>& GetPictureLayers() const override;
   void NotifyReadyToActivate() override;
+  void NotifyReadyToDraw() override;
   void NotifyTileStateChanged(const Tile* tile) override;
   void BuildRasterQueue(RasterTilePriorityQueue* queue,
                         TreePriority tree_priority) override;
@@ -251,8 +249,6 @@
   void CommitVSyncParameters(base::TimeTicks timebase,
                              base::TimeDelta interval) override;
   void SetNeedsRedrawRect(const gfx::Rect& rect) override;
-  void BeginFrame(const BeginFrameArgs& args) override;
-
   void SetExternalDrawConstraints(
       const gfx::Transform& transform,
       const gfx::Rect& viewport,
@@ -329,6 +325,8 @@
   virtual void SetVisible(bool visible);
   bool visible() const { return visible_; }
 
+  bool AnimationsAreVisible() { return visible() && CanDraw(); }
+
   void SetNeedsCommit() { client_->SetNeedsCommitOnImplThread(); }
   void SetNeedsRedraw();
 
@@ -424,7 +422,7 @@
     return begin_impl_frame_interval_;
   }
 
-  void AsValueInto(base::debug::TracedValue* value) const override;
+  void AsValueInto(base::debug::TracedValue* value) const;
   void AsValueWithFrameInto(FrameData* frame,
                             base::debug::TracedValue* value) const;
   scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
@@ -473,8 +471,8 @@
   void RegisterPictureLayerImpl(PictureLayerImpl* layer);
   void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
 
-  void GetPictureLayerImplPairs(
-      std::vector<PictureLayerImpl::Pair>* layers) const;
+  void GetPictureLayerImplPairs(std::vector<PictureLayerImpl::Pair>* layers,
+                                bool need_valid_tile_priorities) const;
 
   void SetTopControlsLayoutHeight(float height);
 
@@ -506,8 +504,6 @@
 
   // Virtual for testing.
   virtual void AnimateLayers(base::TimeTicks monotonic_time);
-  virtual base::TimeDelta LowFrequencyAnimationInterval() const;
-
   const AnimationRegistrar::AnimationControllerMap&
       active_animation_controllers() const {
     return animation_registrar_->active_animation_controllers();
@@ -627,6 +623,10 @@
   int scroll_layer_id_when_mouse_over_scrollbar_;
   ScopedPtrVector<SwapPromise> swap_promises_for_main_thread_scroll_update_;
 
+  // An object to implement the ScrollElasticityHelper interface and
+  // hold all state related to elasticity. May be NULL if never requested.
+  scoped_ptr<ScrollElasticityHelper> scroll_elasticity_helper_;
+
   bool tile_priorities_dirty_;
 
   // The optional delegate for the root layer scroll offset.
@@ -646,9 +646,6 @@
 
   scoped_ptr<PageScaleAnimation> page_scale_animation_;
 
-  // This is used for ticking animations slowly when hidden.
-  scoped_ptr<LayerTreeHostImplTimeSourceAdapter> time_source_client_adapter_;
-
   scoped_ptr<FrameRateCounter> fps_counter_;
   scoped_ptr<PaintTimeCounter> paint_time_counter_;
   scoped_ptr<MemoryHistory> memory_history_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 5d2d939..17179cd 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -124,6 +124,7 @@
     did_notify_ready_to_activate_ = true;
     host_impl_->ActivateSyncTree();
   }
+  void NotifyReadyToDraw() override {}
   void SetNeedsRedrawOnImplThread() override { did_request_redraw_ = true; }
   void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) override {
     did_request_redraw_ = true;
@@ -772,27 +773,40 @@
             host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
 
   // Trying to scroll to the left/top will not succeed.
-  EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
-  EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)));
-  EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)));
+  EXPECT_FALSE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)).did_scroll);
+  EXPECT_FALSE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)).did_scroll);
+  EXPECT_FALSE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)).did_scroll);
 
   // Scrolling to the right/bottom will succeed.
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0)));
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)));
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 10)));
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0)).did_scroll);
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll);
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 10)).did_scroll);
 
   // Scrolling to left/top will now succeed.
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)));
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)));
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)).did_scroll);
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)).did_scroll);
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)).did_scroll);
 
   // Scrolling diagonally against an edge will succeed.
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -10)));
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 10)));
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -10)).did_scroll);
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)).did_scroll);
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 10)).did_scroll);
 
   // Trying to scroll more than the available space will also succeed.
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(5000, 5000)));
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(5000, 5000)).did_scroll);
 }
 
 TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) {
@@ -2574,6 +2588,14 @@
   EXPECT_EQ(InputHandler::ScrollStarted,
             host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
   host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+
+  // scrolling down at the max extents no longer hides the top controls
+  EXPECT_EQ(0.f,
+            settings_.top_controls_height -
+                host_impl_->active_tree()->total_top_controls_content_offset());
+
+  // forcefully hide the top controls by 25px
+  host_impl_->top_controls_manager()->ScrollBy(scroll_delta);
   host_impl_->ScrollEnd();
 
   EXPECT_EQ(scroll_delta.y(),
@@ -3705,6 +3727,7 @@
 }
 
 TEST_F(LayerTreeHostImplTest, OverscrollRoot) {
+  InputHandlerScrollResult scroll_result;
   SetupScrollAndContentsLayers(gfx::Size(100, 100));
   host_impl_->SetViewportSize(gfx::Size(50, 50));
   host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
@@ -3714,38 +3737,105 @@
   // In-bounds scrolling does not affect overscroll.
   EXPECT_EQ(InputHandler::ScrollStarted,
             host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+  EXPECT_TRUE(scroll_result.did_scroll);
+  EXPECT_FALSE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
 
   // Overscroll events are reflected immediately.
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 50));
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 50));
+  EXPECT_TRUE(scroll_result.did_scroll);
+  EXPECT_TRUE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(0, 10), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(0, 10), host_impl_->accumulated_root_overscroll());
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
 
   // In-bounds scrolling resets accumulated overscroll for the scrolled axes.
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -50));
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -50));
+  EXPECT_TRUE(scroll_result.did_scroll);
+  EXPECT_FALSE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(0, 0), host_impl_->accumulated_root_overscroll());
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10));
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
+
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10));
+  EXPECT_FALSE(scroll_result.did_scroll);
+  EXPECT_TRUE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(0, -10), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0));
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
+
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0));
+  EXPECT_TRUE(scroll_result.did_scroll);
+  EXPECT_FALSE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(0, 0), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-15, 0));
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
+
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-15, 0));
+  EXPECT_TRUE(scroll_result.did_scroll);
+  EXPECT_TRUE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(-5, 0), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(-5, -10), host_impl_->accumulated_root_overscroll());
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 60));
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
+
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 60));
+  EXPECT_TRUE(scroll_result.did_scroll);
+  EXPECT_TRUE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(0, 10), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(-5, 10), host_impl_->accumulated_root_overscroll());
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -60));
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
+
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -60));
+  EXPECT_TRUE(scroll_result.did_scroll);
+  EXPECT_TRUE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(0, -10), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
 
   // Overscroll accumulates within the scope of ScrollBegin/ScrollEnd as long
   // as no scroll occurs.
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+  EXPECT_FALSE(scroll_result.did_scroll);
+  EXPECT_TRUE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(0, -20), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(0, -30), host_impl_->accumulated_root_overscroll());
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
+
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+  EXPECT_FALSE(scroll_result.did_scroll);
+  EXPECT_TRUE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(0, -20), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(0, -50), host_impl_->accumulated_root_overscroll());
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
+
   // Overscroll resets on valid scroll.
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+  EXPECT_TRUE(scroll_result.did_scroll);
+  EXPECT_FALSE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(0, 0), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(0, 0), host_impl_->accumulated_root_overscroll());
-  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
+
+  scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+  EXPECT_TRUE(scroll_result.did_scroll);
+  EXPECT_TRUE(scroll_result.did_overscroll_root);
+  EXPECT_EQ(gfx::Vector2dF(0, -10), scroll_result.unused_scroll_delta);
   EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
+  EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+            host_impl_->accumulated_root_overscroll());
+
   host_impl_->ScrollEnd();
 }
 
@@ -5981,7 +6071,8 @@
       pile_tile_size, content_layer_bounds));
 
   scoped_ptr<FakePictureLayerImpl> scoped_content_layer =
-      FakePictureLayerImpl::CreateWithPile(host_impl_->pending_tree(), 3, pile);
+      FakePictureLayerImpl::CreateWithRasterSource(host_impl_->pending_tree(),
+                                                   3, pile);
   LayerImpl* content_layer = scoped_content_layer.get();
   scrolling_layer->AddChild(scoped_content_layer.Pass());
   content_layer->SetBounds(content_layer_bounds);
@@ -6527,7 +6618,7 @@
     gfx::Vector2d scroll_delta(0, -2);
     EXPECT_EQ(InputHandler::ScrollStarted,
               host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
-    EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+    EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
 
     // The grand child should have scrolled up to its limit.
     scroll_info = host_impl_->ProcessScrollDeltas();
@@ -6537,7 +6628,7 @@
 
     // The child should have received the bubbled delta, but the locked
     // scrolling layer should remain set as the grand child.
-    EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+    EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
     scroll_info = host_impl_->ProcessScrollDeltas();
     ASSERT_EQ(2u, scroll_info->scrolls.size());
     ExpectContains(*scroll_info, grand_child->id(), scroll_delta);
@@ -6547,7 +6638,7 @@
     // The first |ScrollBy| after the fling should re-lock the scrolling
     // layer to the first layer that scrolled, which is the child.
     EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
-    EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+    EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
     EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
 
     // The child should have scrolled up to its limit.
@@ -6557,7 +6648,7 @@
     ExpectContains(*scroll_info, child->id(), scroll_delta + scroll_delta);
 
     // As the locked layer is at it's limit, no further scrolling can occur.
-    EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+    EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
     EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
     host_impl_->ScrollEnd();
   }
@@ -6955,7 +7046,8 @@
     // Scrolling normally should not trigger any forwarding.
     EXPECT_EQ(InputHandler::ScrollStarted,
               host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
-    EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)));
+    EXPECT_TRUE(
+        host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll);
     host_impl_->ScrollEnd();
 
     EXPECT_EQ(0, set_needs_commit_count);
@@ -6967,7 +7059,8 @@
     scroll_layer->SetHaveScrollEventHandlers(true);
     EXPECT_EQ(InputHandler::ScrollStarted,
               host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
-    EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)));
+    EXPECT_TRUE(
+        host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll);
     host_impl_->ScrollEnd();
 
     EXPECT_EQ(0, set_needs_commit_count);
@@ -7022,7 +7115,8 @@
   // Scroll just the top controls and verify that the scroll succeeds.
   const float residue = 10;
   float offset = top_controls_height_ - residue;
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
   EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF().ToString(),
             scroll_layer->TotalScrollOffset().ToString());
@@ -7030,7 +7124,8 @@
   // Scroll across the boundary
   const float content_scroll = 20;
   offset = residue + content_scroll;
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
   EXPECT_EQ(-top_controls_height_,
             host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF(0, content_scroll).ToString(),
@@ -7038,7 +7133,8 @@
 
   // Now scroll back to the top of the content
   offset = -content_scroll;
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
   EXPECT_EQ(-top_controls_height_,
             host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF().ToString(),
@@ -7046,13 +7142,15 @@
 
   // And scroll the top controls completely into view
   offset = -top_controls_height_;
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
   EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF().ToString(),
             scroll_layer->TotalScrollOffset().ToString());
 
   // And attempt to scroll past the end
-  EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+  EXPECT_FALSE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
   EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF().ToString(),
             scroll_layer->TotalScrollOffset().ToString());
@@ -7076,7 +7174,8 @@
   // Scroll the top controls partially.
   const float residue = 35;
   float offset = top_controls_height_ - residue;
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
   EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF().ToString(),
             scroll_layer->TotalScrollOffset().ToString());
@@ -7144,7 +7243,8 @@
   // Scroll the top controls partially.
   const float residue = 15;
   float offset = top_controls_height_ - residue;
-  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
   EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
   EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
             scroll_layer->TotalScrollOffset().ToString());
@@ -7184,6 +7284,68 @@
   EXPECT_FALSE(host_impl_->top_controls_manager()->animation());
 }
 
+TEST_F(LayerTreeHostImplWithTopControlsTest,
+       TopControlsScrollDeltaInOverScroll) {
+  // test varifies that the overscroll delta should not have accumulated in
+  // the top controls if we do a hide and show without releasing finger.
+
+  LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 200));
+  host_impl_->SetViewportSize(gfx::Size(100, 100));
+  host_impl_->top_controls_manager()->UpdateTopControlsState(BOTH, SHOWN,
+                                                             false);
+  DrawFrame();
+
+  EXPECT_EQ(InputHandler::ScrollStarted,
+            host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+  EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+  float offset = 50;
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+  EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
+  EXPECT_EQ(gfx::Vector2dF().ToString(),
+            scroll_layer->TotalScrollOffset().ToString());
+
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+  EXPECT_EQ(gfx::Vector2dF(0, offset).ToString(),
+            scroll_layer->TotalScrollOffset().ToString());
+
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+
+  // Should have fully scrolled
+  EXPECT_EQ(gfx::Vector2dF(0, scroll_layer->MaxScrollOffset().y()).ToString(),
+            scroll_layer->TotalScrollOffset().ToString());
+
+  float overscrollamount = 10;
+
+  // Overscroll the content
+  EXPECT_FALSE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, overscrollamount))
+          .did_scroll);
+  EXPECT_EQ(gfx::Vector2dF(0, 2 * offset).ToString(),
+            scroll_layer->TotalScrollOffset().ToString());
+  EXPECT_EQ(gfx::Vector2dF(0, overscrollamount).ToString(),
+            host_impl_->accumulated_root_overscroll().ToString());
+
+  EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -2 * offset))
+                  .did_scroll);
+  EXPECT_EQ(gfx::Vector2dF(0, 0).ToString(),
+            scroll_layer->TotalScrollOffset().ToString());
+  EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+  EXPECT_TRUE(
+      host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -offset)).did_scroll);
+  EXPECT_EQ(gfx::Vector2dF(0, 0).ToString(),
+            scroll_layer->TotalScrollOffset().ToString());
+
+  // Top controls should be fully visible
+  EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+  host_impl_->ScrollEnd();
+}
+
 class LayerTreeHostImplVirtualViewportTest : public LayerTreeHostImplTest {
  public:
   void SetupVirtualViewportLayers(const gfx::Size& content_size,
@@ -7398,7 +7560,7 @@
   LayerImpl* pending_layer = pending_tree->root_layer();
 
   std::vector<PictureLayerImpl::Pair> layer_pairs;
-  host_impl_->GetPictureLayerImplPairs(&layer_pairs);
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
   EXPECT_EQ(1u, layer_pairs.size());
   EXPECT_EQ(pending_layer, layer_pairs[0].pending);
   EXPECT_EQ(nullptr, layer_pairs[0].active);
@@ -7415,7 +7577,7 @@
   host_impl_->CreatePendingTree();
 
   layer_pairs.clear();
-  host_impl_->GetPictureLayerImplPairs(&layer_pairs);
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
   EXPECT_EQ(1u, layer_pairs.size());
   EXPECT_EQ(active_layer, layer_pairs[0].active);
   EXPECT_EQ(pending_layer, layer_pairs[0].pending);
@@ -7424,7 +7586,7 @@
   host_impl_->ActivateSyncTree();
 
   layer_pairs.clear();
-  host_impl_->GetPictureLayerImplPairs(&layer_pairs);
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
   EXPECT_EQ(1u, layer_pairs.size());
   EXPECT_EQ(active_layer, layer_pairs[0].active);
   EXPECT_EQ(nullptr, layer_pairs[0].pending);
@@ -7438,7 +7600,7 @@
   LayerImpl* new_pending_layer = pending_tree->root_layer()->children()[0];
 
   layer_pairs.clear();
-  host_impl_->GetPictureLayerImplPairs(&layer_pairs);
+  host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
   EXPECT_EQ(2u, layer_pairs.size());
 
   // The pair ordering is flaky, so make it consistent.
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
index 7a9ef21..148769e 100644
--- a/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -52,25 +52,29 @@
 const uint32 kUseMasks = 1 << 0;
 const uint32 kUseAntialiasing = 1 << 1;
 const uint32 kUseColorMatrix = 1 << 2;
+const uint32 kForceShaders = 1 << 3;
 
 class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
  public:
-  LayerTreeHostBlendingPixelTest() {
+  LayerTreeHostBlendingPixelTest()
+      : force_antialiasing_(false), force_blending_with_shaders_(false) {
     pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true));
   }
 
   virtual void InitializeSettings(LayerTreeSettings* settings) override {
     settings->force_antialiasing = force_antialiasing_;
+    settings->force_blending_with_shaders = force_blending_with_shaders_;
   }
 
  protected:
   void RunBlendingWithRootPixelTestType(PixelTestType type) {
-    const int kLaneWidth = 15;
-    const int kLaneHeight = kBlendModesCount * kLaneWidth;
-    const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+    const int kLaneWidth = 2;
+    const int kLaneHeight = kLaneWidth;
+    const int kRootWidth = (kBlendModesCount + 2) * kLaneWidth;
+    const int kRootHeight = 2 * kLaneWidth + kLaneHeight;
 
     scoped_refptr<SolidColorLayer> background =
-        CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange);
+        CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSOrange);
 
     // Orange child layers will blend with the green background
     for (int i = 0; i < kBlendModesCount; ++i) {
@@ -88,15 +92,16 @@
   }
 
   void RunBlendingWithTransparentPixelTestType(PixelTestType type) {
-    const int kLaneWidth = 15;
-    const int kLaneHeight = kBlendModesCount * kLaneWidth;
-    const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+    const int kLaneWidth = 2;
+    const int kLaneHeight = 3 * kLaneWidth;
+    const int kRootWidth = (kBlendModesCount + 2) * kLaneWidth;
+    const int kRootHeight = 2 * kLaneWidth + kLaneHeight;
 
     scoped_refptr<SolidColorLayer> root =
-        CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSBrown);
+        CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSBrown);
 
     scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
-        gfx::Rect(0, kLaneWidth * 2, kRootSize, kLaneWidth), kCSSOrange);
+        gfx::Rect(0, kLaneWidth * 2, kRootWidth, kLaneWidth), kCSSOrange);
 
     root->AddChild(background);
     background->SetIsRootForIsolatedGroup(true);
@@ -138,7 +143,7 @@
   }
 
   void SetupMaskLayer(scoped_refptr<Layer> layer) {
-    const int kMaskOffset = 5;
+    const int kMaskOffset = 2;
     gfx::Size bounds = layer->bounds();
     scoped_refptr<ImageLayer> mask = ImageLayer::Create();
     mask->SetIsDrawable(true);
@@ -162,23 +167,22 @@
 
   void SetupColorMatrix(scoped_refptr<Layer> layer) {
     FilterOperations filter_operations;
-    filter_operations.Append(FilterOperation::CreateSepiaFilter(1.f));
+    filter_operations.Append(FilterOperation::CreateSepiaFilter(.001f));
     layer->SetFilters(filter_operations);
   }
 
-  void CreateBlendingColorLayers(int width,
-                                 int height,
+  void CreateBlendingColorLayers(int lane_width,
+                                 int lane_height,
                                  scoped_refptr<Layer> background,
                                  RenderPassOptions flags) {
     const int kLanesCount = kBlendModesCount + 4;
-    int lane_width = width / kLanesCount;
     const SkColor kMiscOpaqueColor = 0xffc86464;
     const SkColor kMiscTransparentColor = 0x80c86464;
     const SkXfermode::Mode kCoeffBlendMode = SkXfermode::kScreen_Mode;
     const SkXfermode::Mode kShaderBlendMode = SkXfermode::kColorBurn_Mode;
     // add vertical lanes with each of the blend modes
     for (int i = 0; i < kLanesCount; ++i) {
-      gfx::Rect child_rect(i * lane_width, 0, lane_width, height);
+      gfx::Rect child_rect(i * lane_width, 0, lane_width, lane_height);
       SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
       float opacity = 1.f;
       SkColor color = kMiscOpaqueColor;
@@ -216,7 +220,9 @@
   void RunBlendingWithRenderPass(PixelTestType type,
                                  const base::FilePath::CharType* expected_path,
                                  RenderPassOptions flags) {
-    const int kRootSize = 400;
+    const int kLaneWidth = 8;
+    const int kLaneHeight = kLaneWidth * kCSSTestColorsCount;
+    const int kRootSize = kLaneHeight;
 
     scoped_refptr<SolidColorLayer> root =
         CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), SK_ColorWHITE);
@@ -226,47 +232,25 @@
     background->SetIsRootForIsolatedGroup(true);
     root->AddChild(background);
 
-    CreateBlendingColorLayers(kRootSize, kRootSize, background.get(), flags);
+    CreateBlendingColorLayers(kLaneWidth, kLaneHeight, background.get(), flags);
 
     this->impl_side_painting_ = false;
     this->force_antialiasing_ = (flags & kUseAntialiasing);
+    this->force_blending_with_shaders_ = (flags & kForceShaders);
 
     if ((flags & kUseAntialiasing) && (type == PIXEL_TEST_GL)) {
-      // Anti aliasing causes differences up to 7 pixels at the edges.
-      // Several pixels have 9 units difference on the alpha channel.
-      int large_error_allowed = (flags & kUseMasks) ? 7 : 9;
+      // Anti aliasing causes differences up to 8 pixels at the edges.
+      int large_error_allowed = 8;
       // Blending results might differ with one pixel.
       int small_error_allowed = 1;
       // Most of the errors are one pixel errors.
-      float percentage_pixels_small_error = (flags & kUseMasks) ? 7.7f : 12.1f;
-      // Because of anti-aliasing, around 3% of pixels (at the edges) have
+      float percentage_pixels_small_error = 13.1f;
+      // Because of anti-aliasing, around 10% of pixels (at the edges) have
       // bigger errors (from small_error_allowed + 1 to large_error_allowed).
-      float percentage_pixels_error = (flags & kUseMasks) ? 12.4f : 15.f;
+      float percentage_pixels_error = 22.5f;
       // The average error is still close to 1.
-      float average_error_allowed_in_bad_pixels =
-          (flags & kUseMasks) ? 1.3f : 1.f;
+      float average_error_allowed_in_bad_pixels = 1.4f;
 
-      // The sepia filter generates more small errors, but the number of large
-      // errors remains around 3%.
-      if (flags & kUseColorMatrix) {
-        percentage_pixels_small_error = (flags & kUseMasks) ? 14.0f : 26.f;
-        percentage_pixels_error = (flags & kUseMasks) ? 18.5f : 29.f;
-        average_error_allowed_in_bad_pixels = (flags & kUseMasks) ? 0.9f : 0.7f;
-      }
-
-      pixel_comparator_.reset(
-          new FuzzyPixelComparator(false,  // discard_alpha
-                                   percentage_pixels_error,
-                                   percentage_pixels_small_error,
-                                   average_error_allowed_in_bad_pixels,
-                                   large_error_allowed,
-                                   small_error_allowed));
-    } else if ((flags & kUseColorMatrix) && (type == PIXEL_TEST_GL)) {
-      float percentage_pixels_error = 100.f;
-      float percentage_pixels_small_error = 0.f;
-      float average_error_allowed_in_bad_pixels = 1.f;
-      int large_error_allowed = 2;
-      int small_error_allowed = 0;
       pixel_comparator_.reset(
           new FuzzyPixelComparator(false,  // discard_alpha
                                    percentage_pixels_error,
@@ -279,7 +263,8 @@
     RunPixelTest(type, root, base::FilePath(expected_path));
   }
 
-  bool force_antialiasing_ = false;
+  bool force_antialiasing_;
+  bool force_blending_with_shaders_;
 };
 
 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) {
@@ -291,12 +276,13 @@
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) {
-  const int kLaneWidth = 15;
-  const int kLaneHeight = kBlendModesCount * kLaneWidth;
-  const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+  const int kLaneWidth = 2;
+  const int kLaneHeight = kLaneWidth;
+  const int kRootWidth = (kBlendModesCount + 2) * kLaneWidth;
+  const int kRootHeight = 2 * kLaneWidth + kLaneHeight;
 
   scoped_refptr<SolidColorLayer> background =
-      CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange);
+      CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSOrange);
 
   // Orange child layers have a background filter set and they will blend with
   // the green background
@@ -377,60 +363,111 @@
 
 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrix_GL) {
   RunBlendingWithRenderPass(PIXEL_TEST_GL,
-                            FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+                            FILE_PATH_LITERAL("blending_render_pass.png"),
                             kUseColorMatrix);
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest,
        BlendingWithRenderPassColorMatrix_Software) {
   RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
-                            FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+                            FILE_PATH_LITERAL("blending_render_pass.png"),
                             kUseColorMatrix);
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrixAA_GL) {
   RunBlendingWithRenderPass(PIXEL_TEST_GL,
-                            FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+                            FILE_PATH_LITERAL("blending_render_pass.png"),
                             kUseAntialiasing | kUseColorMatrix);
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest,
        BlendingWithRenderPassColorMatrixAA_Software) {
   RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
-                            FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+                            FILE_PATH_LITERAL("blending_render_pass.png"),
                             kUseAntialiasing | kUseColorMatrix);
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest,
        BlendingWithRenderPassWithMaskColorMatrix_GL) {
-  RunBlendingWithRenderPass(
-      PIXEL_TEST_GL,
-      FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
-      kUseMasks | kUseColorMatrix);
+  RunBlendingWithRenderPass(PIXEL_TEST_GL,
+                            FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+                            kUseMasks | kUseColorMatrix);
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest,
        BlendingWithRenderPassWithMaskColorMatrix_Software) {
-  RunBlendingWithRenderPass(
-      PIXEL_TEST_SOFTWARE,
-      FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
-      kUseMasks | kUseColorMatrix);
+  RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
+                            FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+                            kUseMasks | kUseColorMatrix);
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest,
        BlendingWithRenderPassWithMaskColorMatrixAA_GL) {
-  RunBlendingWithRenderPass(
-      PIXEL_TEST_GL,
-      FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
-      kUseMasks | kUseAntialiasing | kUseColorMatrix);
+  RunBlendingWithRenderPass(PIXEL_TEST_GL,
+                            FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+                            kUseMasks | kUseAntialiasing | kUseColorMatrix);
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest,
        BlendingWithRenderPassWithMaskColorMatrixAA_Software) {
+  RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
+                            FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+                            kUseMasks | kUseAntialiasing | kUseColorMatrix);
+}
+
+// Tests for render passes forcing shaders for all the blend modes.
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShaders_GL) {
+  RunBlendingWithRenderPass(PIXEL_TEST_GL,
+                            FILE_PATH_LITERAL("blending_render_pass.png"),
+                            kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersAA_GL) {
+  RunBlendingWithRenderPass(PIXEL_TEST_GL,
+                            FILE_PATH_LITERAL("blending_render_pass.png"),
+                            kUseAntialiasing | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+       BlendingWithRenderPassShadersWithMask_GL) {
+  RunBlendingWithRenderPass(PIXEL_TEST_GL,
+                            FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+                            kUseMasks | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+       BlendingWithRenderPassShadersWithMaskAA_GL) {
+  RunBlendingWithRenderPass(PIXEL_TEST_GL,
+                            FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+                            kUseMasks | kUseAntialiasing | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+       BlendingWithRenderPassShadersColorMatrix_GL) {
+  RunBlendingWithRenderPass(PIXEL_TEST_GL,
+                            FILE_PATH_LITERAL("blending_render_pass.png"),
+                            kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+       BlendingWithRenderPassShadersColorMatrixAA_GL) {
+  RunBlendingWithRenderPass(PIXEL_TEST_GL,
+                            FILE_PATH_LITERAL("blending_render_pass.png"),
+                            kUseAntialiasing | kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+       BlendingWithRenderPassShadersWithMaskColorMatrix_GL) {
+  RunBlendingWithRenderPass(PIXEL_TEST_GL,
+                            FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+                            kUseMasks | kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+       BlendingWithRenderPassShadersWithMaskColorMatrixAA_GL) {
   RunBlendingWithRenderPass(
-      PIXEL_TEST_SOFTWARE,
-      FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
-      kUseMasks | kUseAntialiasing | kUseColorMatrix);
+      PIXEL_TEST_GL, FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+      kUseMasks | kUseAntialiasing | kUseColorMatrix | kForceShaders);
 }
 
 }  // namespace
diff --git a/cc/trees/layer_tree_host_pixeltest_filters.cc b/cc/trees/layer_tree_host_pixeltest_filters.cc
index 40fa2c3..dc8cc4a 100644
--- a/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -136,8 +136,8 @@
   blur->SetBackgroundFilters(filters);
 
 #if defined(OS_WIN)
-  // Windows has 153 pixels off by at most 2: crbug.com/225027
-  float percentage_pixels_large_error = 0.3825f;  // 153px / (200*200)
+  // Windows has 116 pixels off by at most 2: crbug.com/225027
+  float percentage_pixels_large_error = 0.3f;  // 116px / (200*200), rounded up
   float percentage_pixels_small_error = 0.0f;
   float average_error_allowed_in_bad_pixels = 1.f;
   int large_error_allowed = 2;
@@ -277,6 +277,63 @@
   RunPixelTestType(PIXEL_TEST_SOFTWARE);
 }
 
+TEST_F(LayerTreeHostFiltersPixelTest, ImageFilterScaled_GL) {
+  scoped_refptr<SolidColorLayer> background =
+      CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
+
+  gfx::Rect rect(50, 50, 100, 100);
+
+  static const int kInset = 3;
+  for (int i = 0; !rect.IsEmpty(); ++i) {
+    scoped_refptr<SolidColorLayer> layer =
+        CreateSolidColorLayer(rect, (i & 1) ? SK_ColorWHITE : SK_ColorRED);
+
+    gfx::Transform transform;
+    transform.Translate(rect.width() / 2.0, rect.height() / 2.0);
+    transform.RotateAboutZAxis(30.0);
+    transform.Translate(-rect.width() / 2.0, -rect.height() / 2.0);
+    layer->SetTransform(transform);
+
+    background->AddChild(layer);
+
+    rect.Inset(kInset, kInset);
+  }
+
+  scoped_refptr<SolidColorLayer> filter =
+      CreateSolidColorLayer(gfx::Rect(100, 0, 100, 200), SK_ColorTRANSPARENT);
+
+  background->AddChild(filter);
+
+  // Apply a scale to |background| so that we can see any scaling artifacts that
+  // may appear.
+  gfx::Transform background_transform;
+  static float scale = 1.1f;
+  background_transform.Scale(scale, scale);
+  background->SetTransform(background_transform);
+
+  FilterOperations filters;
+  filters.Append(FilterOperation::CreateGrayscaleFilter(1.0f));
+  filter->SetBackgroundFilters(filters);
+
+#if defined(OS_WIN)
+  // Windows has 153 pixels off by at most 2: crbug.com/225027
+  float percentage_pixels_large_error = 0.3825f;  // 153px / (200*200)
+  float percentage_pixels_small_error = 0.0f;
+  float average_error_allowed_in_bad_pixels = 1.f;
+  int large_error_allowed = 2;
+  int small_error_allowed = 0;
+  pixel_comparator_.reset(new FuzzyPixelComparator(
+      true,  // discard_alpha
+      percentage_pixels_large_error, percentage_pixels_small_error,
+      average_error_allowed_in_bad_pixels, large_error_allowed,
+      small_error_allowed));
+#endif
+
+  // TODO(hendrikw): Enable test in software as well: crbug.com/432157
+  RunPixelTest(PIXEL_TEST_GL, background,
+               base::FilePath(FILE_PATH_LITERAL("filter_on_scaled_layer.png")));
+}
+
 }  // namespace
 }  // namespace cc
 
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 0859d86..5c66790 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -67,6 +67,151 @@
 
 class LayerTreeHostTest : public LayerTreeTest {};
 
+// Test if the LTHI receives ReadyToActivate notifications from the TileManager
+// when no raster tasks get scheduled.
+class LayerTreeHostTestReadyToActivateEmpty : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestReadyToActivateEmpty()
+      : did_notify_ready_to_activate_(false),
+        all_tiles_required_for_activation_are_ready_to_draw_(false),
+        required_for_activation_count_(0) {}
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
+    const std::vector<PictureLayerImpl*>& layers = impl->GetPictureLayers();
+    required_for_activation_count_ = 0;
+    for (const auto& layer : layers) {
+      FakePictureLayerImpl* fake_layer =
+          static_cast<FakePictureLayerImpl*>(layer);
+      required_for_activation_count_ +=
+          fake_layer->CountTilesRequiredForActivation();
+    }
+  }
+
+  void NotifyReadyToActivateOnThread(LayerTreeHostImpl* impl) override {
+    did_notify_ready_to_activate_ = true;
+    const std::vector<PictureLayerImpl*>& layers = impl->GetPictureLayers();
+    all_tiles_required_for_activation_are_ready_to_draw_ = true;
+    for (const auto& layer : layers) {
+      if (!layer->AllTilesRequiredForActivationAreReadyToDraw())
+        all_tiles_required_for_activation_are_ready_to_draw_ = false;
+    }
+    EndTest();
+  }
+
+  void AfterTest() override {
+    EXPECT_TRUE(did_notify_ready_to_activate_);
+    EXPECT_TRUE(all_tiles_required_for_activation_are_ready_to_draw_);
+    EXPECT_EQ(size_t(0), required_for_activation_count_);
+  }
+
+ protected:
+  bool did_notify_ready_to_activate_;
+  bool all_tiles_required_for_activation_are_ready_to_draw_;
+  size_t required_for_activation_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToActivateEmpty);
+
+// Test if the LTHI receives ReadyToActivate notifications from the TileManager
+// when some raster tasks flagged as REQUIRED_FOR_ACTIVATION got scheduled.
+class LayerTreeHostTestReadyToActivateNonEmpty
+    : public LayerTreeHostTestReadyToActivateEmpty {
+ public:
+  void SetupTree() override {
+    client_.set_fill_with_nonsolid_color(true);
+    scoped_refptr<FakePictureLayer> root_layer =
+        FakePictureLayer::Create(&client_);
+    root_layer->SetBounds(gfx::Size(1024, 1024));
+    root_layer->SetIsDrawable(true);
+
+    layer_tree_host()->SetRootLayer(root_layer);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  void AfterTest() override {
+    EXPECT_TRUE(did_notify_ready_to_activate_);
+    EXPECT_TRUE(all_tiles_required_for_activation_are_ready_to_draw_);
+    EXPECT_LE(size_t(1), required_for_activation_count_);
+  }
+
+ private:
+  FakeContentLayerClient client_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToActivateNonEmpty);
+
+// Test if the LTHI receives ReadyToDraw notifications from the TileManager when
+// no raster tasks get scheduled.
+class LayerTreeHostTestReadyToDrawEmpty : public LayerTreeHostTest {
+ public:
+  LayerTreeHostTestReadyToDrawEmpty()
+      : did_notify_ready_to_draw_(false),
+        all_tiles_required_for_draw_are_ready_to_draw_(false),
+        required_for_draw_count_(0) {}
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void NotifyReadyToDrawOnThread(LayerTreeHostImpl* impl) override {
+    did_notify_ready_to_draw_ = true;
+    const std::vector<PictureLayerImpl*>& layers = impl->GetPictureLayers();
+    all_tiles_required_for_draw_are_ready_to_draw_ = true;
+    for (const auto& layer : layers) {
+      if (!layer->AllTilesRequiredForDrawAreReadyToDraw())
+        all_tiles_required_for_draw_are_ready_to_draw_ = false;
+      FakePictureLayerImpl* fake_layer =
+          static_cast<FakePictureLayerImpl*>(layer);
+      required_for_draw_count_ += fake_layer->CountTilesRequiredForDraw();
+    }
+
+    EndTest();
+  }
+
+  void AfterTest() override {
+    EXPECT_TRUE(did_notify_ready_to_draw_);
+    EXPECT_TRUE(all_tiles_required_for_draw_are_ready_to_draw_);
+    EXPECT_EQ(size_t(0), required_for_draw_count_);
+  }
+
+ protected:
+  bool did_notify_ready_to_draw_;
+  bool all_tiles_required_for_draw_are_ready_to_draw_;
+  size_t required_for_draw_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToDrawEmpty);
+
+// Test if the LTHI receives ReadyToDraw notifications from the TileManager when
+// some raster tasks flagged as REQUIRED_FOR_DRAW got scheduled.
+class LayerTreeHostTestReadyToDrawNonEmpty
+    : public LayerTreeHostTestReadyToDrawEmpty {
+ public:
+  void SetupTree() override {
+    client_.set_fill_with_nonsolid_color(true);
+    scoped_refptr<FakePictureLayer> root_layer =
+        FakePictureLayer::Create(&client_);
+    root_layer->SetBounds(gfx::Size(1024, 1024));
+    root_layer->SetIsDrawable(true);
+
+    layer_tree_host()->SetRootLayer(root_layer);
+    LayerTreeHostTest::SetupTree();
+  }
+
+  void AfterTest() override {
+    EXPECT_TRUE(did_notify_ready_to_draw_);
+    EXPECT_TRUE(all_tiles_required_for_draw_are_ready_to_draw_);
+    EXPECT_LE(size_t(1), required_for_draw_count_);
+  }
+
+ private:
+  FakeContentLayerClient client_;
+};
+
+// Note: With this test setup, we only get tiles flagged as REQUIRED_FOR_DRAW in
+// single threaded mode.
+SINGLE_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToDrawNonEmpty);
+
 // Two setNeedsCommits in a row should lead to at least 1 commit and at least 1
 // draw with frame 0.
 class LayerTreeHostTestSetNeedsCommit1 : public LayerTreeHostTest {
@@ -1969,7 +2114,8 @@
                                           shared_bitmap_manager.get(),
                                           NULL,
                                           settings,
-                                          base::MessageLoopProxy::current());
+                                          base::MessageLoopProxy::current(),
+                                          nullptr);
   client.SetLayerTreeHost(host.get());
   host->Composite(base::TimeTicks::Now());
 
@@ -1991,7 +2137,8 @@
                                           shared_bitmap_manager.get(),
                                           NULL,
                                           settings,
-                                          base::MessageLoopProxy::current());
+                                          base::MessageLoopProxy::current(),
+                                          nullptr);
   client.SetLayerTreeHost(host.get());
   host->Composite(base::TimeTicks::Now());
 
@@ -2013,7 +2160,8 @@
                                           shared_bitmap_manager.get(),
                                           NULL,
                                           settings,
-                                          base::MessageLoopProxy::current());
+                                          base::MessageLoopProxy::current(),
+                                          nullptr);
   client.SetLayerTreeHost(host.get());
   host->Composite(base::TimeTicks::Now());
 
@@ -2036,7 +2184,8 @@
                                           shared_bitmap_manager.get(),
                                           NULL,
                                           settings,
-                                          base::MessageLoopProxy::current());
+                                          base::MessageLoopProxy::current(),
+                                          nullptr);
   client.SetLayerTreeHost(host.get());
   host->Composite(base::TimeTicks::Now());
 
@@ -2225,7 +2374,7 @@
 class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest {
  public:
   void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->begin_frame_scheduling_enabled = true;
+    settings->use_external_begin_frame_source = true;
   }
 
   void BeginTest() override {
@@ -2253,7 +2402,7 @@
     : public LayerTreeHostTest {
  public:
   void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->begin_frame_scheduling_enabled = true;
+    settings->use_external_begin_frame_source = true;
     settings->using_synchronous_renderer_compositor = true;
   }
 
@@ -2280,7 +2429,7 @@
       : commit_count_(0), commit_abort_count_(0), commit_complete_count_(0) {}
 
   void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->begin_frame_scheduling_enabled = true;
+    settings->use_external_begin_frame_source = true;
   }
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
@@ -4739,12 +4888,12 @@
   void BeginTest() override {
     Layer* root = layer_tree_host()->root_layer();
     PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
-    PicturePile* pile = layer->GetPicturePileForTesting();
+    RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
 
     // Verify default values.
     EXPECT_TRUE(root->IsSuitableForGpuRasterization());
     EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
-    EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
     EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
     EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
 
@@ -4795,12 +4944,12 @@
   void BeginTest() override {
     Layer* root = layer_tree_host()->root_layer();
     PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
-    PicturePile* pile = layer->GetPicturePileForTesting();
+    RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
 
     // Verify default values.
     EXPECT_TRUE(root->IsSuitableForGpuRasterization());
     EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
-    EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
     EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
     EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
 
@@ -4810,8 +4959,8 @@
     EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
 
     // Content-based veto is relevant as well.
-    pile->SetUnsuitableForGpuRasterizationForTesting();
-    EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+    recording_source->SetUnsuitableForGpuRasterizationForTesting();
+    EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization());
     EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
     // Veto will take effect when layers are updated.
     // The results will be verified after commit is completed below.
@@ -4860,12 +5009,12 @@
   void BeginTest() override {
     Layer* root = layer_tree_host()->root_layer();
     PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
-    PicturePile* pile = layer->GetPicturePileForTesting();
+    RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
 
     // Verify default values.
     EXPECT_TRUE(root->IsSuitableForGpuRasterization());
     EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
-    EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+    EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
     EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
 
     // With gpu rasterization forced, gpu rasterization trigger is irrelevant.
@@ -4875,8 +5024,8 @@
     EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
 
     // Content-based veto is irrelevant as well.
-    pile->SetUnsuitableForGpuRasterizationForTesting();
-    EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+    recording_source->SetUnsuitableForGpuRasterizationForTesting();
+    EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization());
     EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
     // Veto will take effect when layers are updated.
     // The results will be verified after commit is completed below.
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index cfd8a14..9c346e2 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -348,8 +348,9 @@
   LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree()
       : active_tree_was_animated_(false) {}
 
-  base::TimeDelta LowFrequencyAnimationInterval() const override {
-    return base::TimeDelta::FromMilliseconds(4);
+  base::TimeDelta BackgroundAnimationInterval(LayerTreeHostImpl* host_impl) {
+    return base::TimeDelta::FromSecondsD(
+        1.0 / host_impl->settings().background_animation_rate);
   }
 
   void BeginTest() override {
@@ -409,10 +410,9 @@
           FROM_HERE,
           base::Bind(
               &LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree::
-                   UnblockActivations,
-              base::Unretained(this),
-              host_impl),
-          4 * LowFrequencyAnimationInterval());
+                  UnblockActivations,
+              base::Unretained(this), host_impl),
+          4 * BackgroundAnimationInterval(host_impl));
     }
   }
 
@@ -447,10 +447,9 @@
           FROM_HERE,
           base::Bind(
               &LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree::
-                   InitiateNextCommit,
-              base::Unretained(this),
-              host_impl),
-          4 * LowFrequencyAnimationInterval());
+                  InitiateNextCommit,
+              base::Unretained(this), host_impl),
+          4 * BackgroundAnimationInterval(host_impl));
     }
   }
 
@@ -505,10 +504,10 @@
     const FloatAnimationCurve* curve =
         animation->curve()->ToFloatAnimationCurve();
     float start_opacity = curve->GetValue(0.0);
-    float end_opacity = curve->GetValue(curve->Duration());
+    float end_opacity = curve->GetValue(curve->Duration().InSecondsF());
     float linearly_interpolated_opacity =
         0.25f * end_opacity + 0.75f * start_opacity;
-    double time = curve->Duration() * 0.25;
+    double time = curve->Duration().InSecondsF() * 0.25;
     // If the linear timing function associated with this animation was not
     // picked up, then the linearly interpolated opacity would be different
     // because of the default ease timing function.
diff --git a/cc/trees/layer_tree_host_unittest_no_message_loop.cc b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
index aa5a508..a0b2bdf 100644
--- a/cc/trees/layer_tree_host_unittest_no_message_loop.cc
+++ b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -13,6 +13,7 @@
 #include "cc/output/output_surface.h"
 #include "cc/output/output_surface_client.h"
 #include "cc/resources/resource_provider.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/test/fake_delegated_renderer_layer.h"
 #include "cc/test/test_context_provider.h"
 #include "cc/trees/layer_tree_host.h"
@@ -99,7 +100,7 @@
     LayerTreeSettings settings;
     settings.single_thread_proxy_scheduler = false;
     layer_tree_host_ = LayerTreeHost::CreateSingleThreaded(
-        this, this, NULL, NULL, settings, NULL);
+        this, this, nullptr, nullptr, settings, nullptr, nullptr);
     layer_tree_host_->SetViewportSize(size_);
     layer_tree_host_->SetRootLayer(root_layer_);
   }
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index e922f21..6526ff8 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -8,6 +8,7 @@
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/layers/picture_layer.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_picture_layer.h"
@@ -1091,13 +1092,6 @@
     *received_stop_flinging_ = true;
   }
 
-  void DidOverscroll(const gfx::PointF& causal_event_viewport_point,
-                     const gfx::Vector2dF& accumulated_overscroll,
-                     const gfx::Vector2dF& latest_overscroll_delta) override {
-    if (!task_runner_->BelongsToCurrentThread())
-      ADD_FAILURE() << "DidOverscroll called on wrong thread";
-  }
-
  private:
   base::SingleThreadTaskRunner* task_runner_;
   bool* received_stop_flinging_;
@@ -1129,7 +1123,8 @@
                                     NULL,
                                     settings,
                                     base::MessageLoopProxy::current(),
-                                    impl_thread.message_loop_proxy());
+                                    impl_thread.message_loop_proxy(),
+                                    nullptr);
 
   impl_thread.message_loop_proxy()
       ->PostTask(FROM_HERE,
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 1d5cf1b..48c4133 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -16,9 +16,11 @@
     : impl_side_painting(false),
       allow_antialiasing(true),
       force_antialiasing(false),
+      force_blending_with_shaders(false),
       throttle_frame_production(true),
       single_thread_proxy_scheduler(true),
-      begin_frame_scheduling_enabled(false),
+      use_external_begin_frame_source(false),
+      forward_begin_frames_to_children(false),
       main_frame_before_activation_enabled(false),
       using_synchronous_renderer_compositor(false),
       disable_hi_res_timer_tasks_on_battery(false),
@@ -47,6 +49,7 @@
       top_controls_show_threshold(0.5f),
       top_controls_hide_threshold(0.5f),
       refresh_rate(60.0),
+      background_animation_rate(1.0),
       max_partial_texture_updates(std::numeric_limits<size_t>::max()),
       default_tile_size(gfx::Size(256, 256)),
       max_untiled_layer_size(gfx::Size(512, 512)),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 74a3b0c..3097e59 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -21,9 +21,11 @@
   bool impl_side_painting;
   bool allow_antialiasing;
   bool force_antialiasing;
+  bool force_blending_with_shaders;
   bool throttle_frame_production;
   bool single_thread_proxy_scheduler;
-  bool begin_frame_scheduling_enabled;
+  bool use_external_begin_frame_source;
+  bool forward_begin_frames_to_children;
   bool main_frame_before_activation_enabled;
   bool using_synchronous_renderer_compositor;
   bool disable_hi_res_timer_tasks_on_battery;
@@ -58,6 +60,7 @@
   float top_controls_show_threshold;
   float top_controls_hide_threshold;
   double refresh_rate;
+  double background_animation_rate;
   size_t max_partial_texture_updates;
   gfx::Size default_tile_size;
   gfx::Size max_untiled_layer_size;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 1af657a..f15c7ec 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -23,15 +23,20 @@
 scoped_ptr<Proxy> SingleThreadProxy::Create(
     LayerTreeHost* layer_tree_host,
     LayerTreeHostSingleThreadClient* client,
-    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
-  return make_scoped_ptr(
-      new SingleThreadProxy(layer_tree_host, client, main_task_runner));
+    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  return make_scoped_ptr(new SingleThreadProxy(
+                                 layer_tree_host,
+                                 client,
+                                 main_task_runner,
+                                 external_begin_frame_source.Pass()));
 }
 
 SingleThreadProxy::SingleThreadProxy(
     LayerTreeHost* layer_tree_host,
     LayerTreeHostSingleThreadClient* client,
-    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
+    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source)
     : Proxy(main_task_runner, NULL),
       layer_tree_host_(layer_tree_host),
       client_(client),
@@ -43,6 +48,7 @@
       commit_requested_(false),
       inside_synchronous_composite_(false),
       output_surface_creation_requested_(false),
+      external_begin_frame_source_(external_begin_frame_source.Pass()),
       weak_factory_(this) {
   TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
   DCHECK(Proxy::IsMainThread());
@@ -84,11 +90,13 @@
   if (layer_tree_host_->settings().single_thread_proxy_scheduler &&
       !scheduler_on_impl_thread_) {
     SchedulerSettings scheduler_settings(layer_tree_host_->settings());
-    scheduler_on_impl_thread_ = Scheduler::Create(this,
-                                                  scheduler_settings,
-                                                  layer_tree_host_->id(),
-                                                  MainThreadTaskRunner(),
-                                                  base::PowerMonitor::Get());
+    scheduler_on_impl_thread_ =
+        Scheduler::Create(this,
+                          scheduler_settings,
+                          layer_tree_host_->id(),
+                          MainThreadTaskRunner(),
+                          base::PowerMonitor::Get(),
+                          external_begin_frame_source_.Pass());
     scheduler_on_impl_thread_->SetCanStart();
     scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
   }
@@ -101,7 +109,6 @@
   if (scheduler_on_impl_thread_)
     scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
   // Changing visibility could change ShouldComposite().
-  UpdateBackgroundAnimateTicking();
 }
 
 void SingleThreadProxy::RequestNewOutputSurface() {
@@ -161,6 +168,24 @@
   SetNeedsCommit();
 }
 
+void SingleThreadProxy::DoAnimate() {
+  // Don't animate if there is no root layer.
+  // TODO(mithro): Both Animate and UpdateAnimationState already have a
+  // "!active_tree_->root_layer()" check?
+  if (!layer_tree_host_impl_->active_tree()->root_layer()) {
+    return;
+  }
+
+  layer_tree_host_impl_->Animate(
+      layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
+
+  // If animations are not visible, update the animation state now as it
+  // won't happen in DoComposite.
+  if (!layer_tree_host_impl_->AnimationsAreVisible()) {
+    layer_tree_host_impl_->UpdateAnimationState(true);
+  }
+}
+
 void SingleThreadProxy::DoCommit() {
   TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
   DCHECK(Proxy::IsMainThread());
@@ -202,8 +227,6 @@
 
     layer_tree_host_impl_->CommitComplete();
 
-    UpdateBackgroundAnimateTicking();
-
 #if DCHECK_IS_ON
     // In the single-threaded case, the scale and scroll deltas should never be
     // touched on the impl layer tree.
@@ -212,12 +235,6 @@
     DCHECK(!scroll_info->scrolls.size());
     DCHECK_EQ(1.f, scroll_info->page_scale_delta);
 #endif
-
-    RenderingStatsInstrumentation* stats_instrumentation =
-        layer_tree_host_->rendering_stats_instrumentation();
-    benchmark_instrumentation::IssueMainThreadRenderingStatsEvent(
-        stats_instrumentation->main_thread_rendering_stats());
-    stats_instrumentation->AccumulateAndClearMainThreadStats();
   }
 
   if (layer_tree_host_->settings().impl_side_painting) {
@@ -328,7 +345,6 @@
   TRACE_EVENT1(
       "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
   DCHECK(Proxy::IsImplThread());
-  UpdateBackgroundAnimateTicking();
   if (scheduler_on_impl_thread_)
     scheduler_on_impl_thread_->SetCanDraw(can_draw);
 }
@@ -340,6 +356,9 @@
     scheduler_on_impl_thread_->NotifyReadyToActivate();
 }
 
+void SingleThreadProxy::NotifyReadyToDraw() {
+}
+
 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
   client_->ScheduleComposite();
   if (scheduler_on_impl_thread_)
@@ -347,7 +366,9 @@
 }
 
 void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
-  SetNeedsRedrawOnImplThread();
+  client_->ScheduleComposite();
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->SetNeedsAnimate();
 }
 
 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
@@ -420,7 +441,6 @@
                    weak_factory_.GetWeakPtr()));
   }
 
-  UpdateBackgroundAnimateTicking();
   timing_history_.DidActivateSyncTree();
 }
 
@@ -498,6 +518,8 @@
       layer_tree_host_impl_->SynchronouslyInitializeAllTiles();
     }
 
+    DoAnimate();
+
     LayerTreeHostImpl::FrameData frame;
     DoComposite(frame_begin_time, &frame);
 
@@ -539,12 +561,6 @@
          layer_tree_host_impl_->CanDraw();
 }
 
-void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
-  DCHECK(Proxy::IsImplThread());
-  layer_tree_host_impl_->UpdateBackgroundAnimateTicking(
-      !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer());
-}
-
 void SingleThreadProxy::ScheduleRequestNewOutputSurface() {
   if (output_surface_creation_callback_.IsCancelled() &&
       !output_surface_creation_requested_) {
@@ -572,16 +588,11 @@
     // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
     // CanDraw() as well.
     if (!ShouldComposite()) {
-      UpdateBackgroundAnimateTicking();
       return DRAW_ABORTED_CANT_DRAW;
     }
 
     timing_history_.DidStartDrawing();
 
-    layer_tree_host_impl_->Animate(
-        layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
-    UpdateBackgroundAnimateTicking();
-
     draw_result = layer_tree_host_impl_->PrepareToDraw(frame);
     draw_frame = draw_result == DRAW_SUCCESS;
     if (draw_frame)
@@ -629,10 +640,6 @@
   return false;
 }
 
-BeginFrameSource* SingleThreadProxy::ExternalBeginFrameSource() {
-  return layer_tree_host_impl_.get();
-}
-
 void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
   layer_tree_host_impl_->WillBeginImplFrame(args);
 }
@@ -742,8 +749,8 @@
 
 void SingleThreadProxy::ScheduledActionAnimate() {
   TRACE_EVENT0("cc", "ScheduledActionAnimate");
-  layer_tree_host_impl_->Animate(
-      layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
+  DebugScopedSetImplThread impl(this);
+  DoAnimate();
 }
 
 void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() {
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 5b3766b..fa300de 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -19,6 +19,7 @@
 
 namespace cc {
 
+class BeginFrameSource;
 class ContextProvider;
 class LayerTreeHost;
 class LayerTreeHostSingleThreadClient;
@@ -30,7 +31,8 @@
   static scoped_ptr<Proxy> Create(
       LayerTreeHost* layer_tree_host,
       LayerTreeHostSingleThreadClient* client,
-      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
   ~SingleThreadProxy() override;
 
   // Proxy implementation
@@ -59,7 +61,6 @@
   bool MainFrameWillHappenForTesting() override;
 
   // SchedulerClient implementation
-  BeginFrameSource* ExternalBeginFrameSource() override;
   void WillBeginImplFrame(const BeginFrameArgs& args) override;
   void ScheduledActionSendBeginMainFrame() override;
   DrawResult ScheduledActionDrawAndSwapIfPossible() override;
@@ -87,6 +88,7 @@
   void DidSwapBuffersCompleteOnImplThread() override;
   void OnCanDrawStateChanged(bool can_draw) override;
   void NotifyReadyToActivate() override;
+  void NotifyReadyToDraw() override;
   void SetNeedsRedrawOnImplThread() override;
   void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override;
   void SetNeedsAnimateOnImplThread() override;
@@ -114,10 +116,12 @@
   SingleThreadProxy(
       LayerTreeHost* layer_tree_host,
       LayerTreeHostSingleThreadClient* client,
-      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
 
   void BeginMainFrame();
   void BeginMainFrameAbortedOnImplThread();
+  void DoAnimate();
   void DoBeginMainFrame(const BeginFrameArgs& begin_frame_args);
   void DoCommit();
   DrawResult DoComposite(base::TimeTicks frame_begin_time,
@@ -127,7 +131,6 @@
   void CommitComplete();
 
   bool ShouldComposite() const;
-  void UpdateBackgroundAnimateTicking();
   void ScheduleRequestNewOutputSurface();
 
   // Accessed on main thread only.
@@ -160,6 +163,8 @@
   // This is the callback for the scheduled RequestNewOutputSurface.
   base::CancelableClosure output_surface_creation_callback_;
 
+  scoped_ptr<BeginFrameSource> external_begin_frame_source_;
+
   base::WeakPtrFactory<SingleThreadProxy> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SingleThreadProxy);
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 14e2181..0f7a2a3 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -48,22 +48,27 @@
 scoped_ptr<Proxy> ThreadProxy::Create(
     LayerTreeHost* layer_tree_host,
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
-  return make_scoped_ptr(
-      new ThreadProxy(layer_tree_host, main_task_runner, impl_task_runner));
+    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+  return make_scoped_ptr(new ThreadProxy(layer_tree_host,
+                                         main_task_runner,
+                                         impl_task_runner,
+                                         external_begin_frame_source.Pass()));
 }
 
 ThreadProxy::ThreadProxy(
     LayerTreeHost* layer_tree_host,
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
+    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source)
     : Proxy(main_task_runner, impl_task_runner),
       main_thread_only_vars_unsafe_(this, layer_tree_host->id()),
       main_thread_or_blocked_vars_unsafe_(layer_tree_host),
       compositor_thread_vars_unsafe_(
           this,
           layer_tree_host->id(),
-          layer_tree_host->rendering_stats_instrumentation()) {
+          layer_tree_host->rendering_stats_instrumentation(),
+          external_begin_frame_source.Pass()) {
   TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy");
   DCHECK(IsMainThread());
   DCHECK(this->layer_tree_host());
@@ -99,7 +104,8 @@
 ThreadProxy::CompositorThreadOnly::CompositorThreadOnly(
     ThreadProxy* proxy,
     int layer_tree_host_id,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation)
+    RenderingStatsInstrumentation* rendering_stats_instrumentation,
+    scoped_ptr<BeginFrameSource> external_begin_frame_source)
     : layer_tree_host_id(layer_tree_host_id),
       contents_texture_manager(NULL),
       commit_completion_event(NULL),
@@ -113,6 +119,7 @@
           base::TimeDelta::FromMilliseconds(
               kSmoothnessTakesPriorityExpirationDelay * 1000)),
       timing_history(rendering_stats_instrumentation),
+      external_begin_frame_source(external_begin_frame_source.Pass()),
       weak_factory(proxy) {
 }
 
@@ -176,18 +183,9 @@
   TRACE_EVENT0("cc", "ThreadProxy::SetVisibleOnImplThread");
   impl().layer_tree_host_impl->SetVisible(visible);
   impl().scheduler->SetVisible(visible);
-  UpdateBackgroundAnimateTicking();
   completion->Signal();
 }
 
-void ThreadProxy::UpdateBackgroundAnimateTicking() {
-  bool should_background_tick =
-      !impl().scheduler->WillDrawIfNeeded() &&
-      impl().layer_tree_host_impl->active_tree()->root_layer();
-  impl().layer_tree_host_impl->UpdateBackgroundAnimateTicking(
-      should_background_tick);
-}
-
 void ThreadProxy::DidLoseOutputSurface() {
   TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurface");
   DCHECK(IsMainThread());
@@ -345,10 +343,6 @@
       base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_));
 }
 
-BeginFrameSource* ThreadProxy::ExternalBeginFrameSource() {
-  return impl().layer_tree_host_impl.get();
-}
-
 void ThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
   impl().layer_tree_host_impl->WillBeginImplFrame(args);
 }
@@ -358,7 +352,6 @@
       "cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
   DCHECK(IsImplThread());
   impl().scheduler->SetCanDraw(can_draw);
-  UpdateBackgroundAnimateTicking();
 }
 
 void ThreadProxy::NotifyReadyToActivate() {
@@ -366,6 +359,11 @@
   impl().scheduler->NotifyReadyToActivate();
 }
 
+void ThreadProxy::NotifyReadyToDraw() {
+  TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToDraw");
+  impl().scheduler->NotifyReadyToDraw();
+}
+
 void ThreadProxy::SetNeedsCommitOnImplThread() {
   TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommitOnImplThread");
   DCHECK(IsImplThread());
@@ -851,12 +849,6 @@
                    &completion,
                    queue.release()));
     completion.Wait();
-
-    RenderingStatsInstrumentation* stats_instrumentation =
-        layer_tree_host()->rendering_stats_instrumentation();
-    benchmark_instrumentation::IssueMainThreadRenderingStatsEvent(
-        stats_instrumentation->main_thread_rendering_stats());
-    stats_instrumentation->AccumulateAndClearMainThreadStats();
   }
 
   layer_tree_host()->CommitComplete();
@@ -933,9 +925,22 @@
   TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionAnimate");
   DCHECK(IsImplThread());
 
+  // Don't animate if there is no root layer.
+  // TODO(mithro): Both Animate and UpdateAnimationState already have a
+  // "!active_tree_->root_layer()" check?
+  if (!impl().layer_tree_host_impl->active_tree()->root_layer()) {
+    return;
+  }
+
   impl().animation_time =
       impl().layer_tree_host_impl->CurrentBeginFrameArgs().frame_time;
   impl().layer_tree_host_impl->Animate(impl().animation_time);
+
+  // If animations are not visible, update the state now as
+  // ScheduledActionDrawAndSwapIfPossible will never be called.
+  if (!impl().layer_tree_host_impl->AnimationsAreVisible()) {
+    impl().layer_tree_host_impl->UpdateAnimationState(true);
+  }
 }
 
 void ThreadProxy::ScheduledActionCommit() {
@@ -979,8 +984,6 @@
 
   SetInputThrottledUntilCommitOnImplThread(false);
 
-  UpdateBackgroundAnimateTicking();
-
   impl().next_frame_is_newly_committed_frame = true;
 
   impl().timing_history.DidCommit();
@@ -1149,13 +1152,14 @@
   impl().layer_tree_host_impl =
       layer_tree_host()->CreateLayerTreeHostImpl(this);
   SchedulerSettings scheduler_settings(layer_tree_host()->settings());
-  impl().scheduler = Scheduler::Create(this,
-                                       scheduler_settings,
-                                       impl().layer_tree_host_id,
-                                       ImplThreadTaskRunner(),
-                                       base::PowerMonitor::Get());
+  impl().scheduler = Scheduler::Create(
+                         this,
+                         scheduler_settings,
+                         impl().layer_tree_host_id,
+                         ImplThreadTaskRunner(),
+                         base::PowerMonitor::Get(),
+                         impl().external_begin_frame_source.Pass());
   impl().scheduler->SetVisible(impl().layer_tree_host_impl->visible());
-
   impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr();
   completion->Signal();
 }
@@ -1213,7 +1217,6 @@
   layer_tree_host()->DeleteContentsTexturesOnImplThread(
       impl().layer_tree_host_impl->resource_provider());
   impl().current_resource_update_controller = nullptr;
-  impl().layer_tree_host_impl->SetNeedsBeginFrames(false);
   impl().scheduler = nullptr;
   impl().layer_tree_host_impl = nullptr;
   impl().weak_factory.InvalidateWeakPtrs();
@@ -1358,8 +1361,6 @@
     impl().completion_event_for_commit_held_on_tree_activation = NULL;
   }
 
-  UpdateBackgroundAnimateTicking();
-
   impl().timing_history.DidActivateSyncTree();
 }
 
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index 2f3e7c5..adccf72 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -25,6 +25,7 @@
 
 namespace cc {
 
+class BeginFrameSource;
 class ContextProvider;
 class InputHandlerClient;
 class LayerTreeHost;
@@ -40,7 +41,8 @@
   static scoped_ptr<Proxy> Create(
       LayerTreeHost* layer_tree_host,
       scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
 
   ~ThreadProxy() override;
 
@@ -96,7 +98,8 @@
     CompositorThreadOnly(
         ThreadProxy* proxy,
         int layer_tree_host_id,
-        RenderingStatsInstrumentation* rendering_stats_instrumentation);
+        RenderingStatsInstrumentation* rendering_stats_instrumentation,
+        scoped_ptr<BeginFrameSource> external_begin_frame_source);
     ~CompositorThreadOnly();
 
     const int layer_tree_host_id;
@@ -137,6 +140,8 @@
 
     ProxyTimingHistory timing_history;
 
+    scoped_ptr<BeginFrameSource> external_begin_frame_source;
+
     scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl;
     base::WeakPtrFactory<ThreadProxy> weak_factory;
   };
@@ -182,6 +187,7 @@
   void DidSwapBuffersCompleteOnImplThread() override;
   void OnCanDrawStateChanged(bool can_draw) override;
   void NotifyReadyToActivate() override;
+  void NotifyReadyToDraw() override;
   // Please call these 3 functions through
   // LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and
   // SetNeedsAnimate().
@@ -203,7 +209,6 @@
   void DidManageTiles() override;
 
   // SchedulerClient implementation
-  BeginFrameSource* ExternalBeginFrameSource() override;
   void WillBeginImplFrame(const BeginFrameArgs& args) override;
   void ScheduledActionSendBeginMainFrame() override;
   DrawResult ScheduledActionDrawAndSwapIfPossible() override;
@@ -224,9 +229,11 @@
   void ReadyToFinalizeTextureUpdates() override;
 
  protected:
-  ThreadProxy(LayerTreeHost* layer_tree_host,
-              scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
-              scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+  ThreadProxy(
+      LayerTreeHost* layer_tree_host,
+      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+      scoped_ptr<BeginFrameSource> external_begin_frame_source);
 
  private:
   // Called on main thread.
@@ -253,7 +260,6 @@
   void InitializeImplOnImplThread(CompletionEvent* completion);
   void SetLayerTreeHostClientReadyOnImplThread();
   void SetVisibleOnImplThread(CompletionEvent* completion, bool visible);
-  void UpdateBackgroundAnimateTicking();
   void HasInitializedOutputSurfaceOnImplThread(
       CompletionEvent* completion,
       bool* has_initialized_output_surface);
diff --git a/crypto/BUILD.gn b/crypto/BUILD.gn
index 5991d02..f342af9 100644
--- a/crypto/BUILD.gn
+++ b/crypto/BUILD.gn
@@ -124,11 +124,6 @@
     deps += [ "//third_party/android_tools:cpu_features" ]
   }
 
-  if (is_win) {
-    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
-    cflags = [ "/wd4267" ]
-  }
-
   if (use_openssl) {
     # Remove NSS files when using OpenSSL
     sources -= [
@@ -173,7 +168,9 @@
   defines = [ "CRYPTO_IMPLEMENTATION" ]
 }
 
-if (is_win) {
+# TODO(GYP): TODO(dpranke), fix the compile errors for this stuff
+# and make it work.
+if (false && is_win) {
   # A minimal crypto subset for hmac-related stuff that small standalone
   # targets can use to reduce code size on Windows. This does not depend on
   # OpenSSL/NSS but will use Windows APIs for that functionality.
@@ -203,52 +200,55 @@
   }
 }
 
-test("crypto_unittests") {
-  sources = [
-    # Tests.
-    "curve25519_unittest.cc",
-    "ec_private_key_unittest.cc",
-    "ec_signature_creator_unittest.cc",
-    "encryptor_unittest.cc",
-    "ghash_unittest.cc",
-    "hkdf_unittest.cc",
-    "hmac_unittest.cc",
-    "nss_util_unittest.cc",
-    "openssl_bio_string_unittest.cc",
-    "p224_unittest.cc",
-    "p224_spake_unittest.cc",
-    "random_unittest.cc",
-    "rsa_private_key_unittest.cc",
-    "rsa_private_key_nss_unittest.cc",
-    "secure_hash_unittest.cc",
-    "sha2_unittest.cc",
-    "signature_creator_unittest.cc",
-    "signature_verifier_unittest.cc",
-    "symmetric_key_unittest.cc",
-  ]
-
-  if (use_openssl || !is_linux) {
-    sources -= [
+# TODO(GYP): Make this link on win as well.
+if (!is_win) {
+  test("crypto_unittests") {
+    sources = [
+      # Tests.
+      "curve25519_unittest.cc",
+      "ec_private_key_unittest.cc",
+      "ec_signature_creator_unittest.cc",
+      "encryptor_unittest.cc",
+      "ghash_unittest.cc",
+      "hkdf_unittest.cc",
+      "hmac_unittest.cc",
+      "nss_util_unittest.cc",
+      "openssl_bio_string_unittest.cc",
+      "p224_unittest.cc",
+      "p224_spake_unittest.cc",
+      "random_unittest.cc",
+      "rsa_private_key_unittest.cc",
       "rsa_private_key_nss_unittest.cc",
+      "secure_hash_unittest.cc",
+      "sha2_unittest.cc",
+      "signature_creator_unittest.cc",
+      "signature_verifier_unittest.cc",
+      "symmetric_key_unittest.cc",
+    ]
+
+    if (use_openssl || !is_linux) {
+      sources -= [
+        "rsa_private_key_nss_unittest.cc",
+      ]
+    }
+
+    if (use_openssl) {
+      sources -= [ "nss_util_unittest.cc" ]
+    } else {
+      sources -= [ "openssl_bio_string_unittest.cc" ]
+    }
+
+    deps = [
+      ":crypto",
+      ":platform",
+      ":test_support",
+      "//base",
+      "//base/test:run_all_unittests",
+      "//base/test:test_support",
+      "//testing/gmock",
+      "//testing/gtest",
     ]
   }
-
-  if (use_openssl) {
-    sources -= [ "nss_util_unittest.cc" ]
-  } else {
-    sources -= [ "openssl_bio_string_unittest.cc" ]
-  }
-
-  deps = [
-    ":crypto",
-    ":platform",
-    ":test_support",
-    "//base",
-    "//base/test:run_all_unittests",
-    "//base/test:test_support",
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
 }
 
 source_set("test_support") {
diff --git a/crypto/ec_signature_creator_openssl.cc b/crypto/ec_signature_creator_openssl.cc
index 91e8a6a..c422cef 100644
--- a/crypto/ec_signature_creator_openssl.cc
+++ b/crypto/ec_signature_creator_openssl.cc
@@ -60,24 +60,13 @@
 
   // The result is made of two 32-byte vectors.
   const size_t kMaxBytesPerBN = 32;
-  std::vector<uint8> result;
-  result.resize(2 * kMaxBytesPerBN);
-  memset(&result[0], 0, result.size());
+  std::vector<uint8> result(2 * kMaxBytesPerBN);
 
-  BIGNUM* r = ecdsa_sig.get()->r;
-  BIGNUM* s = ecdsa_sig.get()->s;
-  int r_bytes = BN_num_bytes(r);
-  int s_bytes = BN_num_bytes(s);
-  // NOTE: Can't really check for equality here since sometimes the value
-  // returned by BN_num_bytes() will be slightly smaller than kMaxBytesPerBN.
-  if (r_bytes > static_cast<int>(kMaxBytesPerBN) ||
-      s_bytes > static_cast<int>(kMaxBytesPerBN)) {
-    DLOG(ERROR) << "Invalid key sizes r(" << r_bytes << ") s(" << s_bytes
-                << ")";
+  if (!BN_bn2bin_padded(&result[0], kMaxBytesPerBN, ecdsa_sig->r) ||
+      !BN_bn2bin_padded(&result[kMaxBytesPerBN], kMaxBytesPerBN,
+                        ecdsa_sig->s)) {
     return false;
   }
-  BN_bn2bin(ecdsa_sig.get()->r, &result[kMaxBytesPerBN - r_bytes]);
-  BN_bn2bin(ecdsa_sig.get()->s, &result[2 * kMaxBytesPerBN - s_bytes]);
   out_raw_sig->swap(result);
   return true;
 }
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc
index 8f9865a..02c9327 100644
--- a/crypto/nss_util.cc
+++ b/crypto/nss_util.cc
@@ -835,7 +835,8 @@
       base::CPU cpu;
 
       if (cpu.has_avx_hardware() && !cpu.has_avx()) {
-        base::Environment::Create()->SetVar("NSS_DISABLE_HW_AES", "1");
+        scoped_ptr<base::Environment> env(base::Environment::Create());
+        env->SetVar("NSS_DISABLE_HW_AES", "1");
       }
     }
   }
diff --git a/crypto/rsa_private_key_nss.cc b/crypto/rsa_private_key_nss.cc
index 078544d..0065875 100644
--- a/crypto/rsa_private_key_nss.cc
+++ b/crypto/rsa_private_key_nss.cc
@@ -285,6 +285,9 @@
   // and signature generation.
   const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
                                  KU_DIGITAL_SIGNATURE;
+  // TODO(davidben): PK11_ImportDERPrivateKeyInfoAndReturnKey calls NSS's
+  // SEC_ASN1DecodeItem which does not enforce that there is no trailing
+  // data.
   SECStatus rv =  PK11_ImportDERPrivateKeyInfoAndReturnKey(
       slot, &der_private_key_info, NULL, NULL, permanent, sensitive,
       key_usage, &result->key_, NULL);
diff --git a/crypto/rsa_private_key_openssl.cc b/crypto/rsa_private_key_openssl.cc
index 053c4a2..0df1730 100644
--- a/crypto/rsa_private_key_openssl.cc
+++ b/crypto/rsa_private_key_openssl.cc
@@ -19,6 +19,9 @@
 
 namespace {
 
+typedef ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type
+    ScopedPKCS8_PRIV_KEY_INFO;
+
 // Function pointer definition, for injecting the required key export function
 // into ExportKey, below. The supplied function should export EVP_PKEY into
 // the supplied BIO, returning 1 on success or 0 on failure.
@@ -76,17 +79,16 @@
     return NULL;
 
   OpenSSLErrStackTracer err_tracer(FROM_HERE);
-  // BIO_new_mem_buf is not const aware, but it does not modify the buffer.
-  char* data = reinterpret_cast<char*>(const_cast<uint8*>(&input[0]));
-  ScopedBIO bio(BIO_new_mem_buf(data, input.size()));
-  if (!bio.get())
-    return NULL;
 
   // Importing is a little more involved than exporting, as we must first
   // PKCS#8 decode the input, and then import the EVP_PKEY from Private Key
   // Info structure returned.
-  ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type p8inf(
-      d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
+  //
+  // TODO(davidben): This should check that |ptr| advanced to the end of |input|
+  // to ensure there is no trailing data.
+  const uint8_t* ptr = &input[0];
+  ScopedPKCS8_PRIV_KEY_INFO p8inf(
+      d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr, input.size()));
   if (!p8inf.get())
     return NULL;
 
diff --git a/crypto/signature_verifier_openssl.cc b/crypto/signature_verifier_openssl.cc
index a855120..93ce9ba 100644
--- a/crypto/signature_verifier_openssl.cc
+++ b/crypto/signature_verifier_openssl.cc
@@ -122,8 +122,7 @@
   int rv = EVP_DigestVerifyFinal(verify_context_->ctx.get(),
                                  vector_as_array(&signature_),
                                  signature_.size());
-  // rv is -1 if a DER-encoded ECDSA signature cannot be decoded correctly.
-  DCHECK_GE(rv, -1);
+  DCHECK_EQ(static_cast<int>(!!rv), rv);
   Reset();
   return rv == 1;
 }
@@ -141,19 +140,14 @@
 
   signature_.assign(signature, signature + signature_len);
 
-  // BIO_new_mem_buf is not const aware, but it does not modify the buffer.
-  char* data = reinterpret_cast<char*>(const_cast<uint8*>(public_key_info));
-  ScopedBIO bio(BIO_new_mem_buf(data, public_key_info_len));
-  if (!bio.get())
-    return false;
-
-  ScopedEVP_PKEY public_key(d2i_PUBKEY_bio(bio.get(), NULL));
-  if (!public_key.get())
+  const uint8_t* ptr = public_key_info;
+  ScopedEVP_PKEY public_key(d2i_PUBKEY(nullptr, &ptr, public_key_info_len));
+  if (!public_key.get() || ptr != public_key_info + public_key_info_len)
     return false;
 
   verify_context_->ctx.reset(EVP_MD_CTX_create());
   int rv = EVP_DigestVerifyInit(verify_context_->ctx.get(), pkey_ctx,
-                                digest, NULL, public_key.get());
+                                digest, nullptr, public_key.get());
   return rv == 1;
 }
 
diff --git a/crypto/signature_verifier_unittest.cc b/crypto/signature_verifier_unittest.cc
index f6c42e0..b521bd7 100644
--- a/crypto/signature_verifier_unittest.cc
+++ b/crypto/signature_verifier_unittest.cc
@@ -258,6 +258,26 @@
     ok = verifier.VerifyFinal();
     EXPECT_FALSE(ok);
   }
+
+  // Test 5: import an invalid key.
+  uint8_t bad_public_key_info[sizeof(public_key_info)];
+  memcpy(bad_public_key_info, public_key_info, sizeof(public_key_info));
+  bad_public_key_info[0] += 1;  // Corrupt part of the SPKI syntax.
+  ok = verifier.VerifyInit(signature_algorithm,
+                           sizeof(signature_algorithm),
+                           signature, sizeof(signature),
+                           bad_public_key_info, sizeof(bad_public_key_info));
+  EXPECT_FALSE(ok);
+
+  // Test 6: import a key with extra data.
+  uint8_t long_public_key_info[sizeof(public_key_info) + 5];
+  memset(long_public_key_info, 0, sizeof(long_public_key_info));
+  memcpy(long_public_key_info, public_key_info, sizeof(public_key_info));
+  ok = verifier.VerifyInit(signature_algorithm,
+                           sizeof(signature_algorithm),
+                           signature, sizeof(signature),
+                           long_public_key_info, sizeof(long_public_key_info));
+  EXPECT_FALSE(ok);
 }
 
 //////////////////////////////////////////////////////////////////////
diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc
index 334c0e0..2cdacc0 100644
--- a/gin/isolate_holder.cc
+++ b/gin/isolate_holder.cc
@@ -7,6 +7,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "base/files/memory_mapped_file.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/rand_util.h"
@@ -19,7 +20,6 @@
 #include "gin/run_microtasks_observer.h"
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
-#include "base/files/memory_mapped_file.h"
 #include "base/path_service.h"
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 
@@ -34,10 +34,10 @@
   return true;
 }
 
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
 base::MemoryMappedFile* g_mapped_natives = NULL;
 base::MemoryMappedFile* g_mapped_snapshot = NULL;
 
+#ifdef V8_USE_EXTERNAL_STARTUP_DATA
 bool MapV8Files(base::FilePath* natives_path, base::FilePath* snapshot_path,
                 int natives_fd = -1, int snapshot_fd = -1) {
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
@@ -80,7 +80,13 @@
     return true;
 
   base::FilePath data_path;
-  PathService::Get(base::DIR_ANDROID_APP_DATA, &data_path);
+  PathService::Get(
+#if defined(OS_ANDROID)
+    base::DIR_ANDROID_APP_DATA,
+#elif defined(OS_POSIX)
+    base::DIR_EXE,
+#endif
+    &data_path);
   DCHECK(!data_path.empty());
 
   base::FilePath natives_path = data_path.AppendASCII("natives_blob.bin");
@@ -98,6 +104,22 @@
 }
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 
+//static
+void IsolateHolder::GetV8ExternalSnapshotData(const char** natives_data_out,
+                                              int* natives_size_out,
+                                              const char** snapshot_data_out,
+                                              int* snapshot_size_out) {
+  if (!g_mapped_natives || !g_mapped_snapshot) {
+    *natives_data_out = *snapshot_data_out = NULL;
+    *natives_size_out = *snapshot_size_out = 0;
+    return;
+  }
+  *natives_data_out = reinterpret_cast<const char*>(g_mapped_natives->data());
+  *snapshot_data_out = reinterpret_cast<const char*>(g_mapped_snapshot->data());
+  *natives_size_out = static_cast<int>(g_mapped_natives->length());
+  *snapshot_size_out = static_cast<int>(g_mapped_snapshot->length());
+}
+
 IsolateHolder::IsolateHolder() {
   CHECK(g_array_buffer_allocator)
       << "You need to invoke gin::IsolateHolder::Initialize first";
@@ -158,14 +180,14 @@
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   v8::StartupData natives;
   natives.data = reinterpret_cast<const char*>(g_mapped_natives->data());
-  natives.raw_size = g_mapped_natives->length();
-  natives.compressed_size = g_mapped_natives->length();
+  natives.raw_size = static_cast<int>(g_mapped_natives->length());
+  natives.compressed_size = static_cast<int>(g_mapped_natives->length());
   v8::V8::SetNativesDataBlob(&natives);
 
   v8::StartupData snapshot;
   snapshot.data = reinterpret_cast<const char*>(g_mapped_snapshot->data());
-  snapshot.raw_size = g_mapped_snapshot->length();
-  snapshot.compressed_size = g_mapped_snapshot->length();
+  snapshot.raw_size = static_cast<int>(g_mapped_snapshot->length());
+  snapshot.compressed_size = static_cast<int>(g_mapped_snapshot->length());
   v8::V8::SetSnapshotDataBlob(&snapshot);
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
   v8::V8::Initialize();
diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h
index 4e14ade..b12734c 100644
--- a/gin/public/isolate_holder.h
+++ b/gin/public/isolate_holder.h
@@ -52,11 +52,13 @@
   void RemoveRunMicrotasksObserver();
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
-#ifdef OS_ANDROID
   static bool LoadV8SnapshotFD(int natives_fd, int snapshot_fd);
-#endif
   static bool LoadV8Snapshot();
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
+  static void GetV8ExternalSnapshotData(const char** natives_data_out,
+                                        int* natives_size_out,
+                                        const char** snapshot_data_out,
+                                        int* snapshot_size_out);
 
  private:
   v8::Isolate* isolate_;
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index e8bf519..990cd02 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -184,6 +184,7 @@
     "command_buffer/service/gles2_cmd_decoder_unittest_programs.cc",
     "command_buffer/service/gles2_cmd_decoder_unittest_textures.cc",
     "command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc",
     "command_buffer/service/gl_surface_mock.cc",
     "command_buffer/service/gl_surface_mock.h",
     "command_buffer/service/gpu_scheduler_unittest.cc",
@@ -195,11 +196,13 @@
     "command_buffer/service/mocks.cc",
     "command_buffer/service/mocks.h",
     "command_buffer/service/program_manager_unittest.cc",
+    "command_buffer/service/valuebuffer_manager_unittest.cc",
     "command_buffer/service/query_manager_unittest.cc",
     "command_buffer/service/renderbuffer_manager_unittest.cc",
     "command_buffer/service/program_cache_unittest.cc",
     "command_buffer/service/shader_manager_unittest.cc",
     "command_buffer/service/shader_translator_unittest.cc",
+    "command_buffer/service/shader_translator_cache_unittest.cc",
     "command_buffer/service/test_helper.cc",
     "command_buffer/service/test_helper.h",
     "command_buffer/service/texture_manager_unittest.cc",
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt
index 0a35700..d4685d5 100644
--- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt
@@ -16,8 +16,8 @@
 
 Overview
 
-    This extension adds the ability to query multiple state and program
-    information in a single call.
+    This extension adds the ability to query multiple program information in a
+    single call.
 
 Issues
 
@@ -28,27 +28,6 @@
 
 New Procedures and Functions
 
-    void GetMultipleIntegervCHROMIUM (const GLenum* pnames, GLuint count,
-                                      GLint* results, GLsizeiptr size)
-
-    <pnames> points to an array of state enums that would normally be queried by
-    GetIntegerv. <count> is the number of pnames. <results> points memory large
-    enough to contain all the state being queried. <size> is the size of the
-    buffer pointed to be <results>
-
-    Example: <pnames> points to an array with VIEWPORT and MAX_TEXTURE_SIZE.
-    VIEWPORT returns 4 values, MAX_TEXTURE_SIZE returns 1 value. Therefore
-    results must point to a buffer of size 5 * sizeof(GLint) and size must be at
-    least 5 * sizeof(GLint)
-
-    INVALID_ENUM is generated if any of the pnames are not valid for GetIntegerv
-
-    INVALID_VALUE is generated if <size> does not equal the size needed for the
-    query
-
-    INVALID_VALUE is generated if the memory pointed to be <results> has not
-    been zeroed out.
-
     void GetProgrmaInfoCHROMIUM (GLuint program, GLsizei bufsize,
                                  GLsizei* size, void* info)
 
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_subscribe_uniform.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_subscribe_uniform.txt
new file mode 100644
index 0000000..2427d32
--- /dev/null
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_subscribe_uniform.txt
@@ -0,0 +1,113 @@
+Name
+
+    CHROMIUM_subscribe_uniform
+
+Name Strings
+
+    CHROMIUM_subscribe_uniform
+
+Version
+
+    Last Modifed Date: October 30, 2014
+
+Dependencies
+
+    OpenGL ES 2.0 is required.
+
+Overview
+
+    Allows clients to subscribe to a set of input uniforms which can
+    be populated within buffers and used to modify uniform variables within
+    their programs.
+
+    Decreases percieved latency for operations performed against these
+    uniforms.
+
+New Tokens
+
+    Accepted by the <target> parameter of glBindValueBufferCHROMIUM,
+    glSubscribeValueCHROMIUM, glPopulateSubscribedValuesCHROMIUM and
+    glUniformValueBufferCHROMIUM
+
+    GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM                        0x924B
+
+    Accepted by the <subscription> parameter of glSubscribeValueCHROMIUM and
+    glUniformValueBufferCHROMIUM:
+
+    GL_MOUSE_POSITION_CHROMIUM                                  0x924C
+
+New Procedures and Functions
+
+    The command
+
+       void glGenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers)
+
+    Generates value buffer object names.
+    <n> Specifies the number of value buffer object names to be generated.
+    <buffers> Specifies an array in which the generated value buffer object 
+              names are stored.
+
+   The command
+
+      void glDeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers)
+
+   Deletes named value buffer objects.
+   <n> Specifies the number of value buffer objects to be deleted.
+   <buffers> Specifies an array of value buffer objects to be deleted.
+
+   The command
+
+      boolean glIsValuebufferCHROMIUM(GLuint buffer);
+
+   Returns whether an object is a value buffer object.
+   <buffer> Specifies the name of a buffer object.
+
+   The command
+
+      void glBindValuebufferCHROMIUM(GLenum target, GLuint buffer);
+
+   Lets you use a named value buffer object.
+   <target> Specifies the target to which the buffer object is bound.
+   <buffer> Specifies the name of a buffer object.
+
+   The command
+
+      void glSubscribeValueCHROMIUM(GLenum target, GLenum subscription)
+
+   Subscribes the currently bound buffer object to a subscription target.
+   <target> Specifies the target to which the buffer object is bound.
+   <subscription> Specifies the subscription to which the currently bound
+                  buffer object should be subscribed.
+
+   The command
+
+      void glPopulateSubscribedValuesCHROMIUM(GLenum target)
+
+   Populates the currently bound buffer object with all subscription states
+   to which it is subscribed.
+   <target> Specifies the target to which the buffer object is bound.
+
+   The command
+ 
+      void glUniformValueBufferCHROMIUM(GLint location, GLenum target,
+                                       GLenum subscription)
+
+   Populates the uniform specified by location within the currently bound
+   program with the value in the currently bound buffer for the subscription
+   target.
+   <location> Specifies the location of the uniform variable to by modified.
+   <target> Specifies the target to which the buffer object is bound.
+   <subscription> Specifies the subscription in the currently bound buffer
+                  whose value should be used to populate the uniform.
+
+Errors
+
+    None.
+
+New State
+
+    None.
+
+Revision History
+
+    10/30/2014    Documented the extension
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index c6a3919..5489d06 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -195,7 +195,6 @@
 #define glRequestExtensionCHROMIUM GLES2_GET_FUN(RequestExtensionCHROMIUM)
 #define glRateLimitOffscreenContextCHROMIUM \
   GLES2_GET_FUN(RateLimitOffscreenContextCHROMIUM)
-#define glGetMultipleIntegervCHROMIUM GLES2_GET_FUN(GetMultipleIntegervCHROMIUM)
 #define glGetProgramInfoCHROMIUM GLES2_GET_FUN(GetProgramInfoCHROMIUM)
 #define glCreateStreamTextureCHROMIUM GLES2_GET_FUN(CreateStreamTextureCHROMIUM)
 #define glCreateImageCHROMIUM GLES2_GET_FUN(CreateImageCHROMIUM)
@@ -218,6 +217,14 @@
 #define glCreateAndConsumeTextureCHROMIUM \
   GLES2_GET_FUN(CreateAndConsumeTextureCHROMIUM)
 #define glBindUniformLocationCHROMIUM GLES2_GET_FUN(BindUniformLocationCHROMIUM)
+#define glGenValuebuffersCHROMIUM GLES2_GET_FUN(GenValuebuffersCHROMIUM)
+#define glDeleteValuebuffersCHROMIUM GLES2_GET_FUN(DeleteValuebuffersCHROMIUM)
+#define glIsValuebufferCHROMIUM GLES2_GET_FUN(IsValuebufferCHROMIUM)
+#define glBindValuebufferCHROMIUM GLES2_GET_FUN(BindValuebufferCHROMIUM)
+#define glSubscribeValueCHROMIUM GLES2_GET_FUN(SubscribeValueCHROMIUM)
+#define glPopulateSubscribedValuesCHROMIUM \
+  GLES2_GET_FUN(PopulateSubscribedValuesCHROMIUM)
+#define glUniformValuebufferCHROMIUM GLES2_GET_FUN(UniformValuebufferCHROMIUM)
 #define glBindTexImage2DCHROMIUM GLES2_GET_FUN(BindTexImage2DCHROMIUM)
 #define glReleaseTexImage2DCHROMIUM GLES2_GET_FUN(ReleaseTexImage2DCHROMIUM)
 #define glTraceBeginCHROMIUM GLES2_GET_FUN(TraceBeginCHROMIUM)
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h
index b524112..a4017ec 100644
--- a/gpu/GLES2/gl2extchromium.h
+++ b/gpu/GLES2/gl2extchromium.h
@@ -623,13 +623,9 @@
 #ifndef GL_CHROMIUM_get_multiple
 #define GL_CHROMIUM_get_multiple 1
 #ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glGetMultipleIntegervCHROMIUM(
-    const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
 GL_APICALL void GL_APIENTRY glGetProgramInfoCHROMIUM(
     GLuint program, GLsizei bufsize, GLsizei* size, void* info);
 #endif
-typedef void (GL_APIENTRYP PFNGLGETMULTIPLEINTEGERVCHROMIUMPROC) (
-   const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
 typedef void (GL_APIENTRYP PFNGLGETPROGRAMINFOCHROMIUMPROC) (
    GLuint program, GLsizei bufsize, GLsizei* size, void* info);
 #endif  /* GL_CHROMIUM_get_multiple */
@@ -687,6 +683,35 @@
 #define GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM 0x924A
 #endif
 
+/* GL_CHROMIUM_subscribe_uniform */
+#ifndef GL_CHROMIUM_subscribe_uniform
+#define GL_CHROMIUM_subscribe_uniform 1
+
+#ifndef GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM
+#define GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM 0x924B
+#endif
+
+#ifndef GL_MOUSE_POSITION_CHROMIUM
+#define GL_MOUSE_POSITION_CHROMIUM 0x924C
+#endif
+
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY
+glGenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY
+glDeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers);
+GL_APICALL GLboolean GL_APIENTRY glIsValuebufferCHROMIUM(GLuint valuebuffer);
+GL_APICALL void GL_APIENTRY
+glBindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer);
+GL_APICALL void GL_APIENTRY
+glSubscribeValueCHROMIUM(GLenum target, GLenum subscription);
+GL_APICALL void GL_APIENTRY glPopulateSubscribedValuesCHROMIUM(GLenum target);
+GL_APICALL void GL_APIENTRY glUniformValuebufferCHROMIUM(GLint location,
+                                                         GLenum target,
+                                                         GLenum subscription);
+#endif
+#endif /* GL_CHROMIUM_subscribe_uniform */
+
 #ifdef GL_GLEXT_PROTOTYPES
 GL_APICALL void GL_APIENTRY
     glScheduleOverlayPlaneCHROMIUM(GLint plane_z_order,
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 94c3b34..226cb73 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1195,6 +1195,18 @@
       'GL_SCANOUT_CHROMIUM'
     ],
   },
+  'ValueBufferTarget': {
+    'type': 'GLenum',
+    'valid': [
+      'GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM',
+    ],
+  },
+  'SubscriptionTarget': {
+    'type': 'GLenum',
+    'valid': [
+      'GL_MOUSE_POSITION_CHROMIUM',
+    ],
+  },
   'VertexAttribType': {
     'type': 'GLenum',
     'valid': [
@@ -1448,6 +1460,57 @@
     'extension': "CHROMIUM_texture_mailbox",
     'chromium': True,
   },
+  'GenValuebuffersCHROMIUM': {
+    'type': 'GENn',
+    'gl_test_func': 'glGenValuebuffersCHROMIUM',
+    'resource_type': 'Valuebuffer',
+    'resource_types': 'Valuebuffers',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'DeleteValuebuffersCHROMIUM': {
+    'type': 'DELn',
+    'gl_test_func': 'glDeleteValuebuffersCHROMIUM',
+    'resource_type': 'Valuebuffer',
+    'resource_types': 'Valuebuffers',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'IsValuebufferCHROMIUM': {
+    'type': 'Is',
+    'decoder_func': 'DoIsValuebufferCHROMIUM',
+    'expectation': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'BindValuebufferCHROMIUM': {
+    'type': 'Bind',
+    'decoder_func': 'DoBindValueBufferCHROMIUM',
+    'gen_func': 'GenValueBuffersCHROMIUM',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'SubscribeValueCHROMIUM': {
+    'decoder_func': 'DoSubscribeValueCHROMIUM',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'PopulateSubscribedValuesCHROMIUM': {
+    'decoder_func': 'DoPopulateSubscribedValuesCHROMIUM',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
+  'UniformValuebufferCHROMIUM': {
+    'decoder_func': 'DoUniformValueBufferCHROMIUM',
+    'unit_test': False,
+    'extension': True,
+    'chromium': True,
+  },
   'ClearStencil': {
     'type': 'StateSet',
     'state': 'ClearStencil',
@@ -1807,14 +1870,6 @@
     'chromium': True,
     'impl_func': False,
   },
-  'GetMultipleIntegervCHROMIUM': {
-    'type': 'Custom',
-    'data_transfer_methods': ['shm'],
-    'expectation': False,
-    'extension': True,
-    'chromium': True,
-    'client_test': False,
-  },
   'GetProgramiv': {
     'type': 'GETn',
     'decoder_func': 'DoGetProgramiv',
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 56f1880..b1181ae 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -751,13 +751,6 @@
 void GLES2RateLimitOffscreenContextCHROMIUM() {
   gles2::GetGLContext()->RateLimitOffscreenContextCHROMIUM();
 }
-void GLES2GetMultipleIntegervCHROMIUM(const GLenum* pnames,
-                                      GLuint count,
-                                      GLint* results,
-                                      GLsizeiptr size) {
-  gles2::GetGLContext()->GetMultipleIntegervCHROMIUM(pnames, count, results,
-                                                     size);
-}
 void GLES2GetProgramInfoCHROMIUM(GLuint program,
                                  GLsizei bufsize,
                                  GLsizei* size,
@@ -853,6 +846,30 @@
                                       const char* name) {
   gles2::GetGLContext()->BindUniformLocationCHROMIUM(program, location, name);
 }
+void GLES2GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) {
+  gles2::GetGLContext()->GenValuebuffersCHROMIUM(n, buffers);
+}
+void GLES2DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) {
+  gles2::GetGLContext()->DeleteValuebuffersCHROMIUM(n, valuebuffers);
+}
+GLboolean GLES2IsValuebufferCHROMIUM(GLuint valuebuffer) {
+  return gles2::GetGLContext()->IsValuebufferCHROMIUM(valuebuffer);
+}
+void GLES2BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) {
+  gles2::GetGLContext()->BindValuebufferCHROMIUM(target, valuebuffer);
+}
+void GLES2SubscribeValueCHROMIUM(GLenum target, GLenum subscription) {
+  gles2::GetGLContext()->SubscribeValueCHROMIUM(target, subscription);
+}
+void GLES2PopulateSubscribedValuesCHROMIUM(GLenum target) {
+  gles2::GetGLContext()->PopulateSubscribedValuesCHROMIUM(target);
+}
+void GLES2UniformValuebufferCHROMIUM(GLint location,
+                                     GLenum target,
+                                     GLenum subscription) {
+  gles2::GetGLContext()->UniformValuebufferCHROMIUM(location, target,
+                                                    subscription);
+}
 void GLES2BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
   gles2::GetGLContext()->BindTexImage2DCHROMIUM(target, imageId);
 }
@@ -1654,10 +1671,6 @@
          glRateLimitOffscreenContextCHROMIUM),
     },
     {
-     "glGetMultipleIntegervCHROMIUM",
-     reinterpret_cast<GLES2FunctionPointer>(glGetMultipleIntegervCHROMIUM),
-    },
-    {
      "glGetProgramInfoCHROMIUM",
      reinterpret_cast<GLES2FunctionPointer>(glGetProgramInfoCHROMIUM),
     },
@@ -1731,6 +1744,34 @@
      reinterpret_cast<GLES2FunctionPointer>(glBindUniformLocationCHROMIUM),
     },
     {
+     "glGenValuebuffersCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glGenValuebuffersCHROMIUM),
+    },
+    {
+     "glDeleteValuebuffersCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glDeleteValuebuffersCHROMIUM),
+    },
+    {
+     "glIsValuebufferCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glIsValuebufferCHROMIUM),
+    },
+    {
+     "glBindValuebufferCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glBindValuebufferCHROMIUM),
+    },
+    {
+     "glSubscribeValueCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glSubscribeValueCHROMIUM),
+    },
+    {
+     "glPopulateSubscribedValuesCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glPopulateSubscribedValuesCHROMIUM),
+    },
+    {
+     "glUniformValuebufferCHROMIUM",
+     reinterpret_cast<GLES2FunctionPointer>(glUniformValuebufferCHROMIUM),
+    },
+    {
      "glBindTexImage2DCHROMIUM",
      reinterpret_cast<GLES2FunctionPointer>(glBindTexImage2DCHROMIUM),
     },
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index 9aeb449..75796a2 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -1538,20 +1538,6 @@
   }
 }
 
-void GetMultipleIntegervCHROMIUM(uint32_t pnames_shm_id,
-                                 uint32_t pnames_shm_offset,
-                                 GLuint count,
-                                 uint32_t results_shm_id,
-                                 uint32_t results_shm_offset,
-                                 GLsizeiptr size) {
-  gles2::cmds::GetMultipleIntegervCHROMIUM* c =
-      GetCmdSpace<gles2::cmds::GetMultipleIntegervCHROMIUM>();
-  if (c) {
-    c->Init(pnames_shm_id, pnames_shm_offset, count, results_shm_id,
-            results_shm_offset, size);
-  }
-}
-
 void GetProgramInfoCHROMIUM(GLuint program, uint32_t bucket_id) {
   gles2::cmds::GetProgramInfoCHROMIUM* c =
       GetCmdSpace<gles2::cmds::GetProgramInfoCHROMIUM>();
@@ -1677,6 +1663,73 @@
   }
 }
 
+void GenValuebuffersCHROMIUMImmediate(GLsizei n, GLuint* buffers) {
+  const uint32_t size =
+      gles2::cmds::GenValuebuffersCHROMIUMImmediate::ComputeSize(n);
+  gles2::cmds::GenValuebuffersCHROMIUMImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          gles2::cmds::GenValuebuffersCHROMIUMImmediate>(size);
+  if (c) {
+    c->Init(n, buffers);
+  }
+}
+
+void DeleteValuebuffersCHROMIUMImmediate(GLsizei n,
+                                         const GLuint* valuebuffers) {
+  const uint32_t size =
+      gles2::cmds::DeleteValuebuffersCHROMIUMImmediate::ComputeSize(n);
+  gles2::cmds::DeleteValuebuffersCHROMIUMImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          gles2::cmds::DeleteValuebuffersCHROMIUMImmediate>(size);
+  if (c) {
+    c->Init(n, valuebuffers);
+  }
+}
+
+void IsValuebufferCHROMIUM(GLuint valuebuffer,
+                           uint32_t result_shm_id,
+                           uint32_t result_shm_offset) {
+  gles2::cmds::IsValuebufferCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::IsValuebufferCHROMIUM>();
+  if (c) {
+    c->Init(valuebuffer, result_shm_id, result_shm_offset);
+  }
+}
+
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) {
+  gles2::cmds::BindValuebufferCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::BindValuebufferCHROMIUM>();
+  if (c) {
+    c->Init(target, valuebuffer);
+  }
+}
+
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) {
+  gles2::cmds::SubscribeValueCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::SubscribeValueCHROMIUM>();
+  if (c) {
+    c->Init(target, subscription);
+  }
+}
+
+void PopulateSubscribedValuesCHROMIUM(GLenum target) {
+  gles2::cmds::PopulateSubscribedValuesCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::PopulateSubscribedValuesCHROMIUM>();
+  if (c) {
+    c->Init(target);
+  }
+}
+
+void UniformValuebufferCHROMIUM(GLint location,
+                                GLenum target,
+                                GLenum subscription) {
+  gles2::cmds::UniformValuebufferCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::UniformValuebufferCHROMIUM>();
+  if (c) {
+    c->Init(location, target, subscription);
+  }
+}
+
 void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
   gles2::cmds::BindTexImage2DCHROMIUM* c =
       GetCmdSpace<gles2::cmds::BindTexImage2DCHROMIUM>();
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 66d8c2b..e7118e8 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -49,21 +49,6 @@
 GLES2Implementation::GLStaticState::~GLStaticState() {
 }
 
-GLES2Implementation::GLStaticState::IntState::IntState()
-    : max_combined_texture_image_units(0),
-      max_cube_map_texture_size(0),
-      max_fragment_uniform_vectors(0),
-      max_renderbuffer_size(0),
-      max_texture_image_units(0),
-      max_texture_size(0),
-      max_varying_vectors(0),
-      max_vertex_attribs(0),
-      max_vertex_texture_image_units(0),
-      max_vertex_uniform_vectors(0),
-      num_compressed_texture_formats(0),
-      num_shader_binary_formats(0),
-      bind_generates_resource_chromium(0) {}
-
 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
     GLES2Implementation* gles2_implementation)
     : gles2_implementation_(gles2_implementation) {
@@ -99,6 +84,7 @@
       bound_framebuffer_(0),
       bound_read_framebuffer_(0),
       bound_renderbuffer_(0),
+      bound_valuebuffer_(0),
       current_program_(0),
       bound_array_buffer_id_(0),
       bound_pixel_pack_transfer_buffer_id_(0),
@@ -173,17 +159,22 @@
   }
   mapped_memory_->set_chunk_size_multiple(chunk_size);
 
-  if (!QueryAndCacheStaticState())
-    return false;
+  GLStaticState::ShaderPrecisionMap* shader_precisions =
+      &static_state_.shader_precisions;
+  capabilities_.VisitPrecisions([shader_precisions](
+      GLenum shader, GLenum type, Capabilities::ShaderPrecision* result) {
+    const GLStaticState::ShaderPrecisionKey key(shader, type);
+    cmds::GetShaderPrecisionFormat::Result cached_result = {
+        true, result->min_range, result->max_range, result->precision};
+    shader_precisions->insert(std::make_pair(key, cached_result));
+  });
 
   util_.set_num_compressed_texture_formats(
-      static_state_.int_state.num_compressed_texture_formats);
-  util_.set_num_shader_binary_formats(
-      static_state_.int_state.num_shader_binary_formats);
+      capabilities_.num_compressed_texture_formats);
+  util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats);
 
   texture_units_.reset(
-      new TextureUnit[
-          static_state_.int_state.max_combined_texture_image_units]);
+      new TextureUnit[capabilities_.max_combined_texture_image_units]);
 
   query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
   buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
@@ -195,14 +186,12 @@
   }
 
   vertex_array_object_manager_.reset(new VertexArrayObjectManager(
-      static_state_.int_state.max_vertex_attribs,
-      reserved_ids_[0],
-      reserved_ids_[1],
+      capabilities_.max_vertex_attribs, reserved_ids_[0], reserved_ids_[1],
       support_client_side_arrays_));
 
   // GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
   // on Client & Service.
-  if (static_state_.int_state.bind_generates_resource_chromium !=
+  if (capabilities_.bind_generates_resource_chromium !=
       (share_group_->bind_generates_resource() ? 1 : 0)) {
     SetGLError(GL_INVALID_OPERATION,
                "Initialize",
@@ -213,80 +202,6 @@
   return true;
 }
 
-bool GLES2Implementation::QueryAndCacheStaticState() {
-  TRACE_EVENT0("gpu", "GLES2Implementation::QueryAndCacheStaticState");
-  // Setup query for multiple GetIntegerv's
-  static const GLenum pnames[] = {
-    GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
-    GL_MAX_CUBE_MAP_TEXTURE_SIZE,
-    GL_MAX_FRAGMENT_UNIFORM_VECTORS,
-    GL_MAX_RENDERBUFFER_SIZE,
-    GL_MAX_TEXTURE_IMAGE_UNITS,
-    GL_MAX_TEXTURE_SIZE,
-    GL_MAX_VARYING_VECTORS,
-    GL_MAX_VERTEX_ATTRIBS,
-    GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
-    GL_MAX_VERTEX_UNIFORM_VECTORS,
-    GL_NUM_COMPRESSED_TEXTURE_FORMATS,
-    GL_NUM_SHADER_BINARY_FORMATS,
-    GL_BIND_GENERATES_RESOURCE_CHROMIUM,
-  };
-
-  GetMultipleIntegervState integerv_state(
-      pnames, arraysize(pnames),
-      &static_state_.int_state.max_combined_texture_image_units,
-      sizeof(static_state_.int_state));
-  if (!GetMultipleIntegervSetup(&integerv_state)) {
-    return false;
-  }
-
-  // Setup query for multiple GetShaderPrecisionFormat's
-  static const GLenum precision_params[][2] = {
-    { GL_VERTEX_SHADER, GL_LOW_INT },
-    { GL_VERTEX_SHADER, GL_MEDIUM_INT },
-    { GL_VERTEX_SHADER, GL_HIGH_INT },
-    { GL_VERTEX_SHADER, GL_LOW_FLOAT },
-    { GL_VERTEX_SHADER, GL_MEDIUM_FLOAT },
-    { GL_VERTEX_SHADER, GL_HIGH_FLOAT },
-    { GL_FRAGMENT_SHADER, GL_LOW_INT },
-    { GL_FRAGMENT_SHADER, GL_MEDIUM_INT },
-    { GL_FRAGMENT_SHADER, GL_HIGH_INT },
-    { GL_FRAGMENT_SHADER, GL_LOW_FLOAT },
-    { GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT },
-    { GL_FRAGMENT_SHADER, GL_HIGH_FLOAT },
-  };
-
-  GetAllShaderPrecisionFormatsState  precision_state(
-      precision_params, arraysize(precision_params));
-  GetAllShaderPrecisionFormatsSetup(&precision_state);
-
-  // Allocate and partition transfer buffer for all requests
-  void* buffer = transfer_buffer_->Alloc(
-      integerv_state.transfer_buffer_size_needed +
-      precision_state.transfer_buffer_size_needed);
-  if (!buffer) {
-    SetGLError(GL_OUT_OF_MEMORY, "QueryAndCacheStaticState",
-               "Transfer buffer allocation failed.");
-    return false;
-  }
-  integerv_state.buffer = buffer;
-  precision_state.results_buffer =
-      static_cast<char*>(buffer) + integerv_state.transfer_buffer_size_needed;
-
-  // Make all the requests and wait once for all the results.
-  GetMultipleIntegervRequest(&integerv_state);
-  GetAllShaderPrecisionFormatsRequest(&precision_state);
-  WaitForCmd();
-  GetMultipleIntegervOnCompleted(&integerv_state);
-  GetAllShaderPrecisionFormatsOnCompleted(&precision_state);
-
-  // TODO(gman): We should be able to free without a token.
-  transfer_buffer_->FreePendingToken(buffer, helper_->InsertToken());
-  CheckGLError();
-
-  return true;
-}
-
 GLES2Implementation::~GLES2Implementation() {
   // Make sure the queries are finished otherwise we'll delete the
   // shared memory (mapped_memory_) which will free the memory used
@@ -683,40 +598,40 @@
 bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
   switch (pname) {
     case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
-      *params = static_state_.int_state.max_combined_texture_image_units;
+      *params = capabilities_.max_combined_texture_image_units;
       return true;
     case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
-      *params = static_state_.int_state.max_cube_map_texture_size;
+      *params = capabilities_.max_cube_map_texture_size;
       return true;
     case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
-      *params = static_state_.int_state.max_fragment_uniform_vectors;
+      *params = capabilities_.max_fragment_uniform_vectors;
       return true;
     case GL_MAX_RENDERBUFFER_SIZE:
-      *params = static_state_.int_state.max_renderbuffer_size;
+      *params = capabilities_.max_renderbuffer_size;
       return true;
     case GL_MAX_TEXTURE_IMAGE_UNITS:
-      *params = static_state_.int_state.max_texture_image_units;
+      *params = capabilities_.max_texture_image_units;
       return true;
     case GL_MAX_TEXTURE_SIZE:
-      *params = static_state_.int_state.max_texture_size;
+      *params = capabilities_.max_texture_size;
       return true;
     case GL_MAX_VARYING_VECTORS:
-      *params = static_state_.int_state.max_varying_vectors;
+      *params = capabilities_.max_varying_vectors;
       return true;
     case GL_MAX_VERTEX_ATTRIBS:
-      *params = static_state_.int_state.max_vertex_attribs;
+      *params = capabilities_.max_vertex_attribs;
       return true;
     case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
-      *params = static_state_.int_state.max_vertex_texture_image_units;
+      *params = capabilities_.max_vertex_texture_image_units;
       return true;
     case GL_MAX_VERTEX_UNIFORM_VECTORS:
-      *params = static_state_.int_state.max_vertex_uniform_vectors;
+      *params = capabilities_.max_vertex_uniform_vectors;
       return true;
     case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
-      *params = static_state_.int_state.num_compressed_texture_formats;
+      *params = capabilities_.num_compressed_texture_formats;
       return true;
     case GL_NUM_SHADER_BINARY_FORMATS:
-      *params = static_state_.int_state.num_shader_binary_formats;
+      *params = capabilities_.num_shader_binary_formats;
       return true;
     case GL_ARRAY_BUFFER_BINDING:
       if (share_group_->bind_generates_resource()) {
@@ -2327,8 +2242,8 @@
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
       << GLES2Util::GetStringEnum(texture) << ")");
   GLuint texture_index = texture - GL_TEXTURE0;
-  if (texture_index >= static_cast<GLuint>(
-      static_state_.int_state.max_combined_texture_image_units)) {
+  if (texture_index >=
+      static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
     SetGLErrorInvalidEnum(
         "glActiveTexture", texture, "texture");
     return;
@@ -2364,6 +2279,11 @@
     GLsizei /* n */, const GLuint* /* queries */) {
 }
 
+void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
+    GLsizei /* n */,
+    const GLuint* /* valuebuffers */) {
+}
+
 // NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
 // generates a new resource. On newer versions of OpenGL they don't. The code
 // related to binding below will need to change if we switch to the new OpenGL
@@ -2513,6 +2433,26 @@
   return changed;
 }
 
+bool GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
+                                                        GLuint valuebuffer) {
+  bool changed = false;
+  switch (target) {
+    case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
+      if (bound_valuebuffer_ != valuebuffer) {
+        bound_valuebuffer_ = valuebuffer;
+        changed = true;
+      }
+      break;
+    default:
+      changed = true;
+      break;
+  }
+  // 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;
+}
+
 bool GLES2Implementation::UseProgramHelper(GLuint program) {
   bool changed = false;
   if (current_program_ != program) {
@@ -2612,8 +2552,7 @@
     return;
   }
   for (GLsizei ii = 0; ii < n; ++ii) {
-    for (GLint tt = 0;
-         tt < static_state_.int_state.max_combined_texture_image_units;
+    for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
          ++tt) {
       TextureUnit& unit = texture_units_[tt];
       if (textures[ii] == unit.bound_texture_2d) {
@@ -2629,6 +2568,11 @@
   }
 }
 
+void GLES2Implementation::DeleteTexturesStub(GLsizei n,
+                                             const GLuint* textures) {
+  helper_->DeleteTexturesImmediate(n, textures);
+}
+
 void GLES2Implementation::DeleteVertexArraysOESHelper(
     GLsizei n, const GLuint* arrays) {
   vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
@@ -2646,9 +2590,27 @@
   helper_->DeleteVertexArraysOESImmediate(n, arrays);
 }
 
-void GLES2Implementation::DeleteTexturesStub(
-    GLsizei n, const GLuint* textures) {
-  helper_->DeleteTexturesImmediate(n, textures);
+void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
+    GLsizei n,
+    const GLuint* valuebuffers) {
+  if (!GetIdHandler(id_namespaces::kValuebuffers)
+           ->FreeIds(this, n, valuebuffers,
+                     &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
+    SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
+               "id not created by this context.");
+    return;
+  }
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    if (valuebuffers[ii] == bound_valuebuffer_) {
+      bound_valuebuffer_ = 0;
+    }
+  }
+}
+
+void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
+    GLsizei n,
+    const GLuint* valuebuffers) {
+  helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
 }
 
 void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
@@ -3034,134 +2996,6 @@
   rate_limit_tokens_.push(helper_->InsertToken());
 }
 
-void GLES2Implementation::GetMultipleIntegervCHROMIUM(
-    const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
-  GPU_CLIENT_SINGLE_THREAD_CHECK();
-  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
-                 << static_cast<const void*>(pnames) << ", "
-                 << count << ", " << results << ", "
-                 << size << ")");
-  GPU_CLIENT_LOG_CODE_BLOCK({
-    for (GLuint i = 0; i < count; ++i) {
-      GPU_CLIENT_LOG(
-          "  " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
-    }
-  });
-  DCHECK(size >= 0 && FitInt32NonNegative<GLsizeiptr>(size));
-
-  GetMultipleIntegervState state(pnames, count, results, size);
-  if (!GetMultipleIntegervSetup(&state)) {
-    return;
-  }
-  state.buffer = transfer_buffer_->Alloc(state.transfer_buffer_size_needed);
-  if (!state.buffer) {
-    SetGLError(GL_OUT_OF_MEMORY, "glGetMultipleIntegervCHROMIUM",
-               "Transfer buffer allocation failed.");
-    return;
-  }
-  GetMultipleIntegervRequest(&state);
-  WaitForCmd();
-  GetMultipleIntegervOnCompleted(&state);
-
-  GPU_CLIENT_LOG("  returned");
-  GPU_CLIENT_LOG_CODE_BLOCK({
-    for (int i = 0; i < state.num_results; ++i) {
-      GPU_CLIENT_LOG("  " << i << ": " << (results[i]));
-    }
-  });
-
-  // TODO(gman): We should be able to free without a token.
-  transfer_buffer_->FreePendingToken(state.buffer, helper_->InsertToken());
-  CheckGLError();
-}
-
-bool GLES2Implementation::GetMultipleIntegervSetup(
-    GetMultipleIntegervState* state) {
-  state->num_results = 0;
-  for (GLuint ii = 0; ii < state->pnames_count; ++ii) {
-    int num = util_.GLGetNumValuesReturned(state->pnames[ii]);
-    if (!num) {
-      SetGLErrorInvalidEnum(
-          "glGetMultipleIntegervCHROMIUM", state->pnames[ii], "pname");
-      return false;
-    }
-    state->num_results += num;
-  }
-  if (static_cast<size_t>(state->results_size) !=
-      state->num_results * sizeof(GLint)) {
-    SetGLError(GL_INVALID_VALUE, "glGetMultipleIntegervCHROMIUM", "bad size");
-    return false;
-  }
-  for (int ii = 0; ii < state->num_results; ++ii) {
-    if (state->results[ii] != 0) {
-      SetGLError(GL_INVALID_VALUE,
-                 "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
-      return false;
-    }
-  }
-  state->transfer_buffer_size_needed =
-      state->pnames_count * sizeof(state->pnames[0]) +
-      state->num_results * sizeof(state->results[0]);
-  return true;
-}
-
-void GLES2Implementation::GetMultipleIntegervRequest(
-    GetMultipleIntegervState* state) {
-  GLenum* pnames_buffer = static_cast<GLenum*>(state->buffer);
-  state->results_buffer = pnames_buffer + state->pnames_count;
-  memcpy(pnames_buffer, state->pnames, state->pnames_count * sizeof(GLenum));
-  memset(state->results_buffer, 0, state->num_results * sizeof(GLint));
-  helper_->GetMultipleIntegervCHROMIUM(
-      transfer_buffer_->GetShmId(),
-      transfer_buffer_->GetOffset(pnames_buffer),
-      state->pnames_count,
-      transfer_buffer_->GetShmId(),
-      transfer_buffer_->GetOffset(state->results_buffer),
-      state->results_size);
-}
-
-void GLES2Implementation::GetMultipleIntegervOnCompleted(
-    GetMultipleIntegervState* state) {
-  memcpy(state->results, state->results_buffer, state->results_size);;
-}
-
-void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
-    GetAllShaderPrecisionFormatsState* state) {
-  state->transfer_buffer_size_needed =
-      state->precision_params_count *
-      sizeof(cmds::GetShaderPrecisionFormat::Result);
-}
-
-void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
-    GetAllShaderPrecisionFormatsState* state) {
-  typedef cmds::GetShaderPrecisionFormat::Result Result;
-  Result* result = static_cast<Result*>(state->results_buffer);
-
-  for (int i = 0; i < state->precision_params_count; i++) {
-    result->success = false;
-    helper_->GetShaderPrecisionFormat(state->precision_params[i][0],
-                                      state->precision_params[i][1],
-                                      transfer_buffer_->GetShmId(),
-                                      transfer_buffer_->GetOffset(result));
-    result++;
-  }
-}
-
-void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
-    GetAllShaderPrecisionFormatsState* state) {
-  typedef cmds::GetShaderPrecisionFormat::Result Result;
-  Result* result = static_cast<Result*>(state->results_buffer);
-
-  for (int i = 0; i < state->precision_params_count; i++) {
-    if (result->success) {
-      const GLStaticState::ShaderPrecisionKey key(
-        state->precision_params[i][0], state->precision_params[i][1]);
-      static_state_.shader_precisions[key] = *result;
-    }
-    result++;
-  }
-}
-
 void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
     GLuint program, std::vector<int8>* result) {
   DCHECK(result);
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index a612ac2..cfe8ed9 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -137,24 +137,6 @@
     GLStaticState();
     ~GLStaticState();
 
-    struct GLES2_IMPL_EXPORT IntState {
-      IntState();
-      GLint max_combined_texture_image_units;
-      GLint max_cube_map_texture_size;
-      GLint max_fragment_uniform_vectors;
-      GLint max_renderbuffer_size;
-      GLint max_texture_image_units;
-      GLint max_texture_size;
-      GLint max_varying_vectors;
-      GLint max_vertex_attribs;
-      GLint max_vertex_texture_image_units;
-      GLint max_vertex_uniform_vectors;
-      GLint num_compressed_texture_formats;
-      GLint num_shader_binary_formats;
-      GLint bind_generates_resource_chromium;
-    };
-    IntState int_state;
-
     typedef std::pair<GLenum, GLenum> ShaderPrecisionKey;
     typedef std::map<ShaderPrecisionKey,
                      cmds::GetShaderPrecisionFormat::Result>
@@ -398,58 +380,6 @@
   int32 GetResultShmId();
   uint32 GetResultShmOffset();
 
-  bool QueryAndCacheStaticState();
-
-  // Helpers used to batch synchronous GetIntergerv calls with other
-  // synchronous calls.
-  struct GetMultipleIntegervState {
-    GetMultipleIntegervState(const GLenum* pnames, GLuint pnames_count,
-                             GLint* results, GLsizeiptr results_size)
-       : pnames(pnames),
-         pnames_count(pnames_count),
-         results(results),
-         results_size(results_size)
-    { }
-    // inputs
-    const GLenum* pnames;
-    GLuint pnames_count;
-    // outputs
-    GLint* results;
-    GLsizeiptr results_size;
-    // transfer buffer
-    int num_results;
-    int transfer_buffer_size_needed;
-    void* buffer;
-    void* results_buffer;
-  };
-  bool GetMultipleIntegervSetup(
-      GetMultipleIntegervState* state);
-  void GetMultipleIntegervRequest(
-      GetMultipleIntegervState* state);
-  void GetMultipleIntegervOnCompleted(
-      GetMultipleIntegervState* state);
-
-  // Helpers used to batch synchronous GetShaderPrecision calls with other
-  // synchronous calls.
-  struct GetAllShaderPrecisionFormatsState {
-    GetAllShaderPrecisionFormatsState(
-        const GLenum (*precision_params)[2],
-        int precision_params_count)
-        : precision_params(precision_params),
-          precision_params_count(precision_params_count)
-    { }
-    const GLenum (*precision_params)[2];
-    int precision_params_count;
-    int transfer_buffer_size_needed;
-    void* results_buffer;
-  };
-  void GetAllShaderPrecisionFormatsSetup(
-      GetAllShaderPrecisionFormatsState* state);
-  void GetAllShaderPrecisionFormatsRequest(
-      GetAllShaderPrecisionFormatsState* state);
-  void GetAllShaderPrecisionFormatsOnCompleted(
-      GetAllShaderPrecisionFormatsState* state);
-
   // Lazily determines if GL_ANGLE_pack_reverse_row_order is available
   bool IsAnglePackReverseRowOrderAvailable();
   bool IsChromiumFramebufferMultisampleAvailable();
@@ -495,17 +425,19 @@
 
   // Returns true if id is reserved.
   bool IsBufferReservedId(GLuint id);
-  bool IsFramebufferReservedId(GLuint id) { return false;  }
+  bool IsFramebufferReservedId(GLuint id) { return false; }
   bool IsRenderbufferReservedId(GLuint id) { return false; }
   bool IsTextureReservedId(GLuint id) { return false; }
   bool IsVertexArrayReservedId(GLuint id) { return false; }
   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 GenBuffersHelper(GLsizei n, const GLuint* buffers);
@@ -514,6 +446,7 @@
   void GenTexturesHelper(GLsizei n, const GLuint* textures);
   void GenVertexArraysOESHelper(GLsizei n, const GLuint* arrays);
   void GenQueriesEXTHelper(GLsizei n, const GLuint* queries);
+  void GenValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* valuebuffers);
 
   void DeleteBuffersHelper(GLsizei n, const GLuint* buffers);
   void DeleteFramebuffersHelper(GLsizei n, const GLuint* framebuffers);
@@ -523,6 +456,7 @@
   bool DeleteShaderHelper(GLuint shader);
   void DeleteQueriesEXTHelper(GLsizei n, const GLuint* queries);
   void DeleteVertexArraysOESHelper(GLsizei n, const GLuint* arrays);
+  void DeleteValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* valuebuffers);
 
   void DeleteBuffersStub(GLsizei n, const GLuint* buffers);
   void DeleteFramebuffersStub(GLsizei n, const GLuint* framebuffers);
@@ -531,6 +465,7 @@
   void DeleteProgramStub(GLsizei n, const GLuint* programs);
   void DeleteShaderStub(GLsizei n, const GLuint* shaders);
   void DeleteVertexArraysOESStub(GLsizei n, const GLuint* arrays);
+  void DeleteValuebuffersCHROMIUMStub(GLsizei n, const GLuint* valuebuffers);
 
   void BufferDataHelper(
       GLenum target, GLsizeiptr size, const void* data, GLenum usage);
@@ -699,6 +634,7 @@
   GLuint bound_framebuffer_;
   GLuint bound_read_framebuffer_;
   GLuint bound_renderbuffer_;
+  GLuint bound_valuebuffer_;
 
   // The program in use by glUseProgram
   GLuint current_program_;
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 4e547d9..f58c0a8 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -552,11 +552,6 @@
 
 void RateLimitOffscreenContextCHROMIUM() override;
 
-void GetMultipleIntegervCHROMIUM(const GLenum* pnames,
-                                 GLuint count,
-                                 GLint* results,
-                                 GLsizeiptr size) override;
-
 void GetProgramInfoCHROMIUM(GLuint program,
                             GLsizei bufsize,
                             GLsizei* size,
@@ -629,6 +624,22 @@
                                  GLint location,
                                  const char* name) override;
 
+void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) override;
+
+void DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) override;
+
+GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) override;
+
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) override;
+
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) override;
+
+void PopulateSubscribedValuesCHROMIUM(GLenum target) override;
+
+void UniformValuebufferCHROMIUM(GLint location,
+                                GLenum target,
+                                GLenum subscription) override;
+
 void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
 
 void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index e7cc074..8541e77 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -2019,6 +2019,120 @@
   CheckGLError();
 }
 
+void GLES2Implementation::GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) {
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenValuebuffersCHROMIUM(" << n
+                     << ", " << static_cast<const void*>(buffers) << ")");
+  if (n < 0) {
+    SetGLError(GL_INVALID_VALUE, "glGenValuebuffersCHROMIUM", "n < 0");
+    return;
+  }
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GetIdHandler(id_namespaces::kValuebuffers)->MakeIds(this, 0, n, buffers);
+  GenValuebuffersCHROMIUMHelper(n, buffers);
+  helper_->GenValuebuffersCHROMIUMImmediate(n, buffers);
+  if (share_group_->bind_generates_resource())
+    helper_->CommandBufferHelper::Flush();
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (GLsizei i = 0; i < n; ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << buffers[i]);
+    }
+  });
+  CheckGLError();
+}
+
+void GLES2Implementation::DeleteValuebuffersCHROMIUM(
+    GLsizei n,
+    const GLuint* valuebuffers) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteValuebuffersCHROMIUM(" << n
+                     << ", " << static_cast<const void*>(valuebuffers) << ")");
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (GLsizei i = 0; i < n; ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << valuebuffers[i]);
+    }
+  });
+  GPU_CLIENT_DCHECK_CODE_BLOCK({
+    for (GLsizei i = 0; i < n; ++i) {
+      DCHECK(valuebuffers[i] != 0);
+    }
+  });
+  if (n < 0) {
+    SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM", "n < 0");
+    return;
+  }
+  DeleteValuebuffersCHROMIUMHelper(n, valuebuffers);
+  CheckGLError();
+}
+
+GLboolean GLES2Implementation::IsValuebufferCHROMIUM(GLuint valuebuffer) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  TRACE_EVENT0("gpu", "GLES2Implementation::IsValuebufferCHROMIUM");
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsValuebufferCHROMIUM("
+                     << valuebuffer << ")");
+  typedef cmds::IsValuebufferCHROMIUM::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return GL_FALSE;
+  }
+  *result = 0;
+  helper_->IsValuebufferCHROMIUM(valuebuffer, GetResultShmId(),
+                                 GetResultShmOffset());
+  WaitForCmd();
+  GLboolean result_value = *result != 0;
+  GPU_CLIENT_LOG("returned " << result_value);
+  CheckGLError();
+  return result_value;
+}
+
+void GLES2Implementation::BindValuebufferCHROMIUM(GLenum target,
+                                                  GLuint valuebuffer) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindValuebufferCHROMIUM("
+                     << GLES2Util::GetStringValueBufferTarget(target) << ", "
+                     << valuebuffer << ")");
+  if (IsValuebufferReservedId(valuebuffer)) {
+    SetGLError(GL_INVALID_OPERATION, "BindValuebufferCHROMIUM",
+               "valuebuffer reserved id");
+    return;
+  }
+  if (BindValuebufferCHROMIUMHelper(target, valuebuffer)) {
+    helper_->BindValuebufferCHROMIUM(target, valuebuffer);
+  }
+  CheckGLError();
+}
+
+void GLES2Implementation::SubscribeValueCHROMIUM(GLenum target,
+                                                 GLenum subscription) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSubscribeValueCHROMIUM("
+                     << GLES2Util::GetStringValueBufferTarget(target) << ", "
+                     << GLES2Util::GetStringSubscriptionTarget(subscription)
+                     << ")");
+  helper_->SubscribeValueCHROMIUM(target, subscription);
+  CheckGLError();
+}
+
+void GLES2Implementation::PopulateSubscribedValuesCHROMIUM(GLenum target) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix()
+                     << "] glPopulateSubscribedValuesCHROMIUM("
+                     << GLES2Util::GetStringValueBufferTarget(target) << ")");
+  helper_->PopulateSubscribedValuesCHROMIUM(target);
+  CheckGLError();
+}
+
+void GLES2Implementation::UniformValuebufferCHROMIUM(GLint location,
+                                                     GLenum target,
+                                                     GLenum subscription) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG(
+      "[" << GetLogPrefix() << "] glUniformValuebufferCHROMIUM(" << location
+          << ", " << GLES2Util::GetStringValueBufferTarget(target) << ", "
+          << GLES2Util::GetStringSubscriptionTarget(subscription) << ")");
+  helper_->UniformValuebufferCHROMIUM(location, target, subscription);
+  CheckGLError();
+}
+
 void GLES2Implementation::BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindTexImage2DCHROMIUM("
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index be1f1a3..5c944a8 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -383,6 +383,7 @@
   static const GLuint kTexturesStartId = 1;
   static const GLuint kQueriesStartId = 1;
   static const GLuint kVertexArraysStartId = 1;
+  static const GLuint kValuebuffersStartId = 1;
 
   typedef MockTransferBuffer::ExpectedMemoryInfo ExpectedMemoryInfo;
 
@@ -408,43 +409,36 @@
       helper_->Initialize(kCommandBufferSizeBytes);
 
       gpu_control_.reset(new StrictMock<MockClientGpuControl>());
-      EXPECT_CALL(*gpu_control_, GetCapabilities())
-          .WillOnce(testing::Return(Capabilities()));
-
-      GLES2Implementation::GLStaticState state;
-      GLES2Implementation::GLStaticState::IntState& int_state = state.int_state;
-      int_state.max_combined_texture_image_units =
+      Capabilities capabilities;
+      capabilities.VisitPrecisions(
+          [](GLenum shader, GLenum type,
+             Capabilities::ShaderPrecision* precision) {
+            precision->min_range = 3;
+            precision->max_range = 5;
+            precision->precision = 7;
+          });
+      capabilities.max_combined_texture_image_units =
           kMaxCombinedTextureImageUnits;
-      int_state.max_cube_map_texture_size = kMaxCubeMapTextureSize;
-      int_state.max_fragment_uniform_vectors = kMaxFragmentUniformVectors;
-      int_state.max_renderbuffer_size = kMaxRenderbufferSize;
-      int_state.max_texture_image_units = kMaxTextureImageUnits;
-      int_state.max_texture_size = kMaxTextureSize;
-      int_state.max_varying_vectors = kMaxVaryingVectors;
-      int_state.max_vertex_attribs = kMaxVertexAttribs;
-      int_state.max_vertex_texture_image_units = kMaxVertexTextureImageUnits;
-      int_state.max_vertex_uniform_vectors = kMaxVertexUniformVectors;
-      int_state.num_compressed_texture_formats = kNumCompressedTextureFormats;
-      int_state.num_shader_binary_formats = kNumShaderBinaryFormats;
-      int_state.bind_generates_resource_chromium =
+      capabilities.max_cube_map_texture_size = kMaxCubeMapTextureSize;
+      capabilities.max_fragment_uniform_vectors = kMaxFragmentUniformVectors;
+      capabilities.max_renderbuffer_size = kMaxRenderbufferSize;
+      capabilities.max_texture_image_units = kMaxTextureImageUnits;
+      capabilities.max_texture_size = kMaxTextureSize;
+      capabilities.max_varying_vectors = kMaxVaryingVectors;
+      capabilities.max_vertex_attribs = kMaxVertexAttribs;
+      capabilities.max_vertex_texture_image_units = kMaxVertexTextureImageUnits;
+      capabilities.max_vertex_uniform_vectors = kMaxVertexUniformVectors;
+      capabilities.num_compressed_texture_formats =
+          kNumCompressedTextureFormats;
+      capabilities.num_shader_binary_formats = kNumShaderBinaryFormats;
+      capabilities.bind_generates_resource_chromium =
           bind_generates_resource_service ? 1 : 0;
-
-      // This just happens to work for now because IntState has 1 GLint per
-      // state.
-      // If IntState gets more complicated this code will need to get more
-      // complicated.
-      ExpectedMemoryInfo mem1 = transfer_buffer_->GetExpectedMemory(
-          sizeof(GLES2Implementation::GLStaticState::IntState) * 2 +
-          sizeof(cmds::GetShaderPrecisionFormat::Result) * 12);
+      EXPECT_CALL(*gpu_control_, GetCapabilities())
+          .WillOnce(testing::Return(capabilities));
 
       {
         InSequence sequence;
 
-        EXPECT_CALL(*command_buffer_, OnFlush())
-            .WillOnce(SetMemory(mem1.ptr + sizeof(int_state), int_state))
-            .RetiresOnSaturation();
-        GetNextToken();  // eat the token that starting up will use.
-
         const bool support_client_side_arrays = true;
         gl_.reset(new GLES2Implementation(helper_.get(),
                                           share_group,
@@ -461,7 +455,6 @@
           return false;
       }
 
-      EXPECT_CALL(*command_buffer_, OnFlush()).Times(1).RetiresOnSaturation();
       helper_->CommandBufferHelper::Finish();
       ::testing::Mock::VerifyAndClearExpectations(gl_.get());
 
@@ -755,6 +748,7 @@
 const GLuint GLES2ImplementationTest::kTexturesStartId;
 const GLuint GLES2ImplementationTest::kQueriesStartId;
 const GLuint GLES2ImplementationTest::kVertexArraysStartId;
+const GLuint GLES2ImplementationTest::kValuebuffersStartId;
 #endif
 
 TEST_F(GLES2ImplementationTest, Basic) {
@@ -817,20 +811,22 @@
     cmds::GetShaderPrecisionFormat cmd;
   };
   typedef cmds::GetShaderPrecisionFormat::Result Result;
+  const unsigned kDummyType1 = 3;
+  const unsigned kDummyType2 = 4;
 
-  // The first call for mediump should trigger a command buffer request.
+  // The first call for dummy type 1 should trigger a command buffer request.
   GLint range1[2] = {0, 0};
   GLint precision1 = 0;
   Cmds expected1;
   ExpectedMemoryInfo client_result1 = GetExpectedResultMemory(4);
-  expected1.cmd.Init(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
-                     client_result1.id, client_result1.offset);
+  expected1.cmd.Init(GL_FRAGMENT_SHADER, kDummyType1, client_result1.id,
+                     client_result1.offset);
   Result server_result1 = {true, 14, 14, 10};
   EXPECT_CALL(*command_buffer(), OnFlush())
       .WillOnce(SetMemory(client_result1.ptr, server_result1))
       .RetiresOnSaturation();
-  gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
-                                range1, &precision1);
+  gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, kDummyType1, range1,
+                                &precision1);
   const void* commands2 = GetPut();
   EXPECT_NE(commands_, commands2);
   EXPECT_EQ(0, memcmp(&expected1, commands_, sizeof(expected1)));
@@ -838,39 +834,53 @@
   EXPECT_EQ(range1[1], 14);
   EXPECT_EQ(precision1, 10);
 
-  // The second call for mediump should use the cached value and avoid
+  // The second call for dummy type 1 should use the cached value and avoid
   // triggering a command buffer request, so we do not expect a call to
   // OnFlush() here. We do expect the results to be correct though.
   GLint range2[2] = {0, 0};
   GLint precision2 = 0;
-  gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
-                                range2, &precision2);
+  gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, kDummyType1, range2,
+                                &precision2);
   const void* commands3 = GetPut();
   EXPECT_EQ(commands2, commands3);
   EXPECT_EQ(range2[0], 14);
   EXPECT_EQ(range2[1], 14);
   EXPECT_EQ(precision2, 10);
 
-  // If we then make a request for highp, we should get another command
+  // If we then make a request for dummy type 2, we should get another command
   // buffer request since it hasn't been cached yet.
   GLint range3[2] = {0, 0};
   GLint precision3 = 0;
   Cmds expected3;
   ExpectedMemoryInfo result3 = GetExpectedResultMemory(4);
-  expected3.cmd.Init(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT,
-                     result3.id, result3.offset);
+  expected3.cmd.Init(GL_FRAGMENT_SHADER, kDummyType2, result3.id,
+                     result3.offset);
   Result result3_source = {true, 62, 62, 16};
   EXPECT_CALL(*command_buffer(), OnFlush())
       .WillOnce(SetMemory(result3.ptr, result3_source))
       .RetiresOnSaturation();
-  gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT,
-                                range3, &precision3);
+  gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, kDummyType2, range3,
+                                &precision3);
   const void* commands4 = GetPut();
   EXPECT_NE(commands3, commands4);
   EXPECT_EQ(0, memcmp(&expected3, commands3, sizeof(expected3)));
   EXPECT_EQ(range3[0], 62);
   EXPECT_EQ(range3[1], 62);
   EXPECT_EQ(precision3, 16);
+
+  // Any call for predefined types should use the cached value from the
+  // Capabilities  and avoid triggering a command buffer request, so we do not
+  // expect a call to OnFlush() here. We do expect the results to be correct
+  // though.
+  GLint range4[2] = {0, 0};
+  GLint precision4 = 0;
+  gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, range4,
+                                &precision4);
+  const void* commands5 = GetPut();
+  EXPECT_EQ(commands4, commands5);
+  EXPECT_EQ(range4[0], 3);
+  EXPECT_EQ(range4[1], 5);
+  EXPECT_EQ(precision4, 7);
 }
 
 TEST_F(GLES2ImplementationTest, ShaderSource) {
@@ -1947,122 +1957,6 @@
   EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
 }
 
-TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMValidArgs) {
-  const GLenum pnames[] = {
-    GL_DEPTH_WRITEMASK,
-    GL_COLOR_WRITEMASK,
-    GL_STENCIL_WRITEMASK,
-  };
-  const GLint num_results = 6;
-  GLint results[num_results + 1];
-  struct Cmds {
-    cmds::GetMultipleIntegervCHROMIUM get_multiple;
-    cmd::SetToken set_token;
-  };
-  const GLsizei kNumPnames = arraysize(pnames);
-  const GLsizeiptr kResultsSize = num_results * sizeof(results[0]);
-  const size_t kPNamesSize = kNumPnames * sizeof(pnames[0]);
-
-  ExpectedMemoryInfo mem1 = GetExpectedMemory(kPNamesSize + kResultsSize);
-  ExpectedMemoryInfo result1 = GetExpectedResultMemory(
-      sizeof(cmds::GetError::Result));
-
-  const uint32 kPnamesOffset = mem1.offset;
-  const uint32 kResultsOffset = mem1.offset + kPNamesSize;
-  Cmds expected;
-  expected.get_multiple.Init(
-      mem1.id, kPnamesOffset, kNumPnames,
-      mem1.id, kResultsOffset, kResultsSize);
-  expected.set_token.Init(GetNextToken());
-
-  const GLint kSentinel = 0x12345678;
-  memset(results, 0, sizeof(results));
-  results[num_results] = kSentinel;
-  const GLint returned_results[] = {
-    1, 0, 1, 0, 1, -1,
-  };
-  // One call to flush to wait for results
-  EXPECT_CALL(*command_buffer(), OnFlush())
-      .WillOnce(SetMemoryFromArray(mem1.ptr + kPNamesSize,
-                                   returned_results, sizeof(returned_results)))
-      .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
-      .RetiresOnSaturation();
-
-  gl_->GetMultipleIntegervCHROMIUM(
-      &pnames[0], kNumPnames, &results[0], kResultsSize);
-  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
-  EXPECT_EQ(0, memcmp(&returned_results, results, sizeof(returned_results)));
-  EXPECT_EQ(kSentinel, results[num_results]);
-  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
-}
-
-TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMBadArgs) {
-  GLenum pnames[] = {
-    GL_DEPTH_WRITEMASK,
-    GL_COLOR_WRITEMASK,
-    GL_STENCIL_WRITEMASK,
-  };
-  const GLint num_results = 6;
-  GLint results[num_results + 1];
-  const GLsizei kNumPnames = arraysize(pnames);
-  const GLsizeiptr kResultsSize = num_results * sizeof(results[0]);
-
-  ExpectedMemoryInfo result1 =
-      GetExpectedResultMemory(sizeof(cmds::GetError::Result));
-  ExpectedMemoryInfo result2 =
-      GetExpectedResultMemory(sizeof(cmds::GetError::Result));
-  ExpectedMemoryInfo result3 =
-      GetExpectedResultMemory(sizeof(cmds::GetError::Result));
-  ExpectedMemoryInfo result4 =
-      GetExpectedResultMemory(sizeof(cmds::GetError::Result));
-
-  // Calls to flush to wait for GetError
-  EXPECT_CALL(*command_buffer(), OnFlush())
-      .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
-      .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
-      .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR)))
-      .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR)))
-      .RetiresOnSaturation();
-
-  const GLint kSentinel = 0x12345678;
-  memset(results, 0, sizeof(results));
-  results[num_results] = kSentinel;
-  // try bad size.
-  gl_->GetMultipleIntegervCHROMIUM(
-      &pnames[0], kNumPnames, &results[0], kResultsSize + 1);
-  EXPECT_TRUE(NoCommandsWritten());
-  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
-  EXPECT_EQ(0, results[0]);
-  EXPECT_EQ(kSentinel, results[num_results]);
-  // try bad size.
-  ClearCommands();
-  gl_->GetMultipleIntegervCHROMIUM(
-      &pnames[0], kNumPnames, &results[0], kResultsSize - 1);
-  EXPECT_TRUE(NoCommandsWritten());
-  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
-  EXPECT_EQ(0, results[0]);
-  EXPECT_EQ(kSentinel, results[num_results]);
-  // try uncleared results.
-  ClearCommands();
-  results[2] = 1;
-  gl_->GetMultipleIntegervCHROMIUM(
-      &pnames[0], kNumPnames, &results[0], kResultsSize);
-  EXPECT_TRUE(NoCommandsWritten());
-  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
-  EXPECT_EQ(0, results[0]);
-  EXPECT_EQ(kSentinel, results[num_results]);
-  // try bad enum results.
-  ClearCommands();
-  results[2] = 0;
-  pnames[1] = GL_TRUE;
-  gl_->GetMultipleIntegervCHROMIUM(
-      &pnames[0], kNumPnames, &results[0], kResultsSize);
-  EXPECT_TRUE(NoCommandsWritten());
-  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), gl_->GetError());
-  EXPECT_EQ(0, results[0]);
-  EXPECT_EQ(kSentinel, results[num_results]);
-}
-
 TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMGoodArgs) {
   const uint32 kBucketId = GLES2Implementation::kResultBucketId;
   const GLuint kProgramId = 123;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index 8069b12..74a438c 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -1800,6 +1800,108 @@
 // TODO: Implement unit test for GenMailboxCHROMIUM
 // TODO: Implement unit test for BindUniformLocationCHROMIUM
 
+TEST_F(GLES2ImplementationTest, GenValuebuffersCHROMIUM) {
+  GLuint ids[2] = {
+      0,
+  };
+  struct Cmds {
+    cmds::GenValuebuffersCHROMIUMImmediate gen;
+    GLuint data[2];
+  };
+  Cmds expected;
+  expected.gen.Init(arraysize(ids), &ids[0]);
+  expected.data[0] = kValuebuffersStartId;
+  expected.data[1] = kValuebuffersStartId + 1;
+  gl_->GenValuebuffersCHROMIUM(arraysize(ids), &ids[0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_EQ(kValuebuffersStartId, ids[0]);
+  EXPECT_EQ(kValuebuffersStartId + 1, ids[1]);
+}
+
+TEST_F(GLES2ImplementationTest, DeleteValuebuffersCHROMIUM) {
+  GLuint ids[2] = {kValuebuffersStartId, kValuebuffersStartId + 1};
+  struct Cmds {
+    cmds::DeleteValuebuffersCHROMIUMImmediate del;
+    GLuint data[2];
+  };
+  Cmds expected;
+  expected.del.Init(arraysize(ids), &ids[0]);
+  expected.data[0] = kValuebuffersStartId;
+  expected.data[1] = kValuebuffersStartId + 1;
+  gl_->DeleteValuebuffersCHROMIUM(arraysize(ids), &ids[0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, IsValuebufferCHROMIUM) {
+  struct Cmds {
+    cmds::IsValuebufferCHROMIUM cmd;
+  };
+
+  Cmds expected;
+  ExpectedMemoryInfo result1 =
+      GetExpectedResultMemory(sizeof(cmds::IsValuebufferCHROMIUM::Result));
+  expected.cmd.Init(1, result1.id, result1.offset);
+
+  EXPECT_CALL(*command_buffer(), OnFlush())
+      .WillOnce(SetMemory(result1.ptr, uint32_t(1)))
+      .RetiresOnSaturation();
+
+  GLboolean result = gl_->IsValuebufferCHROMIUM(1);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, BindValuebufferCHROMIUM) {
+  struct Cmds {
+    cmds::BindValuebufferCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 2);
+
+  gl_->BindValuebufferCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 2);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  ClearCommands();
+  gl_->BindValuebufferCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 2);
+  EXPECT_TRUE(NoCommandsWritten());
+}
+
+TEST_F(GLES2ImplementationTest, SubscribeValueCHROMIUM) {
+  struct Cmds {
+    cmds::SubscribeValueCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+                    GL_MOUSE_POSITION_CHROMIUM);
+
+  gl_->SubscribeValueCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+                              GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, PopulateSubscribedValuesCHROMIUM) {
+  struct Cmds {
+    cmds::PopulateSubscribedValuesCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+
+  gl_->PopulateSubscribedValuesCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, UniformValuebufferCHROMIUM) {
+  struct Cmds {
+    cmds::UniformValuebufferCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(1, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+                    GL_MOUSE_POSITION_CHROMIUM);
+
+  gl_->UniformValuebufferCHROMIUM(1, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+                                  GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, BindTexImage2DCHROMIUM) {
   struct Cmds {
     cmds::BindTexImage2DCHROMIUM cmd;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index d840804..ee4591c 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -392,10 +392,6 @@
 virtual const GLchar* GetRequestableExtensionsCHROMIUM() = 0;
 virtual void RequestExtensionCHROMIUM(const char* extension) = 0;
 virtual void RateLimitOffscreenContextCHROMIUM() = 0;
-virtual void GetMultipleIntegervCHROMIUM(const GLenum* pnames,
-                                         GLuint count,
-                                         GLint* results,
-                                         GLsizeiptr size) = 0;
 virtual void GetProgramInfoCHROMIUM(GLuint program,
                                     GLsizei bufsize,
                                     GLsizei* size,
@@ -450,6 +446,16 @@
 virtual void BindUniformLocationCHROMIUM(GLuint program,
                                          GLint location,
                                          const char* name) = 0;
+virtual void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) = 0;
+virtual void DeleteValuebuffersCHROMIUM(GLsizei n,
+                                        const GLuint* valuebuffers) = 0;
+virtual GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) = 0;
+virtual void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) = 0;
+virtual void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) = 0;
+virtual void PopulateSubscribedValuesCHROMIUM(GLenum target) = 0;
+virtual void UniformValuebufferCHROMIUM(GLint location,
+                                        GLenum target,
+                                        GLenum subscription) = 0;
 virtual void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) = 0;
 virtual void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) = 0;
 virtual void TraceBeginCHROMIUM(const char* name) = 0;
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 687ff48..637c000 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -383,10 +383,6 @@
 const GLchar* GetRequestableExtensionsCHROMIUM() override;
 void RequestExtensionCHROMIUM(const char* extension) override;
 void RateLimitOffscreenContextCHROMIUM() override;
-void GetMultipleIntegervCHROMIUM(const GLenum* pnames,
-                                 GLuint count,
-                                 GLint* results,
-                                 GLsizeiptr size) override;
 void GetProgramInfoCHROMIUM(GLuint program,
                             GLsizei bufsize,
                             GLsizei* size,
@@ -441,6 +437,15 @@
 void BindUniformLocationCHROMIUM(GLuint program,
                                  GLint location,
                                  const char* name) override;
+void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) override;
+void DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) override;
+GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) override;
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) override;
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) override;
+void PopulateSubscribedValuesCHROMIUM(GLenum target) override;
+void UniformValuebufferCHROMIUM(GLint location,
+                                GLenum target,
+                                GLenum subscription) override;
 void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
 void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
 void TraceBeginCHROMIUM(const char* name) override;
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 e78b07c..5a986e9 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -694,11 +694,6 @@
 }
 void GLES2InterfaceStub::RateLimitOffscreenContextCHROMIUM() {
 }
-void GLES2InterfaceStub::GetMultipleIntegervCHROMIUM(const GLenum* /* pnames */,
-                                                     GLuint /* count */,
-                                                     GLint* /* results */,
-                                                     GLsizeiptr /* size */) {
-}
 void GLES2InterfaceStub::GetProgramInfoCHROMIUM(GLuint /* program */,
                                                 GLsizei /* bufsize */,
                                                 GLsizei* /* size */,
@@ -781,6 +776,28 @@
                                                      GLint /* location */,
                                                      const char* /* name */) {
 }
+void GLES2InterfaceStub::GenValuebuffersCHROMIUM(GLsizei /* n */,
+                                                 GLuint* /* buffers */) {
+}
+void GLES2InterfaceStub::DeleteValuebuffersCHROMIUM(
+    GLsizei /* n */,
+    const GLuint* /* valuebuffers */) {
+}
+GLboolean GLES2InterfaceStub::IsValuebufferCHROMIUM(GLuint /* valuebuffer */) {
+  return 0;
+}
+void GLES2InterfaceStub::BindValuebufferCHROMIUM(GLenum /* target */,
+                                                 GLuint /* valuebuffer */) {
+}
+void GLES2InterfaceStub::SubscribeValueCHROMIUM(GLenum /* target */,
+                                                GLenum /* subscription */) {
+}
+void GLES2InterfaceStub::PopulateSubscribedValuesCHROMIUM(GLenum /* target */) {
+}
+void GLES2InterfaceStub::UniformValuebufferCHROMIUM(GLint /* location */,
+                                                    GLenum /* target */,
+                                                    GLenum /* subscription */) {
+}
 void GLES2InterfaceStub::BindTexImage2DCHROMIUM(GLenum /* target */,
                                                 GLint /* imageId */) {
 }
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index a599eb4..b4349ae 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -383,10 +383,6 @@
 const GLchar* GetRequestableExtensionsCHROMIUM() override;
 void RequestExtensionCHROMIUM(const char* extension) override;
 void RateLimitOffscreenContextCHROMIUM() override;
-void GetMultipleIntegervCHROMIUM(const GLenum* pnames,
-                                 GLuint count,
-                                 GLint* results,
-                                 GLsizeiptr size) override;
 void GetProgramInfoCHROMIUM(GLuint program,
                             GLsizei bufsize,
                             GLsizei* size,
@@ -441,6 +437,15 @@
 void BindUniformLocationCHROMIUM(GLuint program,
                                  GLint location,
                                  const char* name) override;
+void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) override;
+void DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) override;
+GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) override;
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) override;
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) override;
+void PopulateSubscribedValuesCHROMIUM(GLenum target) override;
+void UniformValuebufferCHROMIUM(GLint location,
+                                GLenum target,
+                                GLenum subscription) override;
 void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
 void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
 void TraceBeginCHROMIUM(const char* name) override;
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 cf614a9..d7b53b4 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -1207,15 +1207,6 @@
   gl_->RateLimitOffscreenContextCHROMIUM();
 }
 
-void GLES2TraceImplementation::GetMultipleIntegervCHROMIUM(const GLenum* pnames,
-                                                           GLuint count,
-                                                           GLint* results,
-                                                           GLsizeiptr size) {
-  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
-                                "GLES2Trace::GetMultipleIntegervCHROMIUM");
-  gl_->GetMultipleIntegervCHROMIUM(pnames, count, results, size);
-}
-
 void GLES2TraceImplementation::GetProgramInfoCHROMIUM(GLuint program,
                                                       GLsizei bufsize,
                                                       GLsizei* size,
@@ -1358,6 +1349,51 @@
   gl_->BindUniformLocationCHROMIUM(program, location, name);
 }
 
+void GLES2TraceImplementation::GenValuebuffersCHROMIUM(GLsizei n,
+                                                       GLuint* buffers) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenValuebuffersCHROMIUM");
+  gl_->GenValuebuffersCHROMIUM(n, buffers);
+}
+
+void GLES2TraceImplementation::DeleteValuebuffersCHROMIUM(
+    GLsizei n,
+    const GLuint* valuebuffers) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+                                "GLES2Trace::DeleteValuebuffersCHROMIUM");
+  gl_->DeleteValuebuffersCHROMIUM(n, valuebuffers);
+}
+
+GLboolean GLES2TraceImplementation::IsValuebufferCHROMIUM(GLuint valuebuffer) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsValuebufferCHROMIUM");
+  return gl_->IsValuebufferCHROMIUM(valuebuffer);
+}
+
+void GLES2TraceImplementation::BindValuebufferCHROMIUM(GLenum target,
+                                                       GLuint valuebuffer) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindValuebufferCHROMIUM");
+  gl_->BindValuebufferCHROMIUM(target, valuebuffer);
+}
+
+void GLES2TraceImplementation::SubscribeValueCHROMIUM(GLenum target,
+                                                      GLenum subscription) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SubscribeValueCHROMIUM");
+  gl_->SubscribeValueCHROMIUM(target, subscription);
+}
+
+void GLES2TraceImplementation::PopulateSubscribedValuesCHROMIUM(GLenum target) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+                                "GLES2Trace::PopulateSubscribedValuesCHROMIUM");
+  gl_->PopulateSubscribedValuesCHROMIUM(target);
+}
+
+void GLES2TraceImplementation::UniformValuebufferCHROMIUM(GLint location,
+                                                          GLenum target,
+                                                          GLenum subscription) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+                                "GLES2Trace::UniformValuebufferCHROMIUM");
+  gl_->UniformValuebufferCHROMIUM(location, target, subscription);
+}
+
 void GLES2TraceImplementation::BindTexImage2DCHROMIUM(GLenum target,
                                                       GLint imageId) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindTexImage2DCHROMIUM");
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 37c33be..0f17198 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -183,7 +183,6 @@
 GL_APICALL const GLchar* GL_APIENTRY glGetRequestableExtensionsCHROMIUM (void);
 GL_APICALL void         GL_APIENTRY glRequestExtensionCHROMIUM (const char* extension);
 GL_APICALL void         GL_APIENTRY glRateLimitOffscreenContextCHROMIUM (void);
-GL_APICALL void         GL_APIENTRY glGetMultipleIntegervCHROMIUM (const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
 GL_APICALL void         GL_APIENTRY glGetProgramInfoCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
 GL_APICALL GLuint       GL_APIENTRY glCreateStreamTextureCHROMIUM (GLuint texture);
 GL_APICALL GLuint       GL_APIENTRY glCreateImageCHROMIUM (ClientBuffer buffer, GLsizei width, GLsizei height, GLenum internalformat);
@@ -202,6 +201,13 @@
 GL_APICALL void         GL_APIENTRY glConsumeTextureCHROMIUM (GLenumTextureBindTarget target, const GLbyte* mailbox);
 GL_APICALL GLuint       GL_APIENTRY glCreateAndConsumeTextureCHROMIUM (GLenumTextureBindTarget target, const GLbyte* mailbox);
 GL_APICALL void         GL_APIENTRY glBindUniformLocationCHROMIUM (GLidProgram program, GLint location, const char* name);
+GL_APICALL void         GL_APIENTRY glGenValuebuffersCHROMIUM (GLsizeiNotNegative n, GLuint* buffers);
+GL_APICALL void         GL_APIENTRY glDeleteValuebuffersCHROMIUM (GLsizeiNotNegative n, const GLuint* valuebuffers);
+GL_APICALL GLboolean    GL_APIENTRY glIsValuebufferCHROMIUM (GLidBindValuebuffer valuebuffer);
+GL_APICALL void         GL_APIENTRY glBindValuebufferCHROMIUM (GLenumValueBufferTarget target, GLidBindValuebuffer valuebuffer);
+GL_APICALL void         GL_APIENTRY glSubscribeValueCHROMIUM (GLenumValueBufferTarget target, GLenumSubscriptionTarget subscription);
+GL_APICALL void         GL_APIENTRY glPopulateSubscribedValuesCHROMIUM (GLenumValueBufferTarget target);
+GL_APICALL void         GL_APIENTRY glUniformValuebufferCHROMIUM (GLintUniformLocation location, GLenumValueBufferTarget target, GLenumSubscriptionTarget subscription);
 GL_APICALL void         GL_APIENTRY glBindTexImage2DCHROMIUM (GLenumTextureBindTarget target, GLint imageId);
 GL_APICALL void         GL_APIENTRY glReleaseTexImage2DCHROMIUM (GLenumTextureBindTarget target, GLint imageId);
 GL_APICALL void         GL_APIENTRY glTraceBeginCHROMIUM (const char* name);
diff --git a/gpu/command_buffer/common/capabilities.cc b/gpu/command_buffer/common/capabilities.cc
index f905f4e..9d9e90d 100644
--- a/gpu/command_buffer/common/capabilities.cc
+++ b/gpu/command_buffer/common/capabilities.cc
@@ -6,8 +6,24 @@
 
 namespace gpu {
 
+Capabilities::PerStagePrecisions::PerStagePrecisions() {
+}
+
 Capabilities::Capabilities()
-    : post_sub_buffer(false),
+    : max_combined_texture_image_units(0),
+      max_cube_map_texture_size(0),
+      max_fragment_uniform_vectors(0),
+      max_renderbuffer_size(0),
+      max_texture_image_units(0),
+      max_texture_size(0),
+      max_varying_vectors(0),
+      max_vertex_attribs(0),
+      max_vertex_texture_image_units(0),
+      max_vertex_uniform_vectors(0),
+      num_compressed_texture_formats(0),
+      num_shader_binary_formats(0),
+      bind_generates_resource_chromium(0),
+      post_sub_buffer(false),
       egl_image_external(false),
       texture_format_bgra8888(false),
       texture_format_etc1(false),
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h
index fff1ef8..224829c 100644
--- a/gpu/command_buffer/common/capabilities.h
+++ b/gpu/command_buffer/common/capabilities.h
@@ -7,9 +7,75 @@
 
 #include "gpu/gpu_export.h"
 
+// From gl2.h. We want to avoid including gl headers because client-side and
+// service-side headers conflict.
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
 namespace gpu {
 
 struct GPU_EXPORT Capabilities {
+  struct ShaderPrecision {
+    ShaderPrecision() : min_range(0), max_range(0), precision(0) {}
+    int min_range;
+    int max_range;
+    int precision;
+  };
+
+  struct PerStagePrecisions {
+    PerStagePrecisions();
+
+    ShaderPrecision low_int;
+    ShaderPrecision medium_int;
+    ShaderPrecision high_int;
+    ShaderPrecision low_float;
+    ShaderPrecision medium_float;
+    ShaderPrecision high_float;
+  };
+
+  Capabilities();
+
+  template <typename T>
+  void VisitStagePrecisions(unsigned stage,
+                            PerStagePrecisions* precisions,
+                            const T& visitor) {
+    visitor(stage, GL_LOW_INT, &precisions->low_int);
+    visitor(stage, GL_MEDIUM_INT, &precisions->medium_int);
+    visitor(stage, GL_HIGH_INT, &precisions->high_int);
+    visitor(stage, GL_LOW_FLOAT, &precisions->low_float);
+    visitor(stage, GL_MEDIUM_FLOAT, &precisions->medium_float);
+    visitor(stage, GL_HIGH_FLOAT, &precisions->high_float);
+  }
+
+  template <typename T>
+  void VisitPrecisions(const T& visitor) {
+    VisitStagePrecisions(GL_VERTEX_SHADER, &vertex_shader_precisions, visitor);
+    VisitStagePrecisions(GL_FRAGMENT_SHADER, &fragment_shader_precisions,
+                         visitor);
+  }
+
+  PerStagePrecisions vertex_shader_precisions;
+  PerStagePrecisions fragment_shader_precisions;
+  int max_combined_texture_image_units;
+  int max_cube_map_texture_size;
+  int max_fragment_uniform_vectors;
+  int max_renderbuffer_size;
+  int max_texture_image_units;
+  int max_texture_size;
+  int max_varying_vectors;
+  int max_vertex_attribs;
+  int max_vertex_texture_image_units;
+  int max_vertex_uniform_vectors;
+  int num_compressed_texture_formats;
+  int num_shader_binary_formats;
+  int bind_generates_resource_chromium;
+
   bool post_sub_buffer;
   bool egl_image_external;
   bool texture_format_bgra8888;
@@ -25,8 +91,6 @@
   bool future_sync_points;
   bool blend_equation_advanced;
   bool blend_equation_advanced_coherent;
-
-  Capabilities();
 };
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index 393303e..c0bc663 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -59,6 +59,7 @@
   kTextures,
   kQueries,
   kVertexArrays,
+  kValuebuffers,
   kNumIdNamespaces
 };
 
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index ecef6bb..14f0728 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -7533,72 +7533,6 @@
 COMPILE_ASSERT(offsetof(RequestExtensionCHROMIUM, bucket_id) == 4,
                OffsetOf_RequestExtensionCHROMIUM_bucket_id_not_4);
 
-struct GetMultipleIntegervCHROMIUM {
-  typedef GetMultipleIntegervCHROMIUM ValueType;
-  static const CommandId kCmdId = kGetMultipleIntegervCHROMIUM;
-  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(uint32_t _pnames_shm_id,
-            uint32_t _pnames_shm_offset,
-            GLuint _count,
-            uint32_t _results_shm_id,
-            uint32_t _results_shm_offset,
-            GLsizeiptr _size) {
-    SetHeader();
-    pnames_shm_id = _pnames_shm_id;
-    pnames_shm_offset = _pnames_shm_offset;
-    count = _count;
-    results_shm_id = _results_shm_id;
-    results_shm_offset = _results_shm_offset;
-    size = _size;
-  }
-
-  void* Set(void* cmd,
-            uint32_t _pnames_shm_id,
-            uint32_t _pnames_shm_offset,
-            GLuint _count,
-            uint32_t _results_shm_id,
-            uint32_t _results_shm_offset,
-            GLsizeiptr _size) {
-    static_cast<ValueType*>(cmd)->Init(_pnames_shm_id, _pnames_shm_offset,
-                                       _count, _results_shm_id,
-                                       _results_shm_offset, _size);
-    return NextCmdAddress<ValueType>(cmd);
-  }
-
-  gpu::CommandHeader header;
-  uint32_t pnames_shm_id;
-  uint32_t pnames_shm_offset;
-  uint32_t count;
-  uint32_t results_shm_id;
-  uint32_t results_shm_offset;
-  int32_t size;
-};
-
-COMPILE_ASSERT(sizeof(GetMultipleIntegervCHROMIUM) == 28,
-               Sizeof_GetMultipleIntegervCHROMIUM_is_not_28);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, header) == 0,
-               OffsetOf_GetMultipleIntegervCHROMIUM_header_not_0);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, pnames_shm_id) == 4,
-               OffsetOf_GetMultipleIntegervCHROMIUM_pnames_shm_id_not_4);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, pnames_shm_offset) == 8,
-               OffsetOf_GetMultipleIntegervCHROMIUM_pnames_shm_offset_not_8);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, count) == 12,
-               OffsetOf_GetMultipleIntegervCHROMIUM_count_not_12);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, results_shm_id) == 16,
-               OffsetOf_GetMultipleIntegervCHROMIUM_results_shm_id_not_16);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, results_shm_offset) == 20,
-               OffsetOf_GetMultipleIntegervCHROMIUM_results_shm_offset_not_20);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, size) == 24,
-               OffsetOf_GetMultipleIntegervCHROMIUM_size_not_24);
-
 struct GetProgramInfoCHROMIUM {
   typedef GetProgramInfoCHROMIUM ValueType;
   static const CommandId kCmdId = kGetProgramInfoCHROMIUM;
@@ -8171,6 +8105,287 @@
     offsetof(BindUniformLocationCHROMIUMBucket, name_bucket_id) == 12,
     OffsetOf_BindUniformLocationCHROMIUMBucket_name_bucket_id_not_12);
 
+struct GenValuebuffersCHROMIUMImmediate {
+  typedef GenValuebuffersCHROMIUMImmediate ValueType;
+  static const CommandId kCmdId = kGenValuebuffersCHROMIUMImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize(GLsizei n) {
+    return static_cast<uint32_t>(sizeof(GLuint) * n);  // NOLINT
+  }
+
+  static uint32_t ComputeSize(GLsizei n) {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize(n));  // NOLINT
+  }
+
+  void SetHeader(GLsizei n) {
+    header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+  }
+
+  void Init(GLsizei _n, GLuint* _buffers) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _buffers, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, GLuint* _buffers) {
+    static_cast<ValueType*>(cmd)->Init(_n, _buffers);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+COMPILE_ASSERT(sizeof(GenValuebuffersCHROMIUMImmediate) == 8,
+               Sizeof_GenValuebuffersCHROMIUMImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenValuebuffersCHROMIUMImmediate, header) == 0,
+               OffsetOf_GenValuebuffersCHROMIUMImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenValuebuffersCHROMIUMImmediate, n) == 4,
+               OffsetOf_GenValuebuffersCHROMIUMImmediate_n_not_4);
+
+struct DeleteValuebuffersCHROMIUMImmediate {
+  typedef DeleteValuebuffersCHROMIUMImmediate ValueType;
+  static const CommandId kCmdId = kDeleteValuebuffersCHROMIUMImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize(GLsizei n) {
+    return static_cast<uint32_t>(sizeof(GLuint) * n);  // NOLINT
+  }
+
+  static uint32_t ComputeSize(GLsizei n) {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize(n));  // NOLINT
+  }
+
+  void SetHeader(GLsizei n) {
+    header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+  }
+
+  void Init(GLsizei _n, const GLuint* _valuebuffers) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _valuebuffers, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, const GLuint* _valuebuffers) {
+    static_cast<ValueType*>(cmd)->Init(_n, _valuebuffers);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteValuebuffersCHROMIUMImmediate) == 8,
+               Sizeof_DeleteValuebuffersCHROMIUMImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteValuebuffersCHROMIUMImmediate, header) == 0,
+               OffsetOf_DeleteValuebuffersCHROMIUMImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteValuebuffersCHROMIUMImmediate, n) == 4,
+               OffsetOf_DeleteValuebuffersCHROMIUMImmediate_n_not_4);
+
+struct IsValuebufferCHROMIUM {
+  typedef IsValuebufferCHROMIUM ValueType;
+  static const CommandId kCmdId = kIsValuebufferCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  typedef uint32_t Result;
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _valuebuffer,
+            uint32_t _result_shm_id,
+            uint32_t _result_shm_offset) {
+    SetHeader();
+    valuebuffer = _valuebuffer;
+    result_shm_id = _result_shm_id;
+    result_shm_offset = _result_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _valuebuffer,
+            uint32_t _result_shm_id,
+            uint32_t _result_shm_offset) {
+    static_cast<ValueType*>(cmd)
+        ->Init(_valuebuffer, _result_shm_id, _result_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t valuebuffer;
+  uint32_t result_shm_id;
+  uint32_t result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsValuebufferCHROMIUM) == 16,
+               Sizeof_IsValuebufferCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, header) == 0,
+               OffsetOf_IsValuebufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, valuebuffer) == 4,
+               OffsetOf_IsValuebufferCHROMIUM_valuebuffer_not_4);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, result_shm_id) == 8,
+               OffsetOf_IsValuebufferCHROMIUM_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, result_shm_offset) == 12,
+               OffsetOf_IsValuebufferCHROMIUM_result_shm_offset_not_12);
+
+struct BindValuebufferCHROMIUM {
+  typedef BindValuebufferCHROMIUM ValueType;
+  static const CommandId kCmdId = kBindValuebufferCHROMIUM;
+  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 _target, GLuint _valuebuffer) {
+    SetHeader();
+    target = _target;
+    valuebuffer = _valuebuffer;
+  }
+
+  void* Set(void* cmd, GLenum _target, GLuint _valuebuffer) {
+    static_cast<ValueType*>(cmd)->Init(_target, _valuebuffer);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  uint32_t valuebuffer;
+};
+
+COMPILE_ASSERT(sizeof(BindValuebufferCHROMIUM) == 12,
+               Sizeof_BindValuebufferCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(BindValuebufferCHROMIUM, header) == 0,
+               OffsetOf_BindValuebufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(BindValuebufferCHROMIUM, target) == 4,
+               OffsetOf_BindValuebufferCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(BindValuebufferCHROMIUM, valuebuffer) == 8,
+               OffsetOf_BindValuebufferCHROMIUM_valuebuffer_not_8);
+
+struct SubscribeValueCHROMIUM {
+  typedef SubscribeValueCHROMIUM ValueType;
+  static const CommandId kCmdId = kSubscribeValueCHROMIUM;
+  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 _target, GLenum _subscription) {
+    SetHeader();
+    target = _target;
+    subscription = _subscription;
+  }
+
+  void* Set(void* cmd, GLenum _target, GLenum _subscription) {
+    static_cast<ValueType*>(cmd)->Init(_target, _subscription);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  uint32_t subscription;
+};
+
+COMPILE_ASSERT(sizeof(SubscribeValueCHROMIUM) == 12,
+               Sizeof_SubscribeValueCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(SubscribeValueCHROMIUM, header) == 0,
+               OffsetOf_SubscribeValueCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(SubscribeValueCHROMIUM, target) == 4,
+               OffsetOf_SubscribeValueCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(SubscribeValueCHROMIUM, subscription) == 8,
+               OffsetOf_SubscribeValueCHROMIUM_subscription_not_8);
+
+struct PopulateSubscribedValuesCHROMIUM {
+  typedef PopulateSubscribedValuesCHROMIUM ValueType;
+  static const CommandId kCmdId = kPopulateSubscribedValuesCHROMIUM;
+  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 _target) {
+    SetHeader();
+    target = _target;
+  }
+
+  void* Set(void* cmd, GLenum _target) {
+    static_cast<ValueType*>(cmd)->Init(_target);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+};
+
+COMPILE_ASSERT(sizeof(PopulateSubscribedValuesCHROMIUM) == 8,
+               Sizeof_PopulateSubscribedValuesCHROMIUM_is_not_8);
+COMPILE_ASSERT(offsetof(PopulateSubscribedValuesCHROMIUM, header) == 0,
+               OffsetOf_PopulateSubscribedValuesCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(PopulateSubscribedValuesCHROMIUM, target) == 4,
+               OffsetOf_PopulateSubscribedValuesCHROMIUM_target_not_4);
+
+struct UniformValuebufferCHROMIUM {
+  typedef UniformValuebufferCHROMIUM ValueType;
+  static const CommandId kCmdId = kUniformValuebufferCHROMIUM;
+  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(GLint _location, GLenum _target, GLenum _subscription) {
+    SetHeader();
+    location = _location;
+    target = _target;
+    subscription = _subscription;
+  }
+
+  void* Set(void* cmd, GLint _location, GLenum _target, GLenum _subscription) {
+    static_cast<ValueType*>(cmd)->Init(_location, _target, _subscription);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  int32_t location;
+  uint32_t target;
+  uint32_t subscription;
+};
+
+COMPILE_ASSERT(sizeof(UniformValuebufferCHROMIUM) == 16,
+               Sizeof_UniformValuebufferCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, header) == 0,
+               OffsetOf_UniformValuebufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, location) == 4,
+               OffsetOf_UniformValuebufferCHROMIUM_location_not_4);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, target) == 8,
+               OffsetOf_UniformValuebufferCHROMIUM_target_not_8);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, subscription) == 12,
+               OffsetOf_UniformValuebufferCHROMIUM_subscription_not_12);
+
 struct BindTexImage2DCHROMIUM {
   typedef BindTexImage2DCHROMIUM ValueType;
   static const CommandId kCmdId = kBindTexImage2DCHROMIUM;
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 7d037a6..d1470d4 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -2533,25 +2533,6 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
-TEST_F(GLES2FormatTest, GetMultipleIntegervCHROMIUM) {
-  cmds::GetMultipleIntegervCHROMIUM& cmd =
-      *GetBufferAs<cmds::GetMultipleIntegervCHROMIUM>();
-  void* next_cmd =
-      cmd.Set(&cmd, static_cast<uint32_t>(11), static_cast<uint32_t>(12),
-              static_cast<GLuint>(13), static_cast<uint32_t>(14),
-              static_cast<uint32_t>(15), static_cast<GLsizeiptr>(16));
-  EXPECT_EQ(static_cast<uint32_t>(cmds::GetMultipleIntegervCHROMIUM::kCmdId),
-            cmd.header.command);
-  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
-  EXPECT_EQ(static_cast<uint32_t>(11), cmd.pnames_shm_id);
-  EXPECT_EQ(static_cast<uint32_t>(12), cmd.pnames_shm_offset);
-  EXPECT_EQ(static_cast<GLuint>(13), cmd.count);
-  EXPECT_EQ(static_cast<uint32_t>(14), cmd.results_shm_id);
-  EXPECT_EQ(static_cast<uint32_t>(15), cmd.results_shm_offset);
-  EXPECT_EQ(static_cast<GLsizeiptr>(16), cmd.size);
-  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
-}
-
 TEST_F(GLES2FormatTest, GetProgramInfoCHROMIUM) {
   cmds::GetProgramInfoCHROMIUM& cmd =
       *GetBufferAs<cmds::GetProgramInfoCHROMIUM>();
@@ -2939,6 +2920,111 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, GenValuebuffersCHROMIUMImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::GenValuebuffersCHROMIUMImmediate& cmd =
+      *GetBufferAs<cmds::GenValuebuffersCHROMIUMImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::GenValuebuffersCHROMIUMImmediate::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(cmd.n * 4u),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd,
+      sizeof(cmd) + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+  // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, DeleteValuebuffersCHROMIUMImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::DeleteValuebuffersCHROMIUMImmediate& cmd =
+      *GetBufferAs<cmds::DeleteValuebuffersCHROMIUMImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::DeleteValuebuffersCHROMIUMImmediate::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(cmd.n * 4u),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd,
+      sizeof(cmd) + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+  // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, IsValuebufferCHROMIUM) {
+  cmds::IsValuebufferCHROMIUM& cmd =
+      *GetBufferAs<cmds::IsValuebufferCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12),
+              static_cast<uint32_t>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::IsValuebufferCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.valuebuffer);
+  EXPECT_EQ(static_cast<uint32_t>(12), cmd.result_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.result_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindValuebufferCHROMIUM) {
+  cmds::BindValuebufferCHROMIUM& cmd =
+      *GetBufferAs<cmds::BindValuebufferCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLuint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BindValuebufferCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.valuebuffer);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, SubscribeValueCHROMIUM) {
+  cmds::SubscribeValueCHROMIUM& cmd =
+      *GetBufferAs<cmds::SubscribeValueCHROMIUM>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLenum>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::SubscribeValueCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.subscription);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, PopulateSubscribedValuesCHROMIUM) {
+  cmds::PopulateSubscribedValuesCHROMIUM& cmd =
+      *GetBufferAs<cmds::PopulateSubscribedValuesCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11));
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::PopulateSubscribedValuesCHROMIUM::kCmdId),
+      cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, UniformValuebufferCHROMIUM) {
+  cmds::UniformValuebufferCHROMIUM& cmd =
+      *GetBufferAs<cmds::UniformValuebufferCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLint>(11),
+                           static_cast<GLenum>(12), static_cast<GLenum>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::UniformValuebufferCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.target);
+  EXPECT_EQ(static_cast<GLenum>(13), cmd.subscription);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, BindTexImage2DCHROMIUM) {
   cmds::BindTexImage2DCHROMIUM& cmd =
       *GetBufferAs<cmds::BindTexImage2DCHROMIUM>();
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 8bd5c0a..9c98f51 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -178,39 +178,45 @@
   OP(ResizeCHROMIUM)                           /* 419 */ \
   OP(GetRequestableExtensionsCHROMIUM)         /* 420 */ \
   OP(RequestExtensionCHROMIUM)                 /* 421 */ \
-  OP(GetMultipleIntegervCHROMIUM)              /* 422 */ \
-  OP(GetProgramInfoCHROMIUM)                   /* 423 */ \
-  OP(GetTranslatedShaderSourceANGLE)           /* 424 */ \
-  OP(PostSubBufferCHROMIUM)                    /* 425 */ \
-  OP(TexImageIOSurface2DCHROMIUM)              /* 426 */ \
-  OP(CopyTextureCHROMIUM)                      /* 427 */ \
-  OP(DrawArraysInstancedANGLE)                 /* 428 */ \
-  OP(DrawElementsInstancedANGLE)               /* 429 */ \
-  OP(VertexAttribDivisorANGLE)                 /* 430 */ \
-  OP(GenMailboxCHROMIUM)                       /* 431 */ \
-  OP(ProduceTextureCHROMIUMImmediate)          /* 432 */ \
-  OP(ProduceTextureDirectCHROMIUMImmediate)    /* 433 */ \
-  OP(ConsumeTextureCHROMIUMImmediate)          /* 434 */ \
-  OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 435 */ \
-  OP(BindUniformLocationCHROMIUMBucket)        /* 436 */ \
-  OP(BindTexImage2DCHROMIUM)                   /* 437 */ \
-  OP(ReleaseTexImage2DCHROMIUM)                /* 438 */ \
-  OP(TraceBeginCHROMIUM)                       /* 439 */ \
-  OP(TraceEndCHROMIUM)                         /* 440 */ \
-  OP(AsyncTexSubImage2DCHROMIUM)               /* 441 */ \
-  OP(AsyncTexImage2DCHROMIUM)                  /* 442 */ \
-  OP(WaitAsyncTexImage2DCHROMIUM)              /* 443 */ \
-  OP(WaitAllAsyncTexImage2DCHROMIUM)           /* 444 */ \
-  OP(DiscardFramebufferEXTImmediate)           /* 445 */ \
-  OP(LoseContextCHROMIUM)                      /* 446 */ \
-  OP(InsertSyncPointCHROMIUM)                  /* 447 */ \
-  OP(WaitSyncPointCHROMIUM)                    /* 448 */ \
-  OP(DrawBuffersEXTImmediate)                  /* 449 */ \
-  OP(DiscardBackbufferCHROMIUM)                /* 450 */ \
-  OP(ScheduleOverlayPlaneCHROMIUM)             /* 451 */ \
-  OP(MatrixLoadfCHROMIUMImmediate)             /* 452 */ \
-  OP(MatrixLoadIdentityCHROMIUM)               /* 453 */ \
-  OP(BlendBarrierKHR)                          /* 454 */
+  OP(GetProgramInfoCHROMIUM)                   /* 422 */ \
+  OP(GetTranslatedShaderSourceANGLE)           /* 423 */ \
+  OP(PostSubBufferCHROMIUM)                    /* 424 */ \
+  OP(TexImageIOSurface2DCHROMIUM)              /* 425 */ \
+  OP(CopyTextureCHROMIUM)                      /* 426 */ \
+  OP(DrawArraysInstancedANGLE)                 /* 427 */ \
+  OP(DrawElementsInstancedANGLE)               /* 428 */ \
+  OP(VertexAttribDivisorANGLE)                 /* 429 */ \
+  OP(GenMailboxCHROMIUM)                       /* 430 */ \
+  OP(ProduceTextureCHROMIUMImmediate)          /* 431 */ \
+  OP(ProduceTextureDirectCHROMIUMImmediate)    /* 432 */ \
+  OP(ConsumeTextureCHROMIUMImmediate)          /* 433 */ \
+  OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 434 */ \
+  OP(BindUniformLocationCHROMIUMBucket)        /* 435 */ \
+  OP(GenValuebuffersCHROMIUMImmediate)         /* 436 */ \
+  OP(DeleteValuebuffersCHROMIUMImmediate)      /* 437 */ \
+  OP(IsValuebufferCHROMIUM)                    /* 438 */ \
+  OP(BindValuebufferCHROMIUM)                  /* 439 */ \
+  OP(SubscribeValueCHROMIUM)                   /* 440 */ \
+  OP(PopulateSubscribedValuesCHROMIUM)         /* 441 */ \
+  OP(UniformValuebufferCHROMIUM)               /* 442 */ \
+  OP(BindTexImage2DCHROMIUM)                   /* 443 */ \
+  OP(ReleaseTexImage2DCHROMIUM)                /* 444 */ \
+  OP(TraceBeginCHROMIUM)                       /* 445 */ \
+  OP(TraceEndCHROMIUM)                         /* 446 */ \
+  OP(AsyncTexSubImage2DCHROMIUM)               /* 447 */ \
+  OP(AsyncTexImage2DCHROMIUM)                  /* 448 */ \
+  OP(WaitAsyncTexImage2DCHROMIUM)              /* 449 */ \
+  OP(WaitAllAsyncTexImage2DCHROMIUM)           /* 450 */ \
+  OP(DiscardFramebufferEXTImmediate)           /* 451 */ \
+  OP(LoseContextCHROMIUM)                      /* 452 */ \
+  OP(InsertSyncPointCHROMIUM)                  /* 453 */ \
+  OP(WaitSyncPointCHROMIUM)                    /* 454 */ \
+  OP(DrawBuffersEXTImmediate)                  /* 455 */ \
+  OP(DiscardBackbufferCHROMIUM)                /* 456 */ \
+  OP(ScheduleOverlayPlaneCHROMIUM)             /* 457 */ \
+  OP(MatrixLoadfCHROMIUMImmediate)             /* 458 */ \
+  OP(MatrixLoadIdentityCHROMIUM)               /* 459 */ \
+  OP(BlendBarrierKHR)                          /* 460 */
 
 enum CommandId {
   kStartPoint = cmd::kLastCommonId,  // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
index 1871201..e8631e6 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -55,6 +55,7 @@
 static std::string GetStringSrcBlendFactor(uint32_t value);
 static std::string GetStringStencilOp(uint32_t value);
 static std::string GetStringStringType(uint32_t value);
+static std::string GetStringSubscriptionTarget(uint32_t value);
 static std::string GetStringTextureBindTarget(uint32_t value);
 static std::string GetStringTextureFormat(uint32_t value);
 static std::string GetStringTextureInternalFormat(uint32_t value);
@@ -66,6 +67,7 @@
 static std::string GetStringTextureTarget(uint32_t value);
 static std::string GetStringTextureUsage(uint32_t value);
 static std::string GetStringTextureWrapMode(uint32_t value);
+static std::string GetStringValueBufferTarget(uint32_t value);
 static std::string GetStringVertexAttribType(uint32_t value);
 static std::string GetStringVertexAttribute(uint32_t value);
 static std::string GetStringVertexPointer(uint32_t value);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index aba98aa..1a0945a 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -3065,6 +3065,14 @@
      "GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT",
     },
     {
+     0x924C,
+     "GL_MOUSE_POSITION_CHROMIUM",
+    },
+    {
+     0x924B,
+     "GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM",
+    },
+    {
      0x924A,
      "GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM",
     },
@@ -4355,6 +4363,14 @@
                                            arraysize(string_table), value);
 }
 
+std::string GLES2Util::GetStringSubscriptionTarget(uint32_t value) {
+  static const EnumToString string_table[] = {
+      {GL_MOUSE_POSITION_CHROMIUM, "GL_MOUSE_POSITION_CHROMIUM"},
+  };
+  return GLES2Util::GetQualifiedEnumString(string_table,
+                                           arraysize(string_table), value);
+}
+
 std::string GLES2Util::GetStringTextureBindTarget(uint32_t value) {
   static const EnumToString string_table[] = {
       {GL_TEXTURE_2D, "GL_TEXTURE_2D"},
@@ -4479,6 +4495,15 @@
                                            arraysize(string_table), value);
 }
 
+std::string GLES2Util::GetStringValueBufferTarget(uint32_t value) {
+  static const EnumToString string_table[] = {
+      {GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+       "GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM"},
+  };
+  return GLES2Util::GetQualifiedEnumString(string_table,
+                                           arraysize(string_table), value);
+}
+
 std::string GLES2Util::GetStringVertexAttribType(uint32_t value) {
   static const EnumToString string_table[] = {
       {GL_BYTE, "GL_BYTE"},
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 8293fbc..4013c3a 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -107,6 +107,8 @@
     "texture_manager.cc",
     "transfer_buffer_manager.cc",
     "transfer_buffer_manager.h",
+    "valuebuffer_manager.h",
+    "valuebuffer_manager.cc",
     "vertex_array_manager.h",
     "vertex_array_manager.cc",
     "vertex_attrib_manager.h",
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index 00e7ec3..6ee57e4 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -21,6 +21,7 @@
 #include "gpu/command_buffer/service/shader_manager.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
 #include "ui/gl/gl_implementation.h"
 
 namespace gpu {
@@ -121,6 +122,7 @@
   renderbuffer_manager_.reset(new RenderbufferManager(
       memory_tracker_.get(), max_renderbuffer_size, max_samples,
       depth24_supported));
+  valuebuffer_manager_.reset(new ValuebufferManager());
   shader_manager_.reset(new ShaderManager());
 
   // Lookup GL things we need to know.
@@ -300,6 +302,11 @@
     renderbuffer_manager_.reset();
   }
 
+  if (valuebuffer_manager_ != NULL) {
+    valuebuffer_manager_->Destroy();
+    valuebuffer_manager_.reset();
+  }
+
   if (texture_manager_ != NULL) {
     texture_manager_->Destroy(have_context);
     texture_manager_.reset();
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index ae4550c..eb53252 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -34,6 +34,7 @@
 class ProgramManager;
 class ShaderManager;
 class TextureManager;
+class ValuebufferManager;
 class MemoryTracker;
 struct DisallowedFeatures;
 
@@ -126,6 +127,10 @@
     return renderbuffer_manager_.get();
   }
 
+  ValuebufferManager* valuebuffer_manager() const {
+    return valuebuffer_manager_.get();
+  }
+
   TextureManager* texture_manager() const {
     return texture_manager_.get();
   }
@@ -199,6 +204,8 @@
 
   scoped_ptr<RenderbufferManager> renderbuffer_manager_;
 
+  scoped_ptr<ValuebufferManager> valuebuffer_manager_;
+
   scoped_ptr<TextureManager> texture_manager_;
 
   scoped_ptr<ProgramManager> program_manager_;
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h
index 7488f57..b4e812c 100644
--- a/gpu/command_buffer/service/context_state.h
+++ b/gpu/command_buffer/service/context_state.h
@@ -13,6 +13,7 @@
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/query_manager.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
 #include "gpu/command_buffer/service/vertex_attrib_manager.h"
 #include "gpu/command_buffer/service/vertex_array_manager.h"
 #include "gpu/gpu_export.h"
@@ -200,6 +201,9 @@
   scoped_refptr<Renderbuffer> bound_renderbuffer;
   bool bound_renderbuffer_valid;
 
+  // The currently bound valuebuffer
+  scoped_refptr<Valuebuffer> bound_valuebuffer;
+
   // A map of of target -> Query for current queries
   typedef std::map<GLuint, scoped_refptr<QueryManager::Query> > QueryMap;
   QueryMap current_queries;
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 9be747d..24e1f92 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -477,16 +477,22 @@
     enable_texture_half_float_linear = true;
     may_enable_chromium_color_buffer_float = true;
   } else {
-    if (is_es3 || extensions.Contains("GL_OES_texture_float")) {
+    // GLES3 adds support for Float type by default but it doesn't support all
+    // formats as GL_OES_texture_float(i.e.LUMINANCE_ALPHA,LUMINANCE and Alpha)
+    if (extensions.Contains("GL_OES_texture_float")) {
       enable_texture_float = true;
       if (extensions.Contains("GL_OES_texture_float_linear")) {
         enable_texture_float_linear = true;
       }
+      // 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) {
         may_enable_chromium_color_buffer_float = true;
       }
     }
+
     // TODO(dshwang): GLES3 supports half float by default but GL_HALF_FLOAT_OES
     // isn't equal to GL_HALF_FLOAT.
     if (extensions.Contains("GL_OES_texture_half_float")) {
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc
index 69bd4d3..88a0a37 100644
--- a/gpu/command_buffer/service/feature_info_unittest.cc
+++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -669,6 +669,26 @@
       GL_RGB32F));
 }
 
+TEST_F(FeatureInfoTest, Initialize_texture_floatGLES3) {
+  SetupInitExpectationsWithGLVersion("", "", "OpenGL ES 3.0");
+  EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_float")));
+  EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_half_float")));
+  EXPECT_THAT(info_->extensions(),
+              Not(HasSubstr("GL_OES_texture_float_linear")));
+  EXPECT_THAT(info_->extensions(),
+              Not(HasSubstr("GL_OES_texture_half_float_linear")));
+  EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGB).IsValid(
+      GL_FLOAT));
+  EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGBA).IsValid(
+      GL_FLOAT));
+  EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE).IsValid(
+      GL_FLOAT));
+  EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE_ALPHA).IsValid(
+      GL_FLOAT));
+  EXPECT_FALSE(info_->GetTextureFormatValidator(GL_ALPHA).IsValid(
+      GL_FLOAT));
+}
+
 TEST_F(FeatureInfoTest, InitializeOES_texture_floatGLES2) {
   SetupInitExpectations("GL_OES_texture_float");
   EXPECT_FALSE(info_->feature_flags().enable_texture_float_linear);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 9b028fd..4d54739 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -56,6 +56,7 @@
 #include "gpu/command_buffer/service/shader_translator.h"
 #include "gpu/command_buffer/service/shader_translator_cache.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
 #include "gpu/command_buffer/service/vertex_array_manager.h"
 #include "gpu/command_buffer/service/vertex_attrib_manager.h"
 #include "third_party/smhasher/src/City.h"
@@ -627,7 +628,7 @@
     return vertex_array_manager_.get();
   }
   ImageManager* GetImageManager() override { return image_manager_.get(); }
-  bool ProcessPendingQueries() override;
+  bool ProcessPendingQueries(bool did_finish) override;
   bool HasMoreIdleWork() override;
   void PerformIdleWork() override;
 
@@ -727,6 +728,8 @@
   void DeleteFramebuffersHelper(GLsizei n, const GLuint* client_ids);
   bool GenRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
   void DeleteRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
+  bool GenValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* client_ids);
+  void DeleteValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* client_ids);
   bool GenQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
   void DeleteQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
   bool GenVertexArraysOESHelper(GLsizei n, const GLuint* client_ids);
@@ -756,6 +759,10 @@
     return group_->framebuffer_manager();
   }
 
+  ValuebufferManager* valuebuffer_manager() {
+    return group_->valuebuffer_manager();
+  }
+
   ProgramManager* program_manager() {
     return group_->program_manager();
   }
@@ -944,6 +951,14 @@
   void DoCreateAndConsumeTextureCHROMIUM(GLenum target, const GLbyte* key,
     GLuint client_id);
 
+  bool DoIsValuebufferCHROMIUM(GLuint client_id);
+  void DoBindValueBufferCHROMIUM(GLenum target, GLuint valuebuffer);
+  void DoSubscribeValueCHROMIUM(GLenum target, GLenum subscription);
+  void DoPopulateSubscribedValuesCHROMIUM(GLenum target);
+  void DoUniformValueBufferCHROMIUM(GLint location,
+                                    GLenum target,
+                                    GLenum subscription);
+
   void DoBindTexImage2DCHROMIUM(
       GLenum target,
       GLint image_id);
@@ -1096,6 +1111,21 @@
     renderbuffer_manager()->RemoveRenderbuffer(client_id);
   }
 
+  // Creates a valuebuffer info for the given valuebuffer.
+  void CreateValuebuffer(GLuint client_id) {
+    return valuebuffer_manager()->CreateValuebuffer(client_id);
+  }
+
+  // Gets the valuebuffer info for a given valuebuffer.
+  Valuebuffer* GetValuebuffer(GLuint client_id) {
+    return valuebuffer_manager()->GetValuebuffer(client_id);
+  }
+
+  // Removes the valuebuffer info for the given valuebuffer.
+  void RemoveValuebuffer(GLuint client_id) {
+    valuebuffer_manager()->RemoveValuebuffer(client_id);
+  }
+
   // Gets the vertex attrib manager for the given vertex array.
   VertexAttribManager* GetVertexAttribManager(GLuint client_id) {
     VertexAttribManager* info =
@@ -1177,6 +1207,22 @@
       GLenum target,
       const char* func_name);
 
+  // Check if the current valuebuffer exists and is valid. If not generates
+  // the appropriate GL error. Returns true if the current valuebuffer is in
+  // a usable state.
+  bool CheckCurrentValuebuffer(const char* function_name);
+
+  // Check if the current valuebuffer exists and is valiud and that the
+  // value buffer is actually subscribed to the given subscription
+  bool CheckCurrentValuebufferForSubscription(GLenum subscription,
+                                              const char* function_name);
+
+  // Check if the location can be used for the given subscription target. If not
+  // generates the appropriate GL error. Returns true if the location is usable
+  bool CheckSubscriptionTarget(GLint location,
+                               GLenum subscription,
+                               const char* function_name);
+
   // Checks if the current program exists and is valid. If not generates the
   // appropriate GL error.  Returns true if the current program is in a usable
   // state.
@@ -1193,6 +1239,13 @@
   // of the draw operation are the same.
   bool CheckDrawingFeedbackLoops();
 
+  // Checks if |api_type| is valid for the given uniform
+  // If the api type is not valid generates the appropriate GL
+  // error. Returns true if |api_type| is valid for the uniform
+  bool CheckUniformForApiType(const Program::UniformInfo* info,
+                              const char* function_name,
+                              Program::UniformApiType api_type);
+
   // Gets the type of a uniform for a location in the current program. Sets GL
   // errors if the current program is not valid. Returns true if the current
   // program is valid and the location exists. Adjusts count so it
@@ -2670,6 +2723,7 @@
   DoBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
   DoBindFramebuffer(GL_FRAMEBUFFER, 0);
   DoBindRenderbuffer(GL_RENDERBUFFER, 0);
+  DoBindValueBufferCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 0);
 
   bool call_gl_clear = !surfaceless_;
 #if defined(OS_ANDROID)
@@ -2719,6 +2773,34 @@
   DCHECK(initialized());
 
   Capabilities caps;
+  caps.VisitPrecisions([](GLenum shader, GLenum type,
+                          Capabilities::ShaderPrecision* shader_precision) {
+    GLint range[2] = {0, 0};
+    GLint precision = 0;
+    GetShaderPrecisionFormatImpl(shader, type, range, &precision);
+    shader_precision->min_range = range[0];
+    shader_precision->max_range = range[1];
+    shader_precision->precision = precision;
+  });
+  DoGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
+                &caps.max_combined_texture_image_units);
+  DoGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &caps.max_cube_map_texture_size);
+  DoGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS,
+                &caps.max_fragment_uniform_vectors);
+  DoGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &caps.max_renderbuffer_size);
+  DoGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &caps.max_texture_image_units);
+  DoGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps.max_texture_size);
+  DoGetIntegerv(GL_MAX_VARYING_VECTORS, &caps.max_varying_vectors);
+  DoGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &caps.max_vertex_attribs);
+  DoGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
+                &caps.max_vertex_texture_image_units);
+  DoGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS,
+                &caps.max_vertex_uniform_vectors);
+  DoGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS,
+                &caps.num_compressed_texture_formats);
+  DoGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &caps.num_shader_binary_formats);
+  DoGetIntegerv(GL_BIND_GENERATES_RESOURCE_CHROMIUM,
+                &caps.bind_generates_resource_chromium);
 
   caps.egl_image_external =
       feature_info_->feature_flags().oes_egl_image_external;
@@ -2907,6 +2989,19 @@
   return true;
 }
 
+bool GLES2DecoderImpl::GenValuebuffersCHROMIUMHelper(GLsizei n,
+                                                     const GLuint* client_ids) {
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    if (GetValuebuffer(client_ids[ii])) {
+      return false;
+    }
+  }
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    CreateValuebuffer(client_ids[ii]);
+  }
+  return true;
+}
+
 bool GLES2DecoderImpl::GenTexturesHelper(GLsizei n, const GLuint* client_ids) {
   for (GLsizei ii = 0; ii < n; ++ii) {
     if (GetTexture(client_ids[ii])) {
@@ -2996,6 +3091,20 @@
   }
 }
 
+void GLES2DecoderImpl::DeleteValuebuffersCHROMIUMHelper(
+    GLsizei n,
+    const GLuint* client_ids) {
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    Valuebuffer* valuebuffer = GetValuebuffer(client_ids[ii]);
+    if (valuebuffer) {
+      if (state_.bound_valuebuffer.get() == valuebuffer) {
+        state_.bound_valuebuffer = NULL;
+      }
+      RemoveValuebuffer(client_ids[ii]);
+    }
+  }
+}
+
 void GLES2DecoderImpl::DeleteTexturesHelper(
     GLsizei n, const GLuint* client_ids) {
   bool supports_separate_framebuffer_binds =
@@ -3425,6 +3534,7 @@
   framebuffer_state_.bound_read_framebuffer = NULL;
   framebuffer_state_.bound_draw_framebuffer = NULL;
   state_.bound_renderbuffer = NULL;
+  state_.bound_valuebuffer = NULL;
 
   if (offscreen_saved_color_texture_info_.get()) {
     DCHECK(offscreen_target_color_texture_);
@@ -3916,12 +4026,12 @@
 void GLES2DecoderImpl::DoFinish() {
   glFinish();
   ProcessPendingReadPixels();
-  ProcessPendingQueries();
+  ProcessPendingQueries(true);
 }
 
 void GLES2DecoderImpl::DoFlush() {
   glFlush();
-  ProcessPendingQueries();
+  ProcessPendingQueries(false);
 }
 
 void GLES2DecoderImpl::DoActiveTexture(GLenum texture_unit) {
@@ -5722,6 +5832,55 @@
       "glTexParameteriv", GetErrorState(), texture, pname, *params);
 }
 
+bool GLES2DecoderImpl::CheckCurrentValuebuffer(const char* function_name) {
+  if (!state_.bound_valuebuffer.get()) {
+    // There is no valuebuffer bound
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+                       "no valuebuffer in use");
+    return false;
+  }
+  return true;
+}
+
+bool GLES2DecoderImpl::CheckCurrentValuebufferForSubscription(
+    GLenum subscription,
+    const char* function_name) {
+  if (!CheckCurrentValuebuffer(function_name)) {
+    return false;
+  }
+  if (!state_.bound_valuebuffer.get()->IsSubscribed(subscription)) {
+    // The valuebuffer is not subscribed to the target
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+                       "valuebuffer is not subscribed");
+    return false;
+  }
+  return true;
+}
+
+bool GLES2DecoderImpl::CheckSubscriptionTarget(GLint location,
+                                               GLenum subscription,
+                                               const char* function_name) {
+  if (!CheckCurrentProgramForUniform(location, function_name)) {
+    return false;
+  }
+  GLint real_location = -1;
+  GLint array_index = -1;
+  const Program::UniformInfo* info =
+      state_.current_program->GetUniformInfoByFakeLocation(
+          location, &real_location, &array_index);
+  if (!info) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, "unknown location");
+    return false;
+  }
+  if ((ValuebufferManager::ApiTypeForSubscriptionTarget(subscription) &
+       info->accepts_api_type) == 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+                       "wrong type for subscription");
+    return false;
+  }
+  return true;
+}
+
 bool GLES2DecoderImpl::CheckCurrentProgram(const char* function_name) {
   if (!state_.current_program.get()) {
     // The program does not exist.
@@ -5777,6 +5936,19 @@
   return false;
 }
 
+bool GLES2DecoderImpl::CheckUniformForApiType(
+    const Program::UniformInfo* info,
+    const char* function_name,
+    Program::UniformApiType api_type) {
+  DCHECK(info);
+  if ((api_type & info->accepts_api_type) == 0) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+                       "wrong uniform function for type");
+    return false;
+  }
+  return true;
+}
+
 bool GLES2DecoderImpl::PrepForSetUniformByLocation(
     GLint fake_location,
     const char* function_name,
@@ -5800,11 +5972,7 @@
         GL_INVALID_OPERATION, function_name, "unknown location");
     return false;
   }
-
-  if ((api_type & info->accepts_api_type) == 0) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_OPERATION, function_name,
-        "wrong uniform function for type");
+  if (!CheckUniformForApiType(info, function_name, api_type)) {
     return false;
   }
   if (*count > 1 && !info->is_array) {
@@ -7608,7 +7776,7 @@
     }
   } else {
     if (async && features().use_async_readpixels) {
-      GLuint buffer;
+      GLuint buffer = 0;
       glGenBuffersARB(1, &buffer);
       glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer);
       glBufferData(GL_PIXEL_PACK_BUFFER_ARB, pixels_size, NULL, GL_STREAM_READ);
@@ -7627,6 +7795,7 @@
       } else {
         // On error, unbind pack buffer and fall through to sync readpixels
         glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
+        glDeleteBuffersARB(1, &buffer);
       }
     }
     glReadPixels(x, y, width, height, format, type, pixels);
@@ -9572,88 +9741,6 @@
   return error::kNoError;
 }
 
-error::Error GLES2DecoderImpl::HandleGetMultipleIntegervCHROMIUM(
-    uint32 immediate_data_size,
-    const void* cmd_data) {
-  const gles2::cmds::GetMultipleIntegervCHROMIUM& c =
-      *static_cast<const gles2::cmds::GetMultipleIntegervCHROMIUM*>(cmd_data);
-  GLuint count = c.count;
-  uint32 pnames_size;
-  if (!SafeMultiplyUint32(count, sizeof(GLenum), &pnames_size)) {
-    return error::kOutOfBounds;
-  }
-  const GLenum* pnames = GetSharedMemoryAs<const GLenum*>(
-      c.pnames_shm_id, c.pnames_shm_offset, pnames_size);
-  if (pnames == NULL) {
-    return error::kOutOfBounds;
-  }
-
-  // We have to copy them since we use them twice so the client
-  // can't change them between the time we validate them and the time we use
-  // them.
-  scoped_ptr<GLenum[]> enums(new GLenum[count]);
-  memcpy(enums.get(), pnames, pnames_size);
-
-  // Count up the space needed for the result.
-  uint32 num_results = 0;
-  for (GLuint ii = 0; ii < count; ++ii) {
-    uint32 num = util_.GLGetNumValuesReturned(enums[ii]);
-    if (num == 0) {
-      LOCAL_SET_GL_ERROR_INVALID_ENUM(
-          "glGetMultipleCHROMIUM", enums[ii], "pname");
-      return error::kNoError;
-    }
-    // Num will never be more than 4.
-    DCHECK_LE(num, 4u);
-    if (!SafeAddUint32(num_results, num, &num_results)) {
-      return error::kOutOfBounds;
-    }
-  }
-
-  uint32 result_size = 0;
-  if (!SafeMultiplyUint32(num_results, sizeof(GLint), &result_size)) {
-    return error::kOutOfBounds;
-  }
-
-  if (result_size != static_cast<uint32>(c.size)) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_VALUE,
-        "glGetMultipleCHROMIUM", "bad size GL_INVALID_VALUE");
-    return error::kNoError;
-  }
-
-  GLint* results = GetSharedMemoryAs<GLint*>(
-      c.results_shm_id, c.results_shm_offset, result_size);
-  if (results == NULL) {
-    return error::kOutOfBounds;
-  }
-
-  // Check the results have been cleared in case the context was lost.
-  for (uint32 ii = 0; ii < num_results; ++ii) {
-    if (results[ii]) {
-      return error::kInvalidArguments;
-    }
-  }
-
-  // Get each result.
-  GLint* start = results;
-  for (GLuint ii = 0; ii < count; ++ii) {
-    GLsizei num_written = 0;
-    if (!state_.GetStateAsGLint(enums[ii], results, &num_written) &&
-        !GetHelper(enums[ii], results, &num_written)) {
-      DoGetIntegerv(enums[ii], results);
-    }
-    results += num_written;
-  }
-
-  // Just to verify. Should this be a DCHECK?
-  if (static_cast<uint32>(results - start) != num_results) {
-    return error::kOutOfBounds;
-  }
-
-  return error::kNoError;
-}
-
 error::Error GLES2DecoderImpl::HandleGetProgramInfoCHROMIUM(
     uint32 immediate_data_size,
     const void* cmd_data) {
@@ -9817,11 +9904,11 @@
   }
 }
 
-bool GLES2DecoderImpl::ProcessPendingQueries() {
+bool GLES2DecoderImpl::ProcessPendingQueries(bool did_finish) {
   if (query_manager_.get() == NULL) {
     return false;
   }
-  if (!query_manager_->ProcessPendingQueries()) {
+  if (!query_manager_->ProcessPendingQueries(did_finish)) {
     current_decoder_error_ = error::kOutOfBounds;
   }
   return query_manager_->HavePendingQueries();
@@ -10696,6 +10783,73 @@
   texture_ref = texture_manager()->Consume(client_id, texture);
 }
 
+bool GLES2DecoderImpl::DoIsValuebufferCHROMIUM(GLuint client_id) {
+  const Valuebuffer* valuebuffer = GetValuebuffer(client_id);
+  return valuebuffer && valuebuffer->IsValid();
+}
+
+void GLES2DecoderImpl::DoBindValueBufferCHROMIUM(GLenum target,
+                                                 GLuint client_id) {
+  Valuebuffer* valuebuffer = NULL;
+  if (client_id != 0) {
+    valuebuffer = GetValuebuffer(client_id);
+    if (!valuebuffer) {
+      if (!group_->bind_generates_resource()) {
+        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBindValuebufferCHROMIUM",
+                           "id not generated by glBindValuebufferCHROMIUM");
+        return;
+      }
+
+      // It's a new id so make a valuebuffer for it.
+      CreateValuebuffer(client_id);
+      valuebuffer = GetValuebuffer(client_id);
+    }
+    valuebuffer->MarkAsValid();
+  }
+  state_.bound_valuebuffer = valuebuffer;
+}
+
+void GLES2DecoderImpl::DoSubscribeValueCHROMIUM(GLenum target,
+                                                GLenum subscription) {
+  if (!CheckCurrentValuebuffer("glSubscribeValueCHROMIUM")) {
+    return;
+  }
+  state_.bound_valuebuffer.get()->AddSubscription(subscription);
+}
+
+void GLES2DecoderImpl::DoPopulateSubscribedValuesCHROMIUM(GLenum target) {
+  if (!CheckCurrentValuebuffer("glPopulateSubscribedValuesCHROMIUM")) {
+    return;
+  }
+  valuebuffer_manager()->UpdateValuebufferState(state_.bound_valuebuffer.get());
+}
+
+void GLES2DecoderImpl::DoUniformValueBufferCHROMIUM(GLint location,
+                                                    GLenum target,
+                                                    GLenum subscription) {
+  if (!CheckCurrentValuebufferForSubscription(
+          subscription, "glPopulateSubscribedValuesCHROMIUM")) {
+    return;
+  }
+  if (!CheckSubscriptionTarget(location, subscription,
+                               "glPopulateSubscribedValuesCHROMIUM")) {
+    return;
+  }
+  const ValueState* state =
+      state_.bound_valuebuffer.get()->GetState(subscription);
+  if (state) {
+    switch (subscription) {
+      case GL_MOUSE_POSITION_CHROMIUM:
+        DoUniform2iv(location, 1, state->int_value);
+        break;
+      default:
+        NOTREACHED() << "Unhandled uniform subscription target "
+                     << subscription;
+        break;
+    }
+  }
+}
+
 void GLES2DecoderImpl::DoInsertEventMarkerEXT(
     GLsizei length, const GLchar* marker) {
   if (!marker) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 8d72335..63618c2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -171,7 +171,7 @@
   virtual ImageManager* GetImageManager() = 0;
 
   // Process any pending queries. Returns false if there are no pending queries.
-  virtual bool ProcessPendingQueries() = 0;
+  virtual bool ProcessPendingQueries(bool did_finish) = 0;
 
   // Returns false if there are no idle work to be made.
   virtual bool HasMoreIdleWork() = 0;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 86b36ca..ee3bba5 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -3109,6 +3109,146 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleGenValuebuffersCHROMIUMImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::GenValuebuffersCHROMIUMImmediate& c =
+      *static_cast<const gles2::cmds::GenValuebuffersCHROMIUMImmediate*>(
+          cmd_data);
+  (void)c;
+  GLsizei n = static_cast<GLsizei>(c.n);
+  uint32_t data_size;
+  if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+    return error::kOutOfBounds;
+  }
+  GLuint* buffers =
+      GetImmediateDataAs<GLuint*>(c, data_size, immediate_data_size);
+  if (buffers == NULL) {
+    return error::kOutOfBounds;
+  }
+  if (!GenValuebuffersCHROMIUMHelper(n, buffers)) {
+    return error::kInvalidArguments;
+  }
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteValuebuffersCHROMIUMImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::DeleteValuebuffersCHROMIUMImmediate& c =
+      *static_cast<const gles2::cmds::DeleteValuebuffersCHROMIUMImmediate*>(
+          cmd_data);
+  (void)c;
+  GLsizei n = static_cast<GLsizei>(c.n);
+  uint32_t data_size;
+  if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+    return error::kOutOfBounds;
+  }
+  const GLuint* valuebuffers =
+      GetImmediateDataAs<const GLuint*>(c, data_size, immediate_data_size);
+  if (valuebuffers == NULL) {
+    return error::kOutOfBounds;
+  }
+  DeleteValuebuffersCHROMIUMHelper(n, valuebuffers);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsValuebufferCHROMIUM(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::IsValuebufferCHROMIUM& c =
+      *static_cast<const gles2::cmds::IsValuebufferCHROMIUM*>(cmd_data);
+  (void)c;
+  GLuint valuebuffer = c.valuebuffer;
+  typedef cmds::IsValuebufferCHROMIUM::Result Result;
+  Result* result_dst = GetSharedMemoryAs<Result*>(
+      c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+  if (!result_dst) {
+    return error::kOutOfBounds;
+  }
+  *result_dst = DoIsValuebufferCHROMIUM(valuebuffer);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindValuebufferCHROMIUM(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::BindValuebufferCHROMIUM& c =
+      *static_cast<const gles2::cmds::BindValuebufferCHROMIUM*>(cmd_data);
+  (void)c;
+  GLenum target = static_cast<GLenum>(c.target);
+  GLuint valuebuffer = c.valuebuffer;
+  if (!validators_->value_buffer_target.IsValid(target)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glBindValuebufferCHROMIUM", target,
+                                    "target");
+    return error::kNoError;
+  }
+  DoBindValueBufferCHROMIUM(target, valuebuffer);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleSubscribeValueCHROMIUM(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::SubscribeValueCHROMIUM& c =
+      *static_cast<const gles2::cmds::SubscribeValueCHROMIUM*>(cmd_data);
+  (void)c;
+  GLenum target = static_cast<GLenum>(c.target);
+  GLenum subscription = static_cast<GLenum>(c.subscription);
+  if (!validators_->value_buffer_target.IsValid(target)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glSubscribeValueCHROMIUM", target,
+                                    "target");
+    return error::kNoError;
+  }
+  if (!validators_->subscription_target.IsValid(subscription)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glSubscribeValueCHROMIUM", subscription,
+                                    "subscription");
+    return error::kNoError;
+  }
+  DoSubscribeValueCHROMIUM(target, subscription);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandlePopulateSubscribedValuesCHROMIUM(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::PopulateSubscribedValuesCHROMIUM& c =
+      *static_cast<const gles2::cmds::PopulateSubscribedValuesCHROMIUM*>(
+          cmd_data);
+  (void)c;
+  GLenum target = static_cast<GLenum>(c.target);
+  if (!validators_->value_buffer_target.IsValid(target)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glPopulateSubscribedValuesCHROMIUM",
+                                    target, "target");
+    return error::kNoError;
+  }
+  DoPopulateSubscribedValuesCHROMIUM(target);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniformValuebufferCHROMIUM(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  const gles2::cmds::UniformValuebufferCHROMIUM& c =
+      *static_cast<const gles2::cmds::UniformValuebufferCHROMIUM*>(cmd_data);
+  (void)c;
+  GLint location = static_cast<GLint>(c.location);
+  GLenum target = static_cast<GLenum>(c.target);
+  GLenum subscription = static_cast<GLenum>(c.subscription);
+  if (!validators_->value_buffer_target.IsValid(target)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glUniformValuebufferCHROMIUM", target,
+                                    "target");
+    return error::kNoError;
+  }
+  if (!validators_->subscription_target.IsValid(subscription)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glUniformValuebufferCHROMIUM",
+                                    subscription, "subscription");
+    return error::kNoError;
+  }
+  DoUniformValueBufferCHROMIUM(location, target, subscription);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleBindTexImage2DCHROMIUM(
     uint32_t immediate_data_size,
     const void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index 7346d8e..d855c87 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -57,7 +57,7 @@
   MOCK_METHOD0(GetContextGroup, ContextGroup*());
   MOCK_METHOD0(GetContextState, const ContextState*());
   MOCK_METHOD0(GetCapabilities, Capabilities());
-  MOCK_METHOD0(ProcessPendingQueries, bool());
+  MOCK_METHOD1(ProcessPendingQueries, bool(bool));
   MOCK_METHOD0(HasMoreIdleWork, bool());
   MOCK_METHOD0(PerformIdleWork, void());
   MOCK_METHOD1(RestoreState, void(const ContextState* prev_state));
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index e97b4c4..0ef9585 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -266,154 +266,6 @@
   EXPECT_FALSE(DoIsTexture(client_texture_id_));
 }
 
-TEST_P(GLES2DecoderTest, GetMultipleIntegervCHROMIUMValidArgs) {
-  const GLsizei kCount = 3;
-  GLenum* pnames = GetSharedMemoryAs<GLenum*>();
-  pnames[0] = GL_DEPTH_WRITEMASK;
-  pnames[1] = GL_COLOR_WRITEMASK;
-  pnames[2] = GL_STENCIL_WRITEMASK;
-  GLint* results =
-      GetSharedMemoryAsWithOffset<GLint*>(sizeof(*pnames) * kCount);
-
-  GLsizei num_results = 0;
-  for (GLsizei ii = 0; ii < kCount; ++ii) {
-    num_results += decoder_->GetGLES2Util()->GLGetNumValuesReturned(pnames[ii]);
-  }
-  const GLsizei result_size = num_results * sizeof(*results);
-  memset(results, 0, result_size);
-
-  const GLint kSentinel = 0x12345678;
-  results[num_results] = kSentinel;
-
-  GetMultipleIntegervCHROMIUM cmd;
-  cmd.Init(kSharedMemoryId,
-           kSharedMemoryOffset,
-           kCount,
-           kSharedMemoryId,
-           kSharedMemoryOffset + sizeof(*pnames) * kCount,
-           result_size);
-
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  EXPECT_EQ(1, results[0]);                    // Depth writemask
-  EXPECT_EQ(1, results[1]);                    // color writemask red
-  EXPECT_EQ(1, results[2]);                    // color writemask green
-  EXPECT_EQ(1, results[3]);                    // color writemask blue
-  EXPECT_EQ(1, results[4]);                    // color writemask alpha
-  EXPECT_EQ(-1, results[5]);                   // stencil writemask alpha
-  EXPECT_EQ(kSentinel, results[num_results]);  // End of results
-}
-
-TEST_P(GLES2DecoderTest, GetMultipleIntegervCHROMIUMInvalidArgs) {
-  const GLsizei kCount = 3;
-  // Offset the pnames because GLGetError will use the first uint32.
-  const uint32 kPnameOffset = sizeof(uint32);
-  const uint32 kResultsOffset = kPnameOffset + sizeof(GLint) * kCount;
-  GLenum* pnames = GetSharedMemoryAsWithOffset<GLenum*>(kPnameOffset);
-  pnames[0] = GL_DEPTH_WRITEMASK;
-  pnames[1] = GL_COLOR_WRITEMASK;
-  pnames[2] = GL_STENCIL_WRITEMASK;
-  GLint* results = GetSharedMemoryAsWithOffset<GLint*>(kResultsOffset);
-
-  GLsizei num_results = 0;
-  for (GLsizei ii = 0; ii < kCount; ++ii) {
-    num_results += decoder_->GetGLES2Util()->GLGetNumValuesReturned(pnames[ii]);
-  }
-  const GLsizei result_size = num_results * sizeof(*results);
-  memset(results, 0, result_size);
-
-  const GLint kSentinel = 0x12345678;
-  results[num_results] = kSentinel;
-
-  GetMultipleIntegervCHROMIUM cmd;
-  // Check bad pnames pointer.
-  cmd.Init(kInvalidSharedMemoryId,
-           kSharedMemoryOffset + kPnameOffset,
-           kCount,
-           kSharedMemoryId,
-           kSharedMemoryOffset + kResultsOffset,
-           result_size);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  // Check bad pnames pointer.
-  cmd.Init(kSharedMemoryId,
-           kInvalidSharedMemoryOffset,
-           kCount,
-           kSharedMemoryId,
-           kSharedMemoryOffset + kResultsOffset,
-           result_size);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  // Check bad count.
-  cmd.Init(kSharedMemoryId,
-           kSharedMemoryOffset + kPnameOffset,
-           static_cast<GLuint>(-1),
-           kSharedMemoryId,
-           kSharedMemoryOffset + kResultsOffset,
-           result_size);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  // Check bad results pointer.
-  cmd.Init(kSharedMemoryId,
-           kSharedMemoryOffset + kPnameOffset,
-           kCount,
-           kInvalidSharedMemoryId,
-           kSharedMemoryOffset + kResultsOffset,
-           result_size);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  // Check bad results pointer.
-  cmd.Init(kSharedMemoryId,
-           kSharedMemoryOffset + kPnameOffset,
-           kCount,
-           kSharedMemoryId,
-           kInvalidSharedMemoryOffset,
-           result_size);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  // Check bad size.
-  cmd.Init(kSharedMemoryId,
-           kSharedMemoryOffset + kPnameOffset,
-           kCount,
-           kSharedMemoryId,
-           kSharedMemoryOffset + kResultsOffset,
-           result_size + 1);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
-  // Check bad size.
-  cmd.Init(kSharedMemoryId,
-           kSharedMemoryOffset + kPnameOffset,
-           kCount,
-           kSharedMemoryId,
-           kSharedMemoryOffset + kResultsOffset,
-           result_size - 1);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
-  // Check bad enum.
-  cmd.Init(kSharedMemoryId,
-           kSharedMemoryOffset + kPnameOffset,
-           kCount,
-           kSharedMemoryId,
-           kSharedMemoryOffset + kResultsOffset,
-           result_size);
-  GLenum temp = pnames[2];
-  pnames[2] = GL_TRUE;
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
-  pnames[2] = temp;
-  // Check results area has not been cleared by client.
-  results[1] = 1;
-  EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
-  // Check buffer is what we expect
-  EXPECT_EQ(0, results[0]);
-  EXPECT_EQ(1, results[1]);
-  EXPECT_EQ(0, results[2]);
-  EXPECT_EQ(0, results[3]);
-  EXPECT_EQ(0, results[4]);
-  EXPECT_EQ(0, results[5]);
-  EXPECT_EQ(kSentinel, results[num_results]);  // End of results
-}
-
 TEST_P(GLES2DecoderManualInitTest, BindGeneratesResourceFalse) {
   InitState init;
   init.gl_version = "3.0";
@@ -636,7 +488,7 @@
 
   QueryManager* query_manager = test->GetDecoder()->GetQueryManager();
   ASSERT_TRUE(query_manager != NULL);
-  bool process_success = query_manager->ProcessPendingQueries();
+  bool process_success = query_manager->ProcessPendingQueries(false);
 
   EXPECT_TRUE(error1 != error::kNoError || error2 != error::kNoError ||
               !process_success);
@@ -797,7 +649,7 @@
   EXPECT_CALL(*gl_, ClientWaitSync(kGlSync, _, _))
       .WillOnce(Return(GL_TIMEOUT_EXPIRED))
       .RetiresOnSaturation();
-  bool process_success = query_manager->ProcessPendingQueries();
+  bool process_success = query_manager->ProcessPendingQueries(false);
 
   EXPECT_TRUE(process_success);
   EXPECT_TRUE(query->pending());
@@ -810,7 +662,7 @@
   EXPECT_CALL(*gl_, ClientWaitSync(kGlSync, _, _))
       .WillOnce(Return(GL_ALREADY_SIGNALED))
       .RetiresOnSaturation();
-  process_success = query_manager->ProcessPendingQueries();
+  process_success = query_manager->ProcessPendingQueries(false);
 
   EXPECT_TRUE(process_success);
   EXPECT_FALSE(query->pending());
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 b29b243..9397f45 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
@@ -664,8 +664,6 @@
 
 // TODO(gman): RequestExtensionCHROMIUM
 
-// TODO(gman): GetMultipleIntegervCHROMIUM
-
 // TODO(gman): GetProgramInfoCHROMIUM
 
 // TODO(gman): GetTranslatedShaderSourceANGLE
@@ -682,6 +680,31 @@
 // TODO(gman): ConsumeTextureCHROMIUMImmediate
 // TODO(gman): CreateAndConsumeTextureCHROMIUMImmediate
 // TODO(gman): BindUniformLocationCHROMIUMBucket
+// TODO(gman): GenValuebuffersCHROMIUMImmediate
+// TODO(gman): DeleteValuebuffersCHROMIUMImmediate
+
+TEST_P(GLES2DecoderTest2, IsValuebufferCHROMIUMValidArgs) {
+  SpecializedSetup<cmds::IsValuebufferCHROMIUM, 0>(true);
+  cmds::IsValuebufferCHROMIUM cmd;
+  cmd.Init(client_valuebuffer_id_, shared_memory_id_, shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, IsValuebufferCHROMIUMInvalidArgsBadSharedMemoryId) {
+  SpecializedSetup<cmds::IsValuebufferCHROMIUM, 0>(false);
+  cmds::IsValuebufferCHROMIUM cmd;
+  cmd.Init(client_valuebuffer_id_, kInvalidSharedMemoryId,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  cmd.Init(client_valuebuffer_id_, shared_memory_id_,
+           kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+// TODO(gman): BindValuebufferCHROMIUM
+// TODO(gman): SubscribeValueCHROMIUM
+// TODO(gman): PopulateSubscribedValuesCHROMIUM
+// TODO(gman): UniformValuebufferCHROMIUM
 // TODO(gman): BindTexImage2DCHROMIUM
 // TODO(gman): ReleaseTexImage2DCHROMIUM
 // TODO(gman): TraceBeginCHROMIUM
@@ -695,13 +718,4 @@
 
 // TODO(gman): WaitAllAsyncTexImage2DCHROMIUM
 
-// TODO(gman): LoseContextCHROMIUM
-// TODO(gman): InsertSyncPointCHROMIUM
-
-// TODO(gman): WaitSyncPointCHROMIUM
-
-// TODO(gman): DrawBuffersEXTImmediate
-// TODO(gman): DiscardBackbufferCHROMIUM
-
-// TODO(gman): ScheduleOverlayPlaneCHROMIUM
 #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 7e93f36..1c98b68 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,4 +12,13 @@
 #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): LoseContextCHROMIUM
+// TODO(gman): InsertSyncPointCHROMIUM
+
+// TODO(gman): WaitSyncPointCHROMIUM
+
+// TODO(gman): DrawBuffersEXTImmediate
+// TODO(gman): DiscardBackbufferCHROMIUM
+
+// TODO(gman): ScheduleOverlayPlaneCHROMIUM
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 136834d..36afe38 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -96,6 +96,7 @@
       client_fragment_shader_id_(122),
       client_query_id_(123),
       client_vertexarray_id_(124),
+      client_valuebuffer_id_(125),
       service_renderbuffer_id_(0),
       service_renderbuffer_valid_(false),
       ignore_cached_state_for_test_(GetParam()),
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index 1507440..1a2b54a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -19,6 +19,7 @@
 #include "gpu/command_buffer/service/shader_manager.h"
 #include "gpu/command_buffer/service/test_helper.h"
 #include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
 #include "gpu/command_buffer/service/vertex_array_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gl/gl_context_stub_with_extensions.h"
@@ -122,6 +123,10 @@
     return group_->program_manager()->GetProgram(client_id);
   }
 
+  Valuebuffer* GetValuebuffer(GLuint client_id) {
+    return group_->valuebuffer_manager()->GetValuebuffer(client_id);
+  }
+
   QueryManager::Query* GetQueryInfo(GLuint client_id) {
     return decoder_->GetQueryManager()->GetQuery(client_id);
   }
@@ -136,6 +141,10 @@
     return group_->program_manager();
   }
 
+  ValuebufferManager* valuebuffer_manager() {
+    return group_->valuebuffer_manager();
+  }
+
   ImageManager* GetImageManager() { return decoder_->GetImageManager(); }
 
   void DoCreateProgram(GLuint client_id, GLuint service_id);
@@ -514,6 +523,7 @@
   GLuint client_fragment_shader_id_;
   GLuint client_query_id_;
   GLuint client_vertexarray_id_;
+  GLuint client_valuebuffer_id_;
 
   uint32 shared_memory_id_;
   uint32 shared_memory_offset_;
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 d555f28..789b48a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -772,6 +772,7 @@
               ReadPixels(0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, _))
       .Times(1);
   EXPECT_CALL(*gl_, GenBuffersARB(1, _)).Times(1);
+  EXPECT_CALL(*gl_, DeleteBuffersARB(1, _)).Times(1);
   EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, _)).Times(2);
   EXPECT_CALL(*gl_,
               BufferData(GL_PIXEL_PACK_BUFFER_ARB, _, NULL, GL_STREAM_READ))
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc
new file mode 100644
index 0000000..012d504
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc
@@ -0,0 +1,130 @@
+// 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 "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+#include "base/command_line.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h"
+
+#include "gpu/command_buffer/service/test_helper.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_mock.h"
+#include "ui/gl/gl_surface_stub.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+
+namespace gpu {
+namespace gles2 {
+
+using namespace cmds;
+
+TEST_P(GLES2DecoderWithShaderTest, ValuebufferBasic) {
+  const uint32 kBufferId = 123;
+  ValueState valuestate;
+  valuestate.int_value[0] = 111;
+  valuestate.int_value[1] = 222;
+  valuebuffer_manager()->CreateValuebuffer(kBufferId);
+  valuebuffer_manager()->UpdateValueState(
+      GL_MOUSE_POSITION_CHROMIUM, valuestate);
+  BindValuebufferCHROMIUM cmd1;
+  cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  SubscribeValueCHROMIUM cmd2;
+  cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+  PopulateSubscribedValuesCHROMIUM cmd3;
+  cmd3.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd3));
+  EXPECT_CALL(*gl_, Uniform2iv(kUniform2RealLocation, 1, _)).Times(1);
+  UniformValuebufferCHROMIUM cmd4;
+  cmd4.Init(kUniform2FakeLocation, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+            GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd4));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, SubscribeValuebufferNotBound) {
+  const uint32 kBufferId = 123;
+  ValueState valuestate;
+  valuestate.int_value[0] = 111;
+  valuestate.int_value[1] = 222;
+  valuebuffer_manager()->CreateValuebuffer(kBufferId);
+  valuebuffer_manager()->UpdateValueState(
+      GL_MOUSE_POSITION_CHROMIUM, valuestate);
+  SubscribeValueCHROMIUM cmd1;
+  cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, PopulateValuebufferNoSubscription) {
+  const uint32 kBufferId = 123;
+  ValueState valuestate;
+  valuestate.int_value[0] = 111;
+  valuestate.int_value[1] = 222;
+  valuebuffer_manager()->CreateValuebuffer(kBufferId);
+  valuebuffer_manager()->UpdateValueState(
+      GL_MOUSE_POSITION_CHROMIUM, valuestate);
+  BindValuebufferCHROMIUM cmd1;
+  cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  PopulateSubscribedValuesCHROMIUM cmd2;
+  cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+  EXPECT_EQ(GL_NONE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, UniformValuebufferNoState) {
+  const uint32 kBufferId = 123;
+  ValueState valuestate;
+  valuestate.int_value[0] = 111;
+  valuestate.int_value[1] = 222;
+  valuebuffer_manager()->CreateValuebuffer(kBufferId);
+  valuebuffer_manager()->UpdateValueState(
+      GL_MOUSE_POSITION_CHROMIUM, valuestate);
+  BindValuebufferCHROMIUM cmd1;
+  cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  SubscribeValueCHROMIUM cmd2;
+  cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+  EXPECT_CALL(*gl_, Uniform2iv(kUniform2RealLocation, 1, _)).Times(0);
+  UniformValuebufferCHROMIUM cmd3;
+  cmd3.Init(kUniform2FakeLocation, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+            GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd3));
+  EXPECT_EQ(GL_NONE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, UniformValuebufferInvalidLocation) {
+  const uint32 kBufferId = 123;
+  ValueState valuestate;
+  valuestate.int_value[0] = 111;
+  valuestate.int_value[1] = 222;
+  valuebuffer_manager()->CreateValuebuffer(kBufferId);
+  valuebuffer_manager()->UpdateValueState(
+      GL_MOUSE_POSITION_CHROMIUM, valuestate);
+  BindValuebufferCHROMIUM cmd1;
+  cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+  SubscribeValueCHROMIUM cmd2;
+  cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+  PopulateSubscribedValuesCHROMIUM cmd3;
+  cmd3.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd3));
+  EXPECT_CALL(*gl_, Uniform2iv(kUniform2RealLocation, 1, _)).Times(0);
+  UniformValuebufferCHROMIUM cmd4;
+  cmd4.Init(kUniform1FakeLocation, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+            GL_MOUSE_POSITION_CHROMIUM);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd4));
+  EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+}  // namespace gles2
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
index de84037..c72bcf8 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -56,6 +56,7 @@
 ValueValidator<GLenum> src_blend_factor;
 ValueValidator<GLenum> stencil_op;
 ValueValidator<GLenum> string_type;
+ValueValidator<GLenum> subscription_target;
 ValueValidator<GLenum> texture_bind_target;
 ValueValidator<GLenum> texture_format;
 ValueValidator<GLenum> texture_internal_format;
@@ -67,6 +68,7 @@
 ValueValidator<GLenum> texture_target;
 ValueValidator<GLenum> texture_usage;
 ValueValidator<GLenum> texture_wrap_mode;
+ValueValidator<GLenum> value_buffer_target;
 ValueValidator<GLint> vertex_attrib_size;
 ValueValidator<GLenum> vertex_attrib_type;
 ValueValidator<GLenum> vertex_attribute;
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
index 790b9b3..6a646ac 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -413,6 +413,10 @@
     GL_EXTENSIONS,
 };
 
+static const GLenum valid_subscription_target_table[] = {
+    GL_MOUSE_POSITION_CHROMIUM,
+};
+
 static const GLenum valid_texture_bind_target_table[] = {
     GL_TEXTURE_2D,
     GL_TEXTURE_CUBE_MAP,
@@ -493,6 +497,10 @@
     GL_REPEAT,
 };
 
+static const GLenum valid_value_buffer_target_table[] = {
+    GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+};
+
 static const GLint valid_vertex_attrib_size_table[] = {
     1,
     2,
@@ -593,6 +601,8 @@
                        arraysize(valid_src_blend_factor_table)),
       stencil_op(valid_stencil_op_table, arraysize(valid_stencil_op_table)),
       string_type(valid_string_type_table, arraysize(valid_string_type_table)),
+      subscription_target(valid_subscription_target_table,
+                          arraysize(valid_subscription_target_table)),
       texture_bind_target(valid_texture_bind_target_table,
                           arraysize(valid_texture_bind_target_table)),
       texture_format(valid_texture_format_table,
@@ -616,6 +626,8 @@
                     arraysize(valid_texture_usage_table)),
       texture_wrap_mode(valid_texture_wrap_mode_table,
                         arraysize(valid_texture_wrap_mode_table)),
+      value_buffer_target(valid_value_buffer_target_table,
+                          arraysize(valid_value_buffer_target_table)),
       vertex_attrib_size(valid_vertex_attrib_size_table,
                          arraysize(valid_vertex_attrib_size_table)),
       vertex_attrib_type(valid_vertex_attrib_type_table,
diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc
index 058a546..48df8dd 100644
--- a/gpu/command_buffer/service/gpu_scheduler.cc
+++ b/gpu/command_buffer/service/gpu_scheduler.cc
@@ -170,7 +170,7 @@
 
 bool GpuScheduler::HasMoreWork() {
   return !unschedule_fences_.empty() ||
-         (decoder_ && decoder_->ProcessPendingQueries()) ||
+         (decoder_ && decoder_->ProcessPendingQueries(false)) ||
          HasMoreIdleWork();
 }
 
diff --git a/gpu/command_buffer/service/gpu_tracer_unittest.cc b/gpu/command_buffer/service/gpu_tracer_unittest.cc
index 59ea63e..2a7a94c 100644
--- a/gpu/command_buffer/service/gpu_tracer_unittest.cc
+++ b/gpu/command_buffer/service/gpu_tracer_unittest.cc
@@ -13,18 +13,9 @@
 namespace gpu {
 namespace gles2 {
 
-using ::testing::InvokeWithoutArgs;
 using ::testing::Return;
-using ::testing::ReturnRef;
-using ::testing::ReturnPointee;
 using ::testing::NotNull;
-using ::testing::ElementsAreArray;
-using ::testing::ElementsAre;
-using ::testing::SetArrayArgument;
 using ::testing::AtLeast;
-using ::testing::SetArgPointee;
-using ::testing::Pointee;
-using ::testing::Unused;
 using ::testing::Invoke;
 using ::testing::_;
 
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index d3e954e..9134c78 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -16,10 +16,8 @@
 #include "ui/gl/gl_mock.h"
 
 using ::testing::_;
-using ::testing::ElementsAreArray;
 using ::testing::Invoke;
 using ::testing::SetArgPointee;
-using ::testing::SetArrayArgument;
 
 namespace gpu {
 namespace gles2 {
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 7bc72de..f3c447c 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -193,8 +193,7 @@
       memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0);
 }
 
-Program::Program(
-    ProgramManager* manager, GLuint service_id)
+Program::Program(ProgramManager* manager, GLuint service_id)
     : manager_(manager),
       use_count_(0),
       max_attrib_name_length_(0),
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index dbe9c14..2f5deae 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -39,6 +39,7 @@
   };
 
   enum UniformApiType {
+    kUniformNone = 0,
     kUniform1i = 1 << 0,
     kUniform2i = 1 << 1,
     kUniform3i = 1 << 2,
diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc
index 5f518ec..fdb5fa8 100644
--- a/gpu/command_buffer/service/query_manager.cc
+++ b/gpu/command_buffer/service/query_manager.cc
@@ -64,7 +64,7 @@
 
   bool Begin() override;
   bool End(base::subtle::Atomic32 submit_count) override;
-  bool Process() override;
+  bool Process(bool did_finish) override;
   void Destroy(bool have_context) override;
 
  protected:
@@ -105,7 +105,7 @@
   return AddToPendingTransferQueue(submit_count);
 }
 
-bool AsyncPixelTransfersCompletedQuery::Process() {
+bool AsyncPixelTransfersCompletedQuery::Process(bool did_finish) {
   QuerySync* sync = manager()->decoder()->GetSharedMemoryAs<QuerySync*>(
       shm_id(), shm_offset(), sizeof(*sync));
   if (!sync)
@@ -141,7 +141,7 @@
       GLuint service_id);
   bool Begin() override;
   bool End(base::subtle::Atomic32 submit_count) override;
-  bool Process() override;
+  bool Process(bool did_finish) override;
   void Destroy(bool have_context) override;
 
  protected:
@@ -169,7 +169,7 @@
   return AddToPendingQueue(submit_count);
 }
 
-bool AllSamplesPassedQuery::Process() {
+bool AllSamplesPassedQuery::Process(bool did_finish) {
   GLuint available = 0;
   glGetQueryObjectuivARB(
       service_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
@@ -200,7 +200,7 @@
 
   bool Begin() override;
   bool End(base::subtle::Atomic32 submit_count) override;
-  bool Process() override;
+  bool Process(bool did_finish) override;
   void Destroy(bool have_context) override;
 
  protected:
@@ -226,7 +226,7 @@
   return MarkAsCompleted(elapsed.InMicroseconds());
 }
 
-bool CommandsIssuedQuery::Process() {
+bool CommandsIssuedQuery::Process(bool did_finish) {
   NOTREACHED();
   return true;
 }
@@ -247,7 +247,7 @@
 
   bool Begin() override;
   bool End(base::subtle::Atomic32 submit_count) override;
-  bool Process() override;
+  bool Process(bool did_finish) override;
   void Destroy(bool have_context) override;
 
  protected:
@@ -269,7 +269,7 @@
     return MarkAsCompleted(now.InMicroseconds());
 }
 
-bool CommandLatencyQuery::Process() {
+bool CommandLatencyQuery::Process(bool did_finish) {
   NOTREACHED();
   return true;
 }
@@ -293,7 +293,7 @@
 
   bool Begin() override;
   bool End(base::subtle::Atomic32 submit_count) override;
-  bool Process() override;
+  bool Process(bool did_finish) override;
   void Destroy(bool have_context) override;
 
  protected:
@@ -324,7 +324,7 @@
       base::Bind(&AsyncReadPixelsCompletedQuery::Complete,
                  AsWeakPtr()));
 
-  return Process();
+  return Process(false);
 }
 
 void AsyncReadPixelsCompletedQuery::Complete() {
@@ -332,7 +332,7 @@
   complete_result_ = MarkAsCompleted(1);
 }
 
-bool AsyncReadPixelsCompletedQuery::Process() {
+bool AsyncReadPixelsCompletedQuery::Process(bool did_finish) {
   return !completed_ || complete_result_;
 }
 
@@ -353,7 +353,7 @@
 
   bool Begin() override;
   bool End(base::subtle::Atomic32 submit_count) override;
-  bool Process() override;
+  bool Process(bool did_finish) override;
   void Destroy(bool have_context) override;
 
  protected:
@@ -376,7 +376,7 @@
   return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
 }
 
-bool GetErrorQuery::Process() {
+bool GetErrorQuery::Process(bool did_finish) {
   NOTREACHED();
   return true;
 }
@@ -400,7 +400,7 @@
   // Overridden from QueryManager::Query:
   bool Begin() override;
   bool End(base::subtle::Atomic32 submit_count) override;
-  bool Process() override;
+  bool Process(bool did_finish) override;
   void Destroy(bool have_context) override;
 
  protected:
@@ -424,9 +424,16 @@
   return AddToPendingQueue(submit_count);
 }
 
-bool CommandsCompletedQuery::Process() {
-  if (fence_ && !fence_->HasCompleted())
+bool CommandsCompletedQuery::Process(bool did_finish) {
+  // Note: |did_finish| guarantees that the GPU has passed the fence but
+  // we cannot assume that GLFence::HasCompleted() will return true yet as
+  // that's not guaranteed by all GLFence implementations.
+  //
+  // TODO(reveman): Add UMA stats to determine how common it is that glFinish()
+  // needs to be called for these queries to complete. crbug.com/431845
+  if (!did_finish && fence_ && !fence_->HasCompleted())
     return true;
+
   return MarkAsCompleted(0);
 }
 
@@ -635,10 +642,10 @@
   return true;
 }
 
-bool QueryManager::ProcessPendingQueries() {
+bool QueryManager::ProcessPendingQueries(bool did_finish) {
   while (!pending_queries_.empty()) {
     Query* query = pending_queries_.front().get();
-    if (!query->Process()) {
+    if (!query->Process(did_finish)) {
       return false;
     }
     if (query->pending()) {
@@ -658,7 +665,7 @@
 bool QueryManager::ProcessPendingTransferQueries() {
   while (!pending_transfer_queries_.empty()) {
     Query* query = pending_transfer_queries_.front().get();
-    if (!query->Process()) {
+    if (!query->Process(false)) {
       return false;
     }
     if (query->pending()) {
diff --git a/gpu/command_buffer/service/query_manager.h b/gpu/command_buffer/service/query_manager.h
index 62da3b8..5f14929 100644
--- a/gpu/command_buffer/service/query_manager.h
+++ b/gpu/command_buffer/service/query_manager.h
@@ -64,7 +64,7 @@
     virtual bool End(base::subtle::Atomic32 submit_count) = 0;
 
     // Returns false if shared memory for sync is invalid.
-    virtual bool Process() = 0;
+    virtual bool Process(bool did_finish) = 0;
 
     virtual void Destroy(bool have_context) = 0;
 
@@ -170,8 +170,9 @@
   bool EndQuery(Query* query, base::subtle::Atomic32 submit_count);
 
   // Processes pending queries. Returns false if any queries are pointing
-  // to invalid shared memory.
-  bool ProcessPendingQueries();
+  // to invalid shared memory. |did_finish| is true if this is called as
+  // a result of calling glFinish().
+  bool ProcessPendingQueries(bool did_finish);
 
   // True if there are pending queries.
   bool HavePendingQueries();
diff --git a/gpu/command_buffer/service/query_manager_unittest.cc b/gpu/command_buffer/service/query_manager_unittest.cc
index 80efd69..7c8e93c 100644
--- a/gpu/command_buffer/service/query_manager_unittest.cc
+++ b/gpu/command_buffer/service/query_manager_unittest.cc
@@ -214,7 +214,7 @@
   const GLuint kResult = 1;
 
   // Check nothing happens if there are no pending queries.
-  EXPECT_TRUE(manager_->ProcessPendingQueries());
+  EXPECT_TRUE(manager_->ProcessPendingQueries(false));
 
   // Create Query.
   scoped_refptr<QueryManager::Query> query(
@@ -239,7 +239,7 @@
       GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
       .WillOnce(SetArgumentPointee<2>(0))
       .RetiresOnSaturation();
-  EXPECT_TRUE(manager_->ProcessPendingQueries());
+  EXPECT_TRUE(manager_->ProcessPendingQueries(false));
   EXPECT_TRUE(query->pending());
   EXPECT_EQ(0, sync->process_count);
   EXPECT_EQ(0u, sync->result);
@@ -254,7 +254,7 @@
       GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
       .WillOnce(SetArgumentPointee<2>(kResult))
       .RetiresOnSaturation();
-  EXPECT_TRUE(manager_->ProcessPendingQueries());
+  EXPECT_TRUE(manager_->ProcessPendingQueries(false));
   EXPECT_FALSE(query->pending());
   EXPECT_EQ(kSubmitCount, sync->process_count);
   EXPECT_EQ(kResult, sync->result);
@@ -262,7 +262,7 @@
 
   // Process with no queries.
   // Expect no GL commands/
-  EXPECT_TRUE(manager_->ProcessPendingQueries());
+  EXPECT_TRUE(manager_->ProcessPendingQueries(false));
 }
 
 TEST_F(QueryManagerTest, ProcessPendingQueries) {
@@ -342,7 +342,7 @@
         GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
         .WillOnce(SetArgumentPointee<2>(0))
         .RetiresOnSaturation();
-    EXPECT_TRUE(manager_->ProcessPendingQueries());
+    EXPECT_TRUE(manager_->ProcessPendingQueries(false));
   }
   EXPECT_FALSE(query1->pending());
   EXPECT_FALSE(query2->pending());
@@ -361,7 +361,7 @@
       GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
       .WillOnce(SetArgumentPointee<2>(0))
       .RetiresOnSaturation();
-  EXPECT_TRUE(manager_->ProcessPendingQueries());
+  EXPECT_TRUE(manager_->ProcessPendingQueries(false));
   EXPECT_TRUE(query3->pending());
   EXPECT_EQ(0, sync3->process_count);
   EXPECT_EQ(0u, sync3->result);
@@ -377,7 +377,7 @@
       GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_EXT, _))
       .WillOnce(SetArgumentPointee<2>(kResult3))
       .RetiresOnSaturation();
-  EXPECT_TRUE(manager_->ProcessPendingQueries());
+  EXPECT_TRUE(manager_->ProcessPendingQueries(false));
   EXPECT_FALSE(query3->pending());
   EXPECT_EQ(kSubmitCount3, sync3->process_count);
   EXPECT_EQ(kResult3, sync3->result);
@@ -410,7 +410,7 @@
       GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
       .WillOnce(SetArgumentPointee<2>(kResult))
       .RetiresOnSaturation();
-  EXPECT_FALSE(manager_->ProcessPendingQueries());
+  EXPECT_FALSE(manager_->ProcessPendingQueries(false));
 }
 
 TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryOffset) {
@@ -439,7 +439,7 @@
       GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
       .WillOnce(SetArgumentPointee<2>(kResult))
       .RetiresOnSaturation();
-  EXPECT_FALSE(manager_->ProcessPendingQueries());
+  EXPECT_FALSE(manager_->ProcessPendingQueries(false));
 }
 
 TEST_F(QueryManagerTest, ExitWithPendingQuery) {
diff --git a/gpu/command_buffer/service/shader_translator_cache.h b/gpu/command_buffer/service/shader_translator_cache.h
index e804ef2..6b0b1a5 100644
--- a/gpu/command_buffer/service/shader_translator_cache.h
+++ b/gpu/command_buffer/service/shader_translator_cache.h
@@ -41,6 +41,7 @@
 
  private:
   friend class base::RefCounted<ShaderTranslatorCache>;
+  friend class ShaderTranslatorCacheTest_InitParamComparable_Test;
   ~ShaderTranslatorCache() override;
 
   // Parameters passed into ShaderTranslator::Init
@@ -52,18 +53,18 @@
         glsl_implementation_type;
     ShCompileOptions driver_bug_workarounds;
 
-    ShaderTranslatorInitParams(
-        sh::GLenum shader_type,
-        ShShaderSpec shader_spec,
-        const ShBuiltInResources& resources,
-        ShaderTranslatorInterface::GlslImplementationType
-            glsl_implementation_type,
-        ShCompileOptions driver_bug_workarounds)
-      : shader_type(shader_type),
-        shader_spec(shader_spec),
-        resources(resources),
-        glsl_implementation_type(glsl_implementation_type),
-        driver_bug_workarounds(driver_bug_workarounds) {
+    ShaderTranslatorInitParams(sh::GLenum shader_type,
+                               ShShaderSpec shader_spec,
+                               const ShBuiltInResources& resources,
+                               ShaderTranslatorInterface::GlslImplementationType
+                                   glsl_implementation_type,
+                               ShCompileOptions driver_bug_workarounds) {
+      memset(this, 0, sizeof(*this));
+      this->shader_type = shader_type;
+      this->shader_spec = shader_spec;
+      this->resources = resources;
+      this->glsl_implementation_type = glsl_implementation_type;
+      this->driver_bug_workarounds = driver_bug_workarounds;
     }
 
     ShaderTranslatorInitParams(const ShaderTranslatorInitParams& params) {
@@ -77,6 +78,10 @@
     bool operator< (const ShaderTranslatorInitParams& params) const {
       return memcmp(&params, this, sizeof(*this)) < 0;
     }
+
+   private:
+    ShaderTranslatorInitParams();
+    ShaderTranslatorInitParams& operator=(const ShaderTranslatorInitParams&);
   };
 
   typedef std::map<ShaderTranslatorInitParams, ShaderTranslator* > Cache;
diff --git a/gpu/command_buffer/service/shader_translator_cache_unittest.cc b/gpu/command_buffer/service/shader_translator_cache_unittest.cc
new file mode 100644
index 0000000..c5233e5
--- /dev/null
+++ b/gpu/command_buffer/service/shader_translator_cache_unittest.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <GLES2/gl2.h>
+
+#include "gpu/command_buffer/service/shader_translator_cache.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace gles2 {
+
+TEST(ShaderTranslatorCacheTest, InitParamComparable) {
+  // Tests that ShaderTranslatorInitParams padding or padding of its
+  // members does not affect the object equality or ordering.
+
+  ShBuiltInResources a_resources;
+  memset(&a_resources, 88, sizeof(a_resources));
+  ShInitBuiltInResources(&a_resources);
+
+  ShBuiltInResources b_resources;
+  memset(&b_resources, 77, sizeof(b_resources));
+  ShInitBuiltInResources(&b_resources);
+
+  EXPECT_TRUE(memcmp(&a_resources, &b_resources, sizeof(a_resources)) == 0);
+
+  ShCompileOptions driver_bug_workarounds = SH_VALIDATE;
+
+  char a_storage[sizeof(ShaderTranslatorCache::ShaderTranslatorInitParams)];
+  memset(a_storage, 55, sizeof(a_storage));
+  ShaderTranslatorCache::ShaderTranslatorInitParams* a =
+      new (&a_storage) ShaderTranslatorCache::ShaderTranslatorInitParams(
+          GL_VERTEX_SHADER,
+          SH_GLES2_SPEC,
+          a_resources,
+          ShaderTranslatorInterface::kGlslES,
+          driver_bug_workarounds);
+
+  ShaderTranslatorCache::ShaderTranslatorInitParams b(
+      GL_VERTEX_SHADER,
+      SH_GLES2_SPEC,
+      b_resources,
+      ShaderTranslatorInterface::kGlslES,
+      driver_bug_workarounds);
+
+  EXPECT_TRUE(*a == b);
+  EXPECT_FALSE(*a < b || b < *a);
+
+  memset(a_storage, 55, sizeof(a_storage));
+  a = new (&a_storage) ShaderTranslatorCache::ShaderTranslatorInitParams(b);
+
+  EXPECT_TRUE(*a == b);
+  EXPECT_FALSE(*a < b || b < *a);
+}
+}  // namespace gles2
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/valuebuffer_manager.cc b/gpu/command_buffer/service/valuebuffer_manager.cc
new file mode 100644
index 0000000..eb4db09
--- /dev/null
+++ b/gpu/command_buffer/service/valuebuffer_manager.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
+
+#include "gpu/command_buffer/service/program_manager.h"
+
+namespace gpu {
+namespace gles2 {
+
+Valuebuffer::Valuebuffer(ValuebufferManager* manager, GLuint client_id)
+    : manager_(manager), client_id_(client_id), has_been_bound_(false) {
+  manager_->StartTracking(this);
+}
+
+Valuebuffer::~Valuebuffer() {
+  if (manager_) {
+    manager_->StopTracking(this);
+    manager_ = NULL;
+  }
+}
+
+void Valuebuffer::AddSubscription(GLenum subscription) {
+  subscriptions_.insert(subscription);
+}
+
+void Valuebuffer::RemoveSubscription(GLenum subscription) {
+  subscriptions_.erase(subscription);
+}
+
+bool Valuebuffer::IsSubscribed(GLenum subscription) {
+  return subscriptions_.find(subscription) != subscriptions_.end();
+}
+
+const ValueState *Valuebuffer::GetState(GLenum target) const {
+  StateMap::const_iterator it = active_state_map_.find(target);
+  return it != active_state_map_.end() ? &it->second : NULL;
+}
+
+void Valuebuffer::UpdateState(const StateMap& pending_state) {
+  for (SubscriptionSet::const_iterator it = subscriptions_.begin();
+       it != subscriptions_.end(); ++it) {
+    StateMap::const_iterator pending_state_it = pending_state.find((*it));
+    if (pending_state_it != pending_state.end()) {
+      active_state_map_[pending_state_it->first] = pending_state_it->second;
+    }
+  }
+}
+
+ValuebufferManager::ValuebufferManager()
+    : valuebuffer_count_(0) {
+}
+
+ValuebufferManager::~ValuebufferManager() {
+  DCHECK(valuebuffer_map_.empty());
+  DCHECK(pending_state_map_.empty());
+  // If this triggers, that means something is keeping a reference to
+  // a Valuebuffer belonging to this.
+  CHECK_EQ(valuebuffer_count_, 0u);
+}
+
+void ValuebufferManager::Destroy() {
+  valuebuffer_map_.clear();
+  pending_state_map_.clear();
+}
+
+void ValuebufferManager::StartTracking(Valuebuffer* /* valuebuffer */) {
+  ++valuebuffer_count_;
+}
+
+void ValuebufferManager::StopTracking(Valuebuffer* /* valuebuffer */) {
+  --valuebuffer_count_;
+}
+
+void ValuebufferManager::CreateValuebuffer(GLuint client_id) {
+  scoped_refptr<Valuebuffer> valuebuffer(new Valuebuffer(this, client_id));
+  std::pair<ValuebufferMap::iterator, bool> result =
+      valuebuffer_map_.insert(std::make_pair(client_id, valuebuffer));
+  DCHECK(result.second);
+}
+
+Valuebuffer* ValuebufferManager::GetValuebuffer(GLuint client_id) {
+  ValuebufferMap::iterator it = valuebuffer_map_.find(client_id);
+  return it != valuebuffer_map_.end() ? it->second.get() : NULL;
+}
+
+void ValuebufferManager::RemoveValuebuffer(GLuint client_id) {
+  ValuebufferMap::iterator it = valuebuffer_map_.find(client_id);
+  if (it != valuebuffer_map_.end()) {
+    Valuebuffer* valuebuffer = it->second.get();
+    valuebuffer->MarkAsDeleted();
+    valuebuffer_map_.erase(it);
+  }
+}
+
+void ValuebufferManager::UpdateValuebufferState(Valuebuffer* valuebuffer) {
+  DCHECK(valuebuffer);
+  valuebuffer->UpdateState(pending_state_map_);
+}
+
+void ValuebufferManager::UpdateValueState(
+    GLenum target, const ValueState& state) {
+  pending_state_map_[target] = state;
+}
+
+uint32 ValuebufferManager::ApiTypeForSubscriptionTarget(GLenum target) {
+  switch (target) {
+    case GL_MOUSE_POSITION_CHROMIUM:
+      return Program::kUniform2i;
+  }
+  NOTREACHED() << "Unhandled uniform subscription target " << target;
+  return Program::kUniformNone;
+}
+
+}  // namespace gles2
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/valuebuffer_manager.h b/gpu/command_buffer/service/valuebuffer_manager.h
new file mode 100644
index 0000000..3cc4ac1
--- /dev/null
+++ b/gpu/command_buffer/service/valuebuffer_manager.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_VALUEBUFFER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_VALUEBUFFER_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class ValuebufferManager;
+
+union ValueState {
+  float float_value[4];
+  int int_value[4];
+};
+
+class GPU_EXPORT Valuebuffer : public base::RefCounted<Valuebuffer> {
+ public:
+  Valuebuffer(ValuebufferManager* manager, GLuint client_id);
+
+  GLuint client_id() const { return client_id_; }
+
+  bool IsDeleted() const { return client_id_ == 0; }
+
+  void MarkAsValid() { has_been_bound_ = true; }
+
+  bool IsValid() const { return has_been_bound_ && !IsDeleted(); }
+
+  void AddSubscription(GLenum subscription);
+  void RemoveSubscription(GLenum subscription);
+
+  // Returns true if this Valuebuffer is subscribed to subscription
+  bool IsSubscribed(GLenum subscription);
+
+  // Returns the active state for a given target in this Valuebuffer
+  // returns NULL if target state doesn't exist
+  const ValueState* GetState(GLenum target) const;
+
+ private:
+  friend class ValuebufferManager;
+  friend class base::RefCounted<Valuebuffer>;
+
+  typedef base::hash_map<GLenum, ValueState> StateMap;
+  typedef base::hash_set<GLenum> SubscriptionSet;
+
+  ~Valuebuffer();
+
+  void UpdateState(const StateMap& pending_state);
+
+  void MarkAsDeleted() { client_id_ = 0; }
+
+  // ValuebufferManager that owns this Valuebuffer.
+  ValuebufferManager* manager_;
+
+  // Client side Valuebuffer id.
+  GLuint client_id_;
+
+  // Whether this Valuebuffer has ever been bound.
+  bool has_been_bound_;
+
+  SubscriptionSet subscriptions_;
+
+  StateMap active_state_map_;
+};
+
+class GPU_EXPORT ValuebufferManager {
+ public:
+  ValuebufferManager();
+  ~ValuebufferManager();
+
+  // Must call before destruction.
+  void Destroy();
+
+  // Creates a Valuebuffer for the given Valuebuffer ids.
+  void CreateValuebuffer(GLuint client_id);
+
+  // Gets the Valuebuffer for the given Valuebuffer id.
+  Valuebuffer* GetValuebuffer(GLuint client_id);
+
+  // Removes a Valuebuffer for the given Valuebuffer id.
+  void RemoveValuebuffer(GLuint client_id);
+
+  // Updates the value state for the given Valuebuffer
+  void UpdateValuebufferState(Valuebuffer* valuebuffer);
+
+  // Gets the state for the given subscription target
+  void UpdateValueState(GLenum target, const ValueState& state);
+
+  static uint32 ApiTypeForSubscriptionTarget(GLenum target);
+
+ private:
+  friend class Valuebuffer;
+
+  typedef base::hash_map<GLuint, scoped_refptr<Valuebuffer>> ValuebufferMap;
+
+  void StartTracking(Valuebuffer* valuebuffer);
+  void StopTracking(Valuebuffer* valuebuffer);
+
+  // Counts the number of Valuebuffer allocated with 'this' as its manager.
+  // Allows to check no Valuebuffer will outlive this.
+  unsigned valuebuffer_count_;
+
+  // Info for each Valuebuffer in the system.
+  ValuebufferMap valuebuffer_map_;
+
+  // Current value state in the system
+  Valuebuffer::StateMap pending_state_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(ValuebufferManager);
+};
+
+}  // namespace gles2
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_VALUEBUFFER_MANAGER_H_
diff --git a/gpu/command_buffer/service/valuebuffer_manager_unittest.cc b/gpu/command_buffer/service/valuebuffer_manager_unittest.cc
new file mode 100644
index 0000000..ead5df5
--- /dev/null
+++ b/gpu/command_buffer/service/valuebuffer_manager_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gpu_service_test.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_mock.h"
+
+namespace gpu {
+namespace gles2 {
+
+class ValuebufferManagerTest : public GpuServiceTest {
+ public:
+  ValuebufferManagerTest() : manager_() {}
+  ~ValuebufferManagerTest() override { manager_.Destroy(); }
+
+ protected:
+  ValuebufferManager manager_;
+};
+
+TEST_F(ValuebufferManagerTest, Basic) {
+  const GLuint kClient1Id = 1;
+  const GLuint kClient2Id = 2;
+  // Check we can create a Valuebuffer
+  manager_.CreateValuebuffer(kClient1Id);
+  Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+  ASSERT_TRUE(valuebuffer0 != NULL);
+  EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+  // Check we get nothing for a non-existent Valuebuffer.
+  // Check trying to a remove non-existent Valuebuffer does not crash
+  manager_.RemoveValuebuffer(kClient2Id);
+  // Check we can't get the renderbuffer after we remove it.
+  manager_.RemoveValuebuffer(kClient1Id);
+  EXPECT_TRUE(manager_.GetValuebuffer(kClient1Id) == NULL);
+}
+
+TEST_F(ValuebufferManagerTest, Destroy) {
+  const GLuint kClient1Id = 1;
+  // Check we can create Valuebuffer.
+  manager_.CreateValuebuffer(kClient1Id);
+  Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+  ASSERT_TRUE(valuebuffer0 != NULL);
+  EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+  manager_.Destroy();
+  // Check the resources were released.
+  Valuebuffer* valuebuffer1 = manager_.GetValuebuffer(kClient1Id);
+  ASSERT_TRUE(valuebuffer1 == NULL);
+}
+
+TEST_F(ValuebufferManagerTest, ValueBuffer) {
+  const GLuint kClient1Id = 1;
+  // Check we can create a Valuebuffer
+  manager_.CreateValuebuffer(kClient1Id);
+  Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+  ASSERT_TRUE(valuebuffer0 != NULL);
+  EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+  EXPECT_FALSE(valuebuffer0->IsValid());
+}
+
+TEST_F(ValuebufferManagerTest, UpdateState) {
+  const GLuint kClient1Id = 1;
+  ValueState valuestate1;
+  valuestate1.int_value[0] = 111;
+  ValueState valuestate2;
+  valuestate2.int_value[0] = 222;
+  manager_.CreateValuebuffer(kClient1Id);
+  Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+  ASSERT_TRUE(valuebuffer0 != NULL);
+  EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+  valuebuffer0->AddSubscription(GL_MOUSE_POSITION_CHROMIUM);
+  ASSERT_TRUE(valuebuffer0->GetState(GL_MOUSE_POSITION_CHROMIUM) == NULL);
+  manager_.UpdateValueState(GL_MOUSE_POSITION_CHROMIUM, valuestate1);
+  manager_.UpdateValuebufferState(valuebuffer0);
+  const ValueState* new_state1 =
+      valuebuffer0->GetState(GL_MOUSE_POSITION_CHROMIUM);
+  ASSERT_TRUE(new_state1 != NULL);
+  ASSERT_TRUE(new_state1->int_value[0] == 111);
+  // Ensure state changes
+  manager_.UpdateValueState(GL_MOUSE_POSITION_CHROMIUM, valuestate2);
+  manager_.UpdateValuebufferState(valuebuffer0);
+  const ValueState* new_state2 =
+      valuebuffer0->GetState(GL_MOUSE_POSITION_CHROMIUM);
+  ASSERT_TRUE(new_state2 != NULL);
+  ASSERT_TRUE(new_state2->int_value[0] == 222);
+}
+
+}  // namespace gles2
+}  // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index a8a7425..ebd821c 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -323,7 +323,11 @@
 }
 
 void GLManager::PumpCommands() {
-  decoder_->MakeCurrent();
+  if (!decoder_->MakeCurrent()) {
+    command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
+    command_buffer_->SetParseError(::gpu::error::kLostContext);
+    return;
+  }
   gpu_scheduler_->PutChanged();
   ::gpu::CommandBuffer::State state = command_buffer_->GetLastState();
   if (!context_lost_allowed_) {
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index f1ed489..13ffe94 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -125,6 +125,8 @@
     'command_buffer/service/texture_manager.cc',
     'command_buffer/service/transfer_buffer_manager.cc',
     'command_buffer/service/transfer_buffer_manager.h',
+    'command_buffer/service/valuebuffer_manager.h',
+    'command_buffer/service/valuebuffer_manager.cc',
     'command_buffer/service/vertex_array_manager.h',
     'command_buffer/service/vertex_array_manager.cc',
     'command_buffer/service/vertex_attrib_manager.h',
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc
index 53343f6..eabf9b2 100644
--- a/gpu/config/gpu_info_collector_win.cc
+++ b/gpu/config/gpu_info_collector_win.cc
@@ -665,6 +665,45 @@
     return;
   }
 
+  // Track D3D Shader Model (if available)
+  const std::string& shader_version =
+      context_gpu_info.vertex_shader_version;
+
+  // Only gather if this is the first time we're seeing
+  // a non-empty shader version string.
+  if (!shader_version.empty() &&
+      basic_gpu_info->vertex_shader_version.empty()) {
+
+    // Note: do not reorder, used by UMA_HISTOGRAM below
+    enum ShaderModel {
+      SHADER_MODEL_UNKNOWN,
+      SHADER_MODEL_2_0,
+      SHADER_MODEL_3_0,
+      SHADER_MODEL_4_0,
+      SHADER_MODEL_4_1,
+      SHADER_MODEL_5_0,
+      NUM_SHADER_MODELS
+    };
+
+    ShaderModel shader_model = SHADER_MODEL_UNKNOWN;
+
+    if (shader_version == "5.0") {
+      shader_model = SHADER_MODEL_5_0;
+    } else if (shader_version == "4.1") {
+      shader_model = SHADER_MODEL_4_1;
+    } else if (shader_version == "4.0") {
+      shader_model = SHADER_MODEL_4_0;
+    } else if (shader_version == "3.0") {
+      shader_model = SHADER_MODEL_3_0;
+    } else if (shader_version == "2.0") {
+      shader_model = SHADER_MODEL_2_0;
+    }
+
+    UMA_HISTOGRAM_ENUMERATION("GPU.D3DShaderModel",
+                              shader_model,
+                              NUM_SHADER_MODELS);
+  }
+
   MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
 
   basic_gpu_info->dx_diagnostics = context_gpu_info.dx_diagnostics;
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index 0878a1d..ddecf45 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -232,6 +232,7 @@
         'command_buffer/service/gles2_cmd_decoder_unittest_programs.cc',
         'command_buffer/service/gles2_cmd_decoder_unittest_textures.cc',
         'command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc',
+        'command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc',
         'command_buffer/service/gl_surface_mock.cc',
         'command_buffer/service/gl_surface_mock.h',
         'command_buffer/service/gpu_scheduler_unittest.cc',
@@ -248,10 +249,12 @@
         'command_buffer/service/program_cache_unittest.cc',
         'command_buffer/service/shader_manager_unittest.cc',
         'command_buffer/service/shader_translator_unittest.cc',
+        'command_buffer/service/shader_translator_cache_unittest.cc',
         'command_buffer/service/test_helper.cc',
         'command_buffer/service/test_helper.h',
         'command_buffer/service/texture_manager_unittest.cc',
         'command_buffer/service/transfer_buffer_manager_unittest.cc',
+        'command_buffer/service/valuebuffer_manager_unittest.cc',
         'command_buffer/service/vertex_attrib_manager_unittest.cc',
         'command_buffer/service/vertex_array_manager_unittest.cc',
         'command_buffer/service/gpu_tracer_unittest.cc',
diff --git a/gpu/ipc/gpu_command_buffer_traits.cc b/gpu/ipc/gpu_command_buffer_traits.cc
index 46395fb..1b30034 100644
--- a/gpu/ipc/gpu_command_buffer_traits.cc
+++ b/gpu/ipc/gpu_command_buffer_traits.cc
@@ -3,8 +3,27 @@
 // found in the LICENSE file.
 
 #include "gpu/ipc/gpu_command_buffer_traits.h"
+
 #include "gpu/command_buffer/common/mailbox_holder.h"
 
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "gpu/ipc/gpu_command_buffer_traits_multi.h"
+}  // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "gpu/ipc/gpu_command_buffer_traits_multi.h"
+}  // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "gpu/ipc/gpu_command_buffer_traits_multi.h"
+}  // namespace IPC
+
 namespace IPC {
 
 void ParamTraits<gpu::CommandBuffer::State> ::Write(Message* m,
diff --git a/gpu/ipc/gpu_command_buffer_traits.h b/gpu/ipc/gpu_command_buffer_traits.h
index ce854d2..3451639 100644
--- a/gpu/ipc/gpu_command_buffer_traits.h
+++ b/gpu/ipc/gpu_command_buffer_traits.h
@@ -5,9 +5,10 @@
 #ifndef GPU_IPC_GPU_PARAM_TRAITS_H_
 #define GPU_IPC_GPU_PARAM_TRAITS_H_
 
-#include "ipc/ipc_message_utils.h"
 #include "gpu/command_buffer/common/command_buffer.h"
 #include "gpu/gpu_export.h"
+#include "gpu/ipc/gpu_command_buffer_traits_multi.h"
+#include "ipc/ipc_message_utils.h"
 
 namespace gpu {
 struct Mailbox;
diff --git a/gpu/ipc/gpu_command_buffer_traits_multi.h b/gpu/ipc/gpu_command_buffer_traits_multi.h
new file mode 100644
index 0000000..0978f79
--- /dev/null
+++ b/gpu/ipc/gpu_command_buffer_traits_multi.h
@@ -0,0 +1,59 @@
+// 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.
+
+// Multiply-included message file, hence no include guard here.
+#include "gpu/command_buffer/common/capabilities.h"
+#include "gpu/gpu_export.h"
+#include "ipc/ipc_message_utils.h"
+#include "ipc/param_traits_macros.h"
+
+#undef IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT GPU_EXPORT
+
+IPC_STRUCT_TRAITS_BEGIN(gpu::Capabilities::ShaderPrecision)
+  IPC_STRUCT_TRAITS_MEMBER(min_range)
+  IPC_STRUCT_TRAITS_MEMBER(max_range)
+  IPC_STRUCT_TRAITS_MEMBER(precision)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(gpu::Capabilities::PerStagePrecisions)
+  IPC_STRUCT_TRAITS_MEMBER(low_int)
+  IPC_STRUCT_TRAITS_MEMBER(medium_int)
+  IPC_STRUCT_TRAITS_MEMBER(high_int)
+  IPC_STRUCT_TRAITS_MEMBER(low_float)
+  IPC_STRUCT_TRAITS_MEMBER(medium_float)
+  IPC_STRUCT_TRAITS_MEMBER(high_float)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(gpu::Capabilities)
+  IPC_STRUCT_TRAITS_MEMBER(vertex_shader_precisions)
+  IPC_STRUCT_TRAITS_MEMBER(fragment_shader_precisions)
+  IPC_STRUCT_TRAITS_MEMBER(max_combined_texture_image_units)
+  IPC_STRUCT_TRAITS_MEMBER(max_cube_map_texture_size)
+  IPC_STRUCT_TRAITS_MEMBER(max_fragment_uniform_vectors)
+  IPC_STRUCT_TRAITS_MEMBER(max_renderbuffer_size)
+  IPC_STRUCT_TRAITS_MEMBER(max_texture_image_units)
+  IPC_STRUCT_TRAITS_MEMBER(max_texture_size)
+  IPC_STRUCT_TRAITS_MEMBER(max_varying_vectors)
+  IPC_STRUCT_TRAITS_MEMBER(max_vertex_attribs)
+  IPC_STRUCT_TRAITS_MEMBER(max_vertex_texture_image_units)
+  IPC_STRUCT_TRAITS_MEMBER(max_vertex_uniform_vectors)
+  IPC_STRUCT_TRAITS_MEMBER(num_compressed_texture_formats)
+  IPC_STRUCT_TRAITS_MEMBER(num_shader_binary_formats)
+  IPC_STRUCT_TRAITS_MEMBER(bind_generates_resource_chromium)
+  IPC_STRUCT_TRAITS_MEMBER(post_sub_buffer)
+  IPC_STRUCT_TRAITS_MEMBER(egl_image_external)
+  IPC_STRUCT_TRAITS_MEMBER(texture_format_bgra8888)
+  IPC_STRUCT_TRAITS_MEMBER(texture_format_etc1)
+  IPC_STRUCT_TRAITS_MEMBER(texture_format_etc1_npot)
+  IPC_STRUCT_TRAITS_MEMBER(texture_rectangle)
+  IPC_STRUCT_TRAITS_MEMBER(iosurface)
+  IPC_STRUCT_TRAITS_MEMBER(texture_usage)
+  IPC_STRUCT_TRAITS_MEMBER(texture_storage)
+  IPC_STRUCT_TRAITS_MEMBER(discard_framebuffer)
+  IPC_STRUCT_TRAITS_MEMBER(sync_query)
+  IPC_STRUCT_TRAITS_MEMBER(image)
+  IPC_STRUCT_TRAITS_MEMBER(blend_equation_advanced)
+  IPC_STRUCT_TRAITS_MEMBER(blend_equation_advanced_coherent)
+IPC_STRUCT_TRAITS_END()
diff --git a/mojo/gles2/gles2_context.cc b/mojo/gles2/gles2_context.cc
index f5e8471..51e7114 100644
--- a/mojo/gles2/gles2_context.cc
+++ b/mojo/gles2/gles2_context.cc
@@ -38,7 +38,7 @@
     return false;
   gles2_helper_->SetAutomaticFlushes(false);
   transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get()));
-  bool bind_generates_resource = true;
+  bool bind_generates_resource = false;
   // TODO(piman): Some contexts (such as compositor) want this to be true, so
   // this needs to be a public parameter.
   bool lose_context_when_out_of_memory = false;
diff --git a/net/BUILD.gn b/net/BUILD.gn
index a184a4c..d95aa5e 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -381,16 +381,6 @@
 
   if (!enable_websockets) {
     sources -= [
-      "socket_stream/socket_stream.cc",
-      "socket_stream/socket_stream.h",
-      "socket_stream/socket_stream_job.cc",
-      "socket_stream/socket_stream_job.h",
-      "socket_stream/socket_stream_job_manager.cc",
-      "socket_stream/socket_stream_job_manager.h",
-      "socket_stream/socket_stream_metrics.cc",
-      "socket_stream/socket_stream_metrics.h",
-      "spdy/spdy_websocket_stream.cc",
-      "spdy/spdy_websocket_stream.h",
       "websockets/websocket_basic_handshake_stream.cc",
       "websockets/websocket_basic_handshake_stream.h",
       "websockets/websocket_basic_stream.cc",
@@ -427,15 +417,9 @@
       "websockets/websocket_handshake_stream_create_helper.h",
       "websockets/websocket_inflater.cc",
       "websockets/websocket_inflater.h",
-      "websockets/websocket_job.cc",
-      "websockets/websocket_job.h",
       "websockets/websocket_mux.h",
-      "websockets/websocket_net_log_params.cc",
-      "websockets/websocket_net_log_params.h",
       "websockets/websocket_stream.cc",
       "websockets/websocket_stream.h",
-      "websockets/websocket_throttle.cc",
-      "websockets/websocket_throttle.h",
     ]
   }
 
@@ -588,11 +572,6 @@
     ":net",
     "//base",
   ]
-  if (is_win) {
-    cflags = [
-      "/wd4267",
-    ]
-  }
 }
 
 executable("dump_cache") {
@@ -689,6 +668,10 @@
     "test/spawned_test_server/spawned_test_server.h",
     "test/spawned_test_server/spawner_communicator.cc",
     "test/spawned_test_server/spawner_communicator.h",
+    "test/url_request/url_request_failed_job.cc",
+    "test/url_request/url_request_failed_job.h",
+    "test/url_request/url_request_mock_http_job.cc",
+    "test/url_request/url_request_mock_http_job.h",
     "url_request/test_url_fetcher_factory.cc",
     "url_request/test_url_fetcher_factory.h",
     "url_request/test_url_request_interceptor.cc",
@@ -1086,7 +1069,8 @@
 
 # TODO(GYP) make this compile on Android, we need some native test deps done.
 # TODO(GYP) Also doesn't work on Windows; dependency on boringssl is wrong.
-if (!is_android && !is_win) {
+# TODO(GYP) Also doesn't work on Mac, need to figure out why not.
+if (!is_android && !is_win && !is_mac) {
 
 source_set("quic_tools") {
   sources = [
@@ -1238,9 +1222,6 @@
 
   if (!enable_websockets) {
     sources -= [
-      "socket_stream/socket_stream_metrics_unittest.cc",
-      "socket_stream/socket_stream_unittest.cc",
-      "spdy/spdy_websocket_stream_unittest.cc",
       "websockets/websocket_basic_stream_test.cc",
       "websockets/websocket_channel_test.cc",
       "websockets/websocket_deflate_predictor_impl_test.cc",
@@ -1254,12 +1235,9 @@
       "websockets/websocket_handshake_handler_test.cc",
       "websockets/websocket_handshake_stream_create_helper_test.cc",
       "websockets/websocket_inflater_test.cc",
-      "websockets/websocket_job_test.cc",
-      "websockets/websocket_net_log_params_test.cc",
       "websockets/websocket_stream_test.cc",
       "websockets/websocket_test_util.cc",
       "websockets/websocket_test_util.h",
-      "websockets/websocket_throttle_test.cc",
     ]
   }
 
@@ -1397,4 +1375,4 @@
   ]
 }
 
-}  # !is_android
+}  # !is_android && !is_win && !is_mac
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index 89fbfff..87063b7 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -271,9 +271,7 @@
 // due to a malformed frame or other protocol violation.
 NET_ERROR(WS_PROTOCOL_ERROR, -145)
 
-// Connection was aborted for switching to another ptotocol.
-// WebSocket abort SocketStream connection when alternate protocol is found.
-NET_ERROR(PROTOCOL_SWITCHED, -146)
+// Error -146 was removed (PROTOCOL_SWITCHED)
 
 // Returned when attempting to bind an address that is already in use.
 NET_ERROR(ADDRESS_IN_USE, -147)
@@ -305,9 +303,7 @@
 // pushed to the queue.
 NET_ERROR(WS_THROTTLE_QUEUE_TOO_LARGE, -154)
 
-// There are too many active SocketStream instances, so the new connect request
-// was rejected.
-NET_ERROR(TOO_MANY_SOCKET_STREAMS, -155)
+// Error -155 was removed (TOO_MANY_SOCKET_STREAMS)
 
 // The SSL server certificate changed in a renegotiation.
 NET_ERROR(SSL_SERVER_CERT_CHANGED, -156)
diff --git a/net/base/net_errors.cc b/net/base/net_errors.cc
index 7c219af..55cdebb 100644
--- a/net/base/net_errors.cc
+++ b/net/base/net_errors.cc
@@ -56,6 +56,18 @@
          (error == ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN);
 }
 
+bool IsClientCertificateError(int error) {
+  switch (error) {
+    case ERR_BAD_SSL_CLIENT_AUTH_CERT:
+    case ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED:
+    case ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY:
+    case ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED:
+      return true;
+    default:
+      return false;
+  }
+}
+
 std::vector<int> GetAllErrorCodesForUma() {
   return base::CustomHistogram::ArrayToCustomRanges(
       kAllErrorCodes, arraysize(kAllErrorCodes));
diff --git a/net/base/net_errors.h b/net/base/net_errors.h
index 4dc6042..29b7742 100644
--- a/net/base/net_errors.h
+++ b/net/base/net_errors.h
@@ -39,6 +39,11 @@
 // Returns true if |error| is a certificate error code.
 NET_EXPORT bool IsCertificateError(int error);
 
+// Returns true if |error| is a client certificate authentication error. This
+// does not include ERR_SSL_PROTOCOL_ERROR which may also signal a bad client
+// certificate.
+NET_EXPORT bool IsClientCertificateError(int error);
+
 // Map system error code to Error.
 NET_EXPORT Error MapSystemError(int os_error);
 
diff --git a/net/base/net_log.h b/net/base/net_log.h
index 1b598ed..5fb2791 100644
--- a/net/base/net_log.h
+++ b/net/base/net_log.h
@@ -27,7 +27,7 @@
 // NetLog is the destination for log messages generated by the network stack.
 // Each log message has a "source" field which identifies the specific entity
 // that generated the message (for example, which URLRequest or which
-// SocketStream).
+// SpdySession).
 //
 // To avoid needing to pass in the "source ID" to the logging functions, NetLog
 // is usually accessed through a BoundNetLog, which will always pass in a
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 823cde1..6dfe8c6 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -26,22 +26,13 @@
 //   }
 EVENT_TYPE(FAILED)
 
-// Marks the creation/destruction of a request (net::URLRequest or
-// SocketStream).
+// Marks the creation/destruction of a request (net::URLRequest).
 EVENT_TYPE(REQUEST_ALIVE)
 
 // ------------------------------------------------------------------------
 // HostResolverImpl
 // ------------------------------------------------------------------------
 
-// The start/end of waiting on a host resolve (DNS) request.
-// The BEGIN phase contains the following parameters:
-//
-//   {
-//     "source_dependency": <Source id of the request being waited on>,
-//   }
-EVENT_TYPE(HOST_RESOLVER_IMPL)
-
 // The start/end of a host resolve (DNS) request.  Note that these events are
 // logged for all DNS requests, though not all requests result in the creation
 // of a HostResolvedImpl::Request object.
@@ -50,12 +41,11 @@
 //
 //   {
 //     "host": <Hostname associated with the request>,
-//     "address_family": <The address family to restrict results to>
+//     "address_family": <The address family to restrict results to>,
 //     "allow_cached_response": <Whether it is ok to return a result from
-//                               the host cache>
+//                               the host cache>,
 //     "is_speculative": <Whether this request was started by the DNS
 //                        prefetcher>
-//     "source_dependency": <Source id, if any, of what created the request>,
 //   }
 //
 // If an error occurred, the END phase will contain these parameters:
@@ -1694,49 +1684,6 @@
 EVENT_TYPE(HTTP_STREAM_PARSER_READ_HEADERS)
 
 // ------------------------------------------------------------------------
-// SocketStream
-// ------------------------------------------------------------------------
-
-// Measures the time between SocketStream::Connect() and
-// SocketStream::DidEstablishConnection()
-//
-// For the BEGIN phase, the following parameters are attached:
-//   {
-//      "url": <String of URL being loaded>,
-//   }
-//
-// For the END phase, if there was an error, the following parameters are
-// attached:
-//   {
-//      "net_error": <Net error code of the failure>,
-//   }
-EVENT_TYPE(SOCKET_STREAM_CONNECT)
-
-// A message sent on the SocketStream.
-EVENT_TYPE(SOCKET_STREAM_SENT)
-
-// A message received on the SocketStream.
-EVENT_TYPE(SOCKET_STREAM_RECEIVED)
-
-// ------------------------------------------------------------------------
-// WebSocketJob
-// ------------------------------------------------------------------------
-
-// This event is sent for a WebSocket handshake request.
-// The following parameters are attached:
-//   {
-//     "headers": <handshake request message>,
-//   }
-EVENT_TYPE(WEB_SOCKET_SEND_REQUEST_HEADERS)
-
-// This event is sent on receipt of the WebSocket handshake response headers.
-// The following parameters are attached:
-//   {
-//     "headers": <handshake response message>,
-//   }
-EVENT_TYPE(WEB_SOCKET_READ_RESPONSE_HEADERS)
-
-// ------------------------------------------------------------------------
 // SOCKS5ClientSocket
 // ------------------------------------------------------------------------
 
diff --git a/net/base/net_log_source_type_list.h b/net/base/net_log_source_type_list.h
index 9d66c17..dc553a4 100644
--- a/net/base/net_log_source_type_list.h
+++ b/net/base/net_log_source_type_list.h
@@ -9,13 +9,11 @@
 SOURCE_TYPE(NONE)
 
 SOURCE_TYPE(URL_REQUEST)
-SOURCE_TYPE(SOCKET_STREAM)
 SOURCE_TYPE(PROXY_SCRIPT_DECIDER)
 SOURCE_TYPE(CONNECT_JOB)
 SOURCE_TYPE(SOCKET)
 SOURCE_TYPE(SPDY_SESSION)
 SOURCE_TYPE(QUIC_SESSION)
-SOURCE_TYPE(HOST_RESOLVER_IMPL_REQUEST)
 SOURCE_TYPE(HOST_RESOLVER_IMPL_JOB)
 SOURCE_TYPE(DISK_CACHE_ENTRY)
 SOURCE_TYPE(MEMORY_CACHE_ENTRY)
diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc
index 9cad50a..5b69cfb 100644
--- a/net/base/network_delegate.cc
+++ b/net/base/network_delegate.cc
@@ -176,19 +176,6 @@
   return OnAuthRequired(request, auth_info, callback, credentials);
 }
 
-int NetworkDelegate::NotifyBeforeSocketStreamConnect(
-    SocketStream* socket,
-    const CompletionCallback& callback) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(socket);
-  DCHECK(!callback.is_null());
-  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
-  tracked_objects::ScopedTracker tracking_profile(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "423948 NetworkDelegate::OnBeforeSocketStreamConnect"));
-  return OnBeforeSocketStreamConnect(socket, callback);
-}
-
 bool NetworkDelegate::CanGetCookies(const URLRequest& request,
                                     const CookieList& cookie_list) {
   DCHECK(CalledOnValidThread());
diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h
index 299989c..03dee0b 100644
--- a/net/base/network_delegate.h
+++ b/net/base/network_delegate.h
@@ -105,9 +105,6 @@
   bool CanEnablePrivacyMode(const GURL& url,
                             const GURL& first_party_for_cookies) const;
 
-  int NotifyBeforeSocketStreamConnect(SocketStream* socket,
-                                      const CompletionCallback& callback);
-
   bool CancelURLRequestWithPolicyViolatingReferrerHeader(
       const URLRequest& request,
       const GURL& target_url,
diff --git a/net/base/registry_controlled_domains/effective_tld_names.dat b/net/base/registry_controlled_domains/effective_tld_names.dat
index ab13045..111ee06 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.dat
+++ b/net/base/registry_controlled_domains/effective_tld_names.dat
@@ -1601,7 +1601,7 @@
 
 // jp : http://en.wikipedia.org/wiki/.jp
 // http://jprs.co.jp/en/jpdomain.html
-// Submitted by registry <info@jprs.jp> 2014-02-28
+// Submitted by registry <info@jprs.jp> 2014-10-30
 jp
 // jp organizational type names
 ac.jp
@@ -1613,7 +1613,7 @@
 lg.jp
 ne.jp
 or.jp
-// jp preficture type names
+// jp prefecture type names
 aichi.jp
 akita.jp
 aomori.jp
@@ -1661,6 +1661,53 @@
 yamagata.jp
 yamaguchi.jp
 yamanashi.jp
+栃木.jp
+愛知.jp
+愛媛.jp
+兵庫.jp
+熊本.jp
+茨城.jp
+北海道.jp
+千葉.jp
+和歌山.jp
+長崎.jp
+長野.jp
+新潟.jp
+青森.jp
+静岡.jp
+東京.jp
+石川.jp
+埼玉.jp
+三重.jp
+京都.jp
+佐賀.jp
+大分.jp
+大阪.jp
+奈良.jp
+宮城.jp
+宮崎.jp
+富山.jp
+山口.jp
+山形.jp
+山梨.jp
+岩手.jp
+岐阜.jp
+岡山.jp
+島根.jp
+広島.jp
+徳島.jp
+沖縄.jp
+滋賀.jp
+神奈川.jp
+福井.jp
+福岡.jp
+福島.jp
+秋田.jp
+群馬.jp
+香川.jp
+高知.jp
+鳥取.jp
+鹿児島.jp
 // jp geographic type names
 // http://jprs.jp/doc/rule/saisoku-1.html
 *.kawasaki.jp
@@ -5259,27 +5306,30 @@
 gos.pk
 info.pk
 
-// pl : http://www.dns.pl/english/
+// pl http://www.dns.pl/english/index.html
+// confirmed on 26.09.2014 from Bogna Tchórzewska <partner@dns.pl>
 pl
-// NASK functional domains (nask.pl / dns.pl) : http://www.dns.pl/english/dns-funk.html
+com.pl
+net.pl
+org.pl
+info.pl
+waw.pl
+gov.pl
+// pl functional domains (http://www.dns.pl/english/index.html)
 aid.pl
 agro.pl
 atm.pl
 auto.pl
 biz.pl
-com.pl
 edu.pl
 gmina.pl
 gsm.pl
-info.pl
 mail.pl
 miasta.pl
 media.pl
 mil.pl
-net.pl
 nieruchomosci.pl
 nom.pl
-org.pl
 pc.pl
 powiat.pl
 priv.pl
@@ -5295,12 +5345,7 @@
 tourism.pl
 travel.pl
 turystyka.pl
-// ICM functional domains (icm.edu.pl)
-6bone.pl
-art.pl
-mbone.pl
 // Government domains (administred by ippt.gov.pl)
-gov.pl
 uw.gov.pl
 um.gov.pl
 ug.gov.pl
@@ -5310,11 +5355,7 @@
 sr.gov.pl
 po.gov.pl
 pa.gov.pl
-// other functional domains
-ngo.pl
-irc.pl
-usenet.pl
-// NASK geographical domains : http://www.dns.pl/english/dns-regiony.html
+// pl regional domains (http://www.dns.pl/english/index.html)
 augustow.pl
 babia-gora.pl
 bedzin.pl
@@ -5400,7 +5441,6 @@
 rzeszow.pl
 sanok.pl
 sejny.pl
-siedlce.pl
 slask.pl
 slupsk.pl
 sosnowiec.pl
@@ -5422,7 +5462,6 @@
 walbrzych.pl
 warmia.pl
 warszawa.pl
-waw.pl
 wegrow.pl
 wielun.pl
 wlocl.pl
@@ -5435,18 +5474,6 @@
 zarow.pl
 zgora.pl
 zgorzelec.pl
-// TASK geographical domains (www.task.gda.pl/uslugi/dns)
-gda.pl
-gdansk.pl
-gdynia.pl
-med.pl
-sopot.pl
-// other geographical domains
-gliwice.pl
-krakow.pl
-poznan.pl
-wroc.pl
-zakopane.pl
 
 // pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
 pm
@@ -5631,7 +5658,7 @@
 mari-el.ru
 marine.ru
 mordovia.ru
-mosreg.ru
+// mosreg.ru  Bug 1090800 - removed at request of Aleksey Konstantinov <konstantinovav@mosreg.ru>
 msk.ru
 murmansk.ru
 nalchik.ru
@@ -6756,7 +6783,10 @@
 *.zw
 
 
-// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2014-09-02T12:02:06Z
+// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2014-11-03T18:02:06Z
+
+// abb : 2014-10-24 ABB Ltd
+abb
 
 // abbott : 2014-07-24 Abbott Laboratories, Inc.
 abbott
@@ -6779,6 +6809,12 @@
 // actor : 2013-12-12 United TLD Holdco Ltd.
 actor
 
+// adult : 2014-10-16 ICM Registry AD LLC
+adult
+
+// afl : 2014-10-02 Australian Football League
+afl
+
 // africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa
 africa
 
@@ -6788,6 +6824,9 @@
 // airforce : 2014-03-06 United TLD Holdco Ltd.
 airforce
 
+// airtel : 2014-10-24 Bharti Airtel Limited
+airtel
+
 // allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft
 allfinanz
 
@@ -6812,10 +6851,10 @@
 // associates : 2014-03-06 Baxter Hill, LLC
 associates
 
-// attorney : 2014-03-20 undefined
+// attorney : 2014-03-20 
 attorney
 
-// auction : 2014-03-20 undefined
+// auction : 2014-03-20 
 auction
 
 // audio : 2014-03-20 Uniregistry, Corp.
@@ -6827,9 +6866,12 @@
 // axa : 2013-12-19 AXA SA
 axa
 
-// band : 2014-06-12 Auburn Hollow, LLC
+// band : 2014-06-12 
 band
 
+// bank : 2014-09-25 fTLD Registry Services LLC
+bank
+
 // bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
 bar
 
@@ -6845,6 +6887,9 @@
 // bayern : 2014-01-23 Bayern Connect GmbH
 bayern
 
+// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A.
+bbva
+
 // bcn : 2014-07-24 Municipi de Barcelona
 bcn
 
@@ -6884,6 +6929,9 @@
 // blue : 2013-11-07 Afilias Limited
 blue
 
+// bms : 2014-10-30 Bristol-Myers Squibb Company
+bms
+
 // bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft
 bmw
 
@@ -6893,6 +6941,9 @@
 // bnpparibas : 2014-05-29 BNP Paribas
 bnpparibas
 
+// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+bom
+
 // bond : 2014-06-05 Bond University Limited
 bond
 
@@ -6938,6 +6989,9 @@
 // cancerresearch : 2014-05-15 Australian Cancer Research Foundation
 cancerresearch
 
+// canon : 2014-09-12 Canon Inc.
+canon
+
 // capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
 capetown
 
@@ -6995,6 +7049,9 @@
 // cheap : 2013-11-14 Sand Cover, LLC
 cheap
 
+// chloe : 2014-10-16 Richemont DNS Inc.
+chloe
+
 // christmas : 2013-11-21 Uniregistry, Corp.
 christmas
 
@@ -7028,6 +7085,9 @@
 // club : 2013-11-08 .CLUB DOMAINS, LLC
 club
 
+// coach : 2014-10-09 Koko Island, LLC
+coach
+
 // codes : 2013-10-31 Puff Willow, LLC
 codes
 
@@ -7058,7 +7118,7 @@
 // construction : 2013-09-16 Fox Dynamite, LLC
 construction
 
-// consulting : 2013-12-05 undefined
+// consulting : 2013-12-05 
 consulting
 
 // contractors : 2013-09-10 Magic Woods, LLC
@@ -7070,6 +7130,9 @@
 // cool : 2013-11-14 Koko Lake, LLC
 cool
 
+// corsica : 2014-09-25 Collectivité Territoriale de Corse
+corsica
+
 // country : 2013-12-19 Top Level Domain Holdings Limited
 country
 
@@ -7079,12 +7142,21 @@
 // creditcard : 2014-03-20 Binky Frostbite, LLC
 creditcard
 
+// cricket : 2014-10-09 dot Cricket Limited
+cricket
+
+// crown : 2014-10-24 Crown Equipment Corporation
+crown
+
 // crs : 2014-04-03 Federated Co-operatives Limited
 crs
 
 // cruises : 2013-12-05 Spring Way, LLC
 cruises
 
+// csc : 2014-09-25 Alliance-One Services, Inc.
+csc
+
 // cuisinella : 2014-04-03 SALM S.A.S.
 cuisinella
 
@@ -7112,21 +7184,30 @@
 // deals : 2014-05-22 Sand Sunset, LLC
 deals
 
-// degree : 2014-03-06 undefined
+// degree : 2014-03-06 
 degree
 
+// delivery : 2014-09-11 Steel Station, LLC
+delivery
+
+// dell : 2014-10-24 Dell Inc.
+dell
+
 // democrat : 2013-10-24 United TLD Holdco Ltd.
 democrat
 
 // dental : 2014-03-20 Tin Birch, LLC
 dental
 
-// dentist : 2014-03-20 undefined
+// dentist : 2014-03-20 
 dentist
 
 // desi : 2013-11-14 Desi Networks LLC
 desi
 
+// dev : 2014-10-16 Charleston Road Registry Inc.
+dev
+
 // diamonds : 2013-09-22 John Edge, LLC
 diamonds
 
@@ -7148,6 +7229,12 @@
 // dnp : 2013-12-13 Dai Nippon Printing Co., Ltd.
 dnp
 
+// docs : 2014-10-16 Charleston Road Registry Inc.
+docs
+
+// doha : 2014-09-18 Communications Regulatory Authority (CRA)
+doha
+
 // domains : 2013-10-17 Sugar Cross, LLC
 domains
 
@@ -7172,6 +7259,9 @@
 // emerck : 2014-04-03 Merck KGaA
 emerck
 
+// energy : 2014-09-11 Binky Birch, LLC
+energy
+
 // engineer : 2014-03-06 United TLD Holdco Ltd.
 engineer
 
@@ -7217,7 +7307,7 @@
 // fail : 2014-03-06 Atomic Pipe, LLC
 fail
 
-// fan : 2014-03-06 undefined
+// fan : 2014-03-06 
 fan
 
 // farm : 2013-11-07 Just Maple, LLC
@@ -7229,6 +7319,9 @@
 // feedback : 2013-12-19 Top Level Spectrum, Inc.
 feedback
 
+// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+final
+
 // finance : 2014-03-20 Cotton Cypress, LLC
 finance
 
@@ -7253,6 +7346,9 @@
 // florist : 2013-11-07 Half Cypress, LLC
 florist
 
+// flowers : 2014-10-09 Uniregistry, Corp.
+flowers
+
 // flsmidth : 2014-07-24 FLSmidth A/S
 flsmidth
 
@@ -7262,7 +7358,7 @@
 // foo : 2014-01-23 Charleston Road Registry Inc.
 foo
 
-// forsale : 2014-05-22 undefined
+// forsale : 2014-05-22 
 forsale
 
 // foundation : 2013-12-05 John Dale, LLC
@@ -7280,7 +7376,7 @@
 // furniture : 2014-03-20 Lone Fields, LLC
 furniture
 
-// futbol : 2013-09-20 undefined
+// futbol : 2013-09-20 
 futbol
 
 // gal : 2013-11-07 Asociación puntoGAL
@@ -7370,7 +7466,7 @@
 // hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH
 hamburg
 
-// haus : 2013-12-05 undefined
+// haus : 2013-12-05 
 haus
 
 // healthcare : 2014-06-12 Silver Glen, LLC
@@ -7388,6 +7484,9 @@
 // hiphop : 2014-03-06 Uniregistry, Corp.
 hiphop
 
+// hitachi : 2014-10-31 Hitachi, Ltd.
+hitachi
+
 // hiv : 2014-03-13 dotHIV gemeinnuetziger e.V.
 hiv
 
@@ -7415,9 +7514,15 @@
 // how : 2014-01-23 Charleston Road Registry Inc.
 how
 
+// hsbc : 2014-10-24 HSBC Holdings PLC
+hsbc
+
 // ibm : 2014-07-31 International Business Machines Corporation
 ibm
 
+// ice : 2014-10-30 IntercontinentalExchange, Inc.
+ice
+
 // ifm : 2014-01-30 ifm electronic gmbh
 ifm
 
@@ -7466,6 +7571,9 @@
 // istanbul : 2014-08-28 Istanbul Metropolitan Municipality
 istanbul
 
+// itau : 2014-10-02 Itau Unibanco Holding S.A.
+itau
+
 // iwc : 2014-06-23 Richemont DNS Inc.
 iwc
 
@@ -7478,12 +7586,18 @@
 // joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
 joburg
 
+// jprs : 2014-09-18 Japan Registry Services Co., Ltd.
+jprs
+
 // juegos : 2014-03-20 Uniregistry, Corp.
 juegos
 
 // kaufen : 2013-11-07 United TLD Holdco Ltd.
 kaufen
 
+// kddi : 2014-09-12 KDDI CORPORATION
+kddi
+
 // kim : 2013-09-23 Afilias Limited
 kim
 
@@ -7508,10 +7622,13 @@
 // land : 2013-09-10 Pine Moon, LLC
 land
 
+// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico
+lat
+
 // latrobe : 2014-06-16 La Trobe University
 latrobe
 
-// lawyer : 2014-03-20 undefined
+// lawyer : 2014-03-20 
 lawyer
 
 // lds : 2014-03-20 IRI Domain Management, LLC (\
@@ -7523,9 +7640,18 @@
 // leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc
 leclerc
 
+// legal : 2014-10-16 Blue Falls, LLC
+legal
+
 // lgbt : 2014-05-08 Afilias Limited
 lgbt
 
+// liaison : 2014-10-02 Liaison Technologies, Incorporated
+liaison
+
+// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+lidl
+
 // life : 2014-02-06 Trixy Oaks, LLC
 life
 
@@ -7550,6 +7676,9 @@
 // lotto : 2014-04-10 Afilias Limited
 lotto
 
+// ltd : 2014-09-25 Over Corner, LLC
+ltd
+
 // ltda : 2014-04-17 DOMAIN ROBOT SERVICOS DE HOSPEDAGEM NA INTERNET LTDA
 ltda
 
@@ -7562,6 +7691,9 @@
 // madrid : 2014-05-01 Comunidad de Madrid
 madrid
 
+// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF)
+maif
+
 // maison : 2013-12-05 Victor Frostbite, LLC
 maison
 
@@ -7571,12 +7703,15 @@
 // mango : 2013-10-24 PUNTO FA S.L.
 mango
 
-// market : 2014-03-06 undefined
+// market : 2014-03-06 
 market
 
 // marketing : 2013-11-07 Fern Pass, LLC
 marketing
 
+// marriott : 2014-10-09 Marriott Worldwide Corporation
+marriott
+
 // media : 2014-03-06 Grand Glen, LLC
 media
 
@@ -7589,6 +7724,9 @@
 // meme : 2014-01-30 Charleston Road Registry Inc.
 meme
 
+// memorial : 2014-10-16 Dog Beach, LLC
+memorial
+
 // menu : 2013-09-11 Wedding TLD2, LLC
 menu
 
@@ -7607,13 +7745,16 @@
 // monash : 2013-09-30 Monash University
 monash
 
+// money : 2014-10-16 Outer McCook, LLC
+money
+
 // montblanc : 2014-06-23 Richemont DNS Inc.
 montblanc
 
 // mormon : 2013-12-05 IRI Domain Management, LLC (\
 mormon
 
-// mortgage : 2014-03-20 undefined
+// mortgage : 2014-03-20 
 mortgage
 
 // moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
@@ -7625,6 +7766,9 @@
 // mov : 2014-01-30 Charleston Road Registry Inc.
 mov
 
+// movistar : 2014-10-16 Telefónica S.A.
+movistar
+
 // nagoya : 2013-10-24 GMO Registry, Inc.
 nagoya
 
@@ -7658,16 +7802,25 @@
 // nissan : 2014-03-27 NISSAN MOTOR CO., LTD.
 nissan
 
+// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+nowruz
+
 // nra : 2014-05-22 NRA Holdings Company, INC.
 nra
 
 // nrw : 2013-11-21 Minds + Machines GmbH
 nrw
 
+// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
+ntt
+
 // nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications
 nyc
 
-// okinawa : 2013-12-05 BusinessRalliart inc.
+// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA
+obi
+
+// okinawa : 2013-12-05 BusinessRalliart Inc.
 okinawa
 
 // ong : 2014-03-06 Public Interest Registry
@@ -7685,6 +7838,9 @@
 // organic : 2014-03-27 Afilias Limited
 organic
 
+// osaka : 2014-09-04 Interlink Co., Ltd.
+osaka
+
 // otsuka : 2013-10-11 Otsuka Holdings Co., Ltd.
 otsuka
 
@@ -7694,12 +7850,18 @@
 // paris : 2014-01-30 City of Paris
 paris
 
+// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+pars
+
 // partners : 2013-12-05 Magic Glen, LLC
 partners
 
 // parts : 2013-12-05 Sea Goodbye, LLC
 parts
 
+// party : 2014-09-11 Blue Sky Registry Limited
+party
+
 // pharmacy : 2014-06-19 National Association of Boards of Pharmacy
 pharmacy
 
@@ -7715,6 +7877,9 @@
 // physio : 2014-05-01 PhysBiz Pty Ltd
 physio
 
+// piaget : 2014-10-16 Richemont DNS Inc.
+piaget
+
 // pics : 2013-11-14 Uniregistry, Corp.
 pics
 
@@ -7742,6 +7907,9 @@
 // poker : 2014-07-03 Afilias Domains No. 5 Limited
 poker
 
+// porn : 2014-10-16 ICM Registry PN LLC
+porn
+
 // praxi : 2013-12-05 Praxi S.p.A.
 praxi
 
@@ -7781,6 +7949,9 @@
 // red : 2013-11-07 Afilias Limited
 red
 
+// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd.
+redstone
+
 // rehab : 2014-03-06 United TLD Holdco Ltd.
 rehab
 
@@ -7790,6 +7961,9 @@
 // reisen : 2014-03-06 New Cypress, LLC
 reisen
 
+// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc.
+reit
+
 // ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd.
 ren
 
@@ -7811,7 +7985,7 @@
 // restaurant : 2014-07-03 Snow Avenue, LLC
 restaurant
 
-// reviews : 2013-09-13 undefined
+// reviews : 2013-09-13 
 reviews
 
 // rich : 2013-11-21 I-Registry Ltd.
@@ -7823,7 +7997,7 @@
 // rip : 2014-07-10 United TLD Holdco Ltd.
 rip
 
-// rocks : 2013-11-14 undefined
+// rocks : 2013-11-14 
 rocks
 
 // rodeo : 2013-12-19 Top Level Domain Holdings Limited
@@ -7835,21 +8009,30 @@
 // ruhr : 2013-10-02 regiodot GmbH & Co. KG
 ruhr
 
-// ryukyu : 2014-01-09 BusinessRalliart inc.
+// ryukyu : 2014-01-09 BusinessRalliart Inc.
 ryukyu
 
 // saarland : 2013-12-12 dotSaarland GmbH
 saarland
 
+// sale : 2014-10-16 Half Bloom, LLC
+sale
+
 // samsung : 2014-04-03 SAMSUNG SDS CO., LTD
 samsung
 
+// sanofi : 2014-10-09 Sanofi
+sanofi
+
 // sap : 2014-03-27 SAP AG
 sap
 
 // sarl : 2014-07-03 Delta Orchard, LLC
 sarl
 
+// saxo : 2014-10-31 Saxo Bank A/S
+saxo
+
 // sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ)
 sca
 
@@ -7865,12 +8048,24 @@
 // schule : 2014-03-06 Outer Moon, LLC
 schule
 
+// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+schwarz
+
+// science : 2014-09-11 dot Science Limited
+science
+
+// scor : 2014-10-31 SCOR SE
+scor
+
 // scot : 2014-01-23 Dot Scot Registry Limited
 scot
 
 // seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal)
 seat
 
+// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A.
+sener
+
 // services : 2014-02-27 Fox Castle, LLC
 services
 
@@ -7883,6 +8078,9 @@
 // sharp : 2014-05-01 Sharp Corporation
 sharp
 
+// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+shia
+
 // shiksha : 2013-11-14 Afilias Limited
 shiksha
 
@@ -7901,7 +8099,7 @@
 // social : 2013-11-07 United TLD Holdco Ltd.
 social
 
-// software : 2014-03-20 undefined
+// software : 2014-03-20 
 software
 
 // sohu : 2013-12-19 Sohu.com Limited
@@ -7922,6 +8120,12 @@
 // spiegel : 2014-02-05 SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG
 spiegel
 
+// stc : 2014-10-09 Saudi Telecom Company
+stc
+
+// stcgroup : 2014-10-09 Saudi Telecom Company
+stcgroup
+
 // supplies : 2013-12-19 Atomic Fields, LLC
 supplies
 
@@ -7940,6 +8144,12 @@
 // suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION
 suzuki
 
+// swiss : 2014-10-16 Swiss Confederation
+swiss
+
+// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet
+sydney
+
 // systems : 2013-11-07 Dash Cypress, LLC
 systems
 
@@ -7955,9 +8165,15 @@
 // tax : 2014-03-20 Storm Orchard, LLC
 tax
 
+// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+tci
+
 // technology : 2013-09-13 Auburn Falls
 technology
 
+// telefonica : 2014-10-16 Telefónica S.A.
+telefonica
+
 // temasek : 2014-08-07 Temasek Holdings (Private) Limited
 temasek
 
@@ -7997,6 +8213,9 @@
 // training : 2013-11-07 Wild Willow, LLC
 training
 
+// trust : 2014-10-16 
+trust
+
 // tui : 2014-07-03 TUI AG
 tui
 
@@ -8021,18 +8240,30 @@
 // versicherung : 2014-03-20 dotversicherung-registry GmbH
 versicherung
 
-// vet : 2014-03-06 undefined
+// vet : 2014-03-06 
 vet
 
 // viajes : 2013-10-17 Black Madison, LLC
 viajes
 
+// video : 2014-10-16 Lone Tigers, LLC
+video
+
 // villas : 2013-12-05 New Sky, LLC
 villas
 
+// virgin : 2014-09-25 Virgin Enterprises Limited
+virgin
+
 // vision : 2013-12-05 Koko Station, LLC
 vision
 
+// vista : 2014-09-18 Vistaprint Limited
+vista
+
+// vistaprint : 2014-09-18 Vistaprint Limited
+vistaprint
+
 // vlaanderen : 2014-02-06 DNS.be vzw
 vlaanderen
 
@@ -8102,6 +8333,9 @@
 // wtf : 2014-03-06 Hidden Way, LLC
 wtf
 
+// xerox : 2014-10-24 Xerox DNHC LLC
+xerox
+
 // xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd.
 佛山
 
@@ -8195,6 +8429,9 @@
 // xn--mgbab2bd : 2013-10-31 CORE Association
 بازار
 
+// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+همراه
+
 // xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd.
 政府
 
@@ -8234,6 +8471,9 @@
 // xn--vhquv : 2013-08-27 Dash McCook, LLC
 企业
 
+// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd.
+信息
+
 // xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd.
 广东
 
@@ -8706,6 +8946,7 @@
 // Google, Inc.
 // Submitted by Eduardo Vela <evn@google.com> 2012-10-24
 appspot.com
+blogspot.ae
 blogspot.be
 blogspot.bj
 blogspot.ca
@@ -8720,6 +8961,7 @@
 blogspot.com.au
 blogspot.com.br
 blogspot.com.es
+blogspot.com.tr
 blogspot.cv
 blogspot.cz
 blogspot.de
@@ -8741,6 +8983,7 @@
 blogspot.pt
 blogspot.re
 blogspot.ro
+blogspot.ru
 blogspot.se
 blogspot.sg
 blogspot.sk
@@ -8793,6 +9036,14 @@
 // Submitted by Duarte Santos <domain-admin@outsystemscloud.com> 2014-03-11
 outsystemscloud.com
 
+// .pl domains (grandfathered)
+art.pl
+gliwice.pl
+krakow.pl
+poznan.pl
+wroc.pl
+zakopane.pl
+
 // Red Hat, Inc. OpenShift : https://openshift.redhat.com/
 // Submitted by Tim Kramer <tkramer@rhcloud.com> 2012-10-24
 rhcloud.com
@@ -8805,6 +9056,13 @@
 // Submitted by registry <lendl@nic.at> 2008-06-09
 priv.at
 
+// TASK geographical domains (www.task.gda.pl/uslugi/dns)
+gda.pl
+gdansk.pl
+gdynia.pl
+med.pl
+sopot.pl
+
 // Yola : https://www.yola.com/
 // Submitted by Stefano Rivera <stefano@yola.com> 2014-07-09
 yolasite.com
diff --git a/net/base/registry_controlled_domains/effective_tld_names.gperf b/net/base/registry_controlled_domains/effective_tld_names.gperf
index 1ef69e4..b3b6afd 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.gperf
+++ b/net/base/registry_controlled_domains/effective_tld_names.gperf
@@ -19,7 +19,6 @@
 4.bg, 0
 5.bg, 0
 6.bg, 0
-6bone.pl, 0
 7.bg, 0
 8.bg, 0
 9.bg, 0
@@ -31,6 +30,7 @@
 aarborte.no, 0
 ab.ca, 0
 abashiri.hokkaido.jp, 0
+abb, 0
 abbott, 0
 abeno.osaka.jp, 0
 abiko.chiba.jp, 0
@@ -88,6 +88,7 @@
 ad.jp, 0
 adachi.tokyo.jp, 0
 adm.br, 0
+adult, 0
 adult.ht, 0
 adv.br, 0
 adygeya.ru, 0
@@ -103,6 +104,7 @@
 aeroport.fr, 0
 af, 0
 afjord.no, 0
+afl, 0
 africa, 0
 africa.com, 4
 ag, 0
@@ -138,6 +140,7 @@
 airguard.museum, 0
 airline.aero, 0
 airport.aero, 0
+airtel, 0
 airtraffic.aero, 0
 aisai.aichi.jp, 0
 aisho.shiga.jp, 0
@@ -276,7 +279,7 @@
 art.dz, 0
 art.ht, 0
 art.museum, 0
-art.pl, 0
+art.pl, 4
 art.sn, 0
 artanddesign.museum, 0
 artcenter.museum, 0
@@ -421,6 +424,7 @@
 band, 0
 bandai.fukushima.jp, 0
 bando.ibaraki.jp, 0
+bank, 0
 bar, 0
 bar.pro, 0
 barcelona, 0
@@ -447,6 +451,7 @@
 bayern, 0
 bb, 0
 bbs.tr, 0
+bbva, 0
 bc.ca, 0
 bcn, 0
 bd, 2
@@ -541,6 +546,7 @@
 blogdns.net, 4
 blogdns.org, 4
 blogsite.org, 4
+blogspot.ae, 4
 blogspot.be, 4
 blogspot.bj, 4
 blogspot.ca, 4
@@ -555,6 +561,7 @@
 blogspot.com.au, 4
 blogspot.com.br, 4
 blogspot.com.es, 4
+blogspot.com.tr, 4
 blogspot.cv, 4
 blogspot.cz, 4
 blogspot.de, 4
@@ -576,6 +583,7 @@
 blogspot.pt, 4
 blogspot.re, 4
 blogspot.ro, 4
+blogspot.ru, 4
 blogspot.se, 4
 blogspot.sg, 4
 blogspot.sk, 4
@@ -585,6 +593,7 @@
 blue, 0
 bm, 0
 bmd.br, 0
+bms, 0
 bmw, 0
 bn, 2
 bn.it, 0
@@ -601,6 +610,7 @@
 bologna.it, 0
 bolt.hu, 0
 bolzano.it, 0
+bom, 0
 bomlo.no, 0
 bond, 0
 bonn.museum, 0
@@ -698,6 +708,7 @@
 can.museum, 0
 canada.museum, 0
 cancerresearch, 0
+canon, 0
 capebreton.museum, 0
 capetown, 0
 capital, 0
@@ -849,6 +860,7 @@
 chiyoda.gunma.jp, 0
 chiyoda.tokyo.jp, 0
 chizu.tottori.jp, 0
+chloe, 0
 chocolate.museum, 0
 chofu.tokyo.jp, 0
 chonan.chiba.jp, 0
@@ -973,6 +985,7 @@
 co.uz, 0
 co.ve, 0
 co.vi, 0
+coach, 0
 coal.museum, 0
 coastaldefence.museum, 0
 codes, 0
@@ -1155,6 +1168,7 @@
 coop.tt, 0
 copenhagen.museum, 0
 corporation.museum, 0
+corsica, 0
 corvette.museum, 0
 cosenza.it, 0
 costume.museum, 0
@@ -1175,11 +1189,14 @@
 cremona.it, 0
 crew.aero, 0
 cri.nz, 0
+cricket, 0
 crimea.ua, 0
 crotone.it, 0
+crown, 0
 crs, 0
 cruises, 0
 cs.it, 0
+csc, 0
 ct.it, 0
 ct.us, 0
 cu, 0
@@ -1235,6 +1252,8 @@
 defense.tn, 0
 degree, 0
 delaware.museum, 0
+delivery, 0
+dell, 0
 dell-ogliastra.it, 0
 dellogliastra.it, 0
 delmenhorst.museum, 0
@@ -1249,6 +1268,7 @@
 design.aero, 0
 design.museum, 0
 detroit.museum, 0
+dev, 0
 dgca.aero, 0
 diamonds, 0
 dielddanuorri.no, 0
@@ -1277,9 +1297,11 @@
 dnsdojo.net, 4
 dnsdojo.org, 4
 do, 0
+docs, 0
 does-it.net, 4
 doesntexist.com, 4
 doesntexist.org, 4
+doha, 0
 dolls.museum, 0
 domains, 0
 dominic.ua, 0
@@ -1509,6 +1531,7 @@
 endofinternet.org, 4
 endoftheinternet.org, 4
 enebakk.no, 0
+energy, 0
 eng.br, 0
 eng.pro, 0
 engerdal.no, 0
@@ -1616,6 +1639,7 @@
 film.museum, 0
 fin.ec, 0
 fin.tn, 0
+final, 0
 finance, 0
 financial, 0
 fineart.museum, 0
@@ -1655,6 +1679,7 @@
 florida.museum, 0
 florist, 0
 floro.no, 0
+flowers, 0
 flsmidth, 0
 fly, 0
 flynnhub.com, 4
@@ -1867,10 +1892,10 @@
 gc.ca, 0
 gd, 0
 gd.cn, 0
-gda.pl, 0
-gdansk.pl, 0
+gda.pl, 4
+gdansk.pl, 4
 gdn, 0
-gdynia.pl, 0
+gdynia.pl, 4
 ge, 0
 ge.it, 0
 geek.nz, 0
@@ -1920,7 +1945,7 @@
 glass.museum, 0
 gle, 0
 gliding.aero, 0
-gliwice.pl, 0
+gliwice.pl, 4
 global, 0
 global.prod.fastly.net, 4
 global.ssl.fastly.net, 4
@@ -2360,6 +2385,7 @@
 history.museum, 0
 historyofscience.museum, 0
 hita.oita.jp, 0
+hitachi, 0
 hitachi.ibaraki.jp, 0
 hitachinaka.ibaraki.jp, 0
 hitachiomiya.ibaraki.jp, 0
@@ -2432,6 +2458,7 @@
 hoylandet.no, 0
 hr, 0
 hs.kr, 0
+hsbc, 0
 ht, 0
 hu, 0
 hu.com, 4
@@ -2456,6 +2483,7 @@
 ibestad.no, 0
 ibigawa.gifu.jp, 0
 ibm, 0
+ice, 0
 ichiba.tokushima.jp, 0
 ichihara.chiba.jp, 0
 ichikai.tochigi.jp, 0
@@ -2620,7 +2648,6 @@
 iq, 0
 ir, 0
 iraq.museum, 0
-irc.pl, 0
 iris.arpa, 0
 irish, 0
 irkutsk.ru, 0
@@ -2737,6 +2764,7 @@
 itakura.gunma.jp, 0
 itami.hyogo.jp, 0
 itano.tokushima.jp, 0
+itau, 0
 itayanagi.aomori.jp, 0
 ito.shizuoka.jp, 0
 itoigawa.niigata.jp, 0
@@ -2821,6 +2849,7 @@
 jp, 0
 jp.net, 4
 jpn.com, 4
+jprs, 0
 js.cn, 0
 judaica.museum, 0
 judygarland.museum, 0
@@ -3042,6 +3071,7 @@
 kazo.saitama.jp, 0
 kazuno.akita.jp, 0
 kchr.ru, 0
+kddi, 0
 ke, 2
 keisen.fukuoka.jp, 0
 kembuchi.hokkaido.jp, 0
@@ -3203,7 +3233,7 @@
 kr.ua, 0
 kraanghke.no, 0
 kragero.no, 0
-krakow.pl, 0
+krakow.pl, 4
 krasnoyarsk.ru, 0
 krd, 0
 kred, 0
@@ -3315,6 +3345,7 @@
 larsson.museum, 0
 larvik.no, 0
 laspezia.it, 0
+lat, 0
 latina.it, 0
 latrobe, 0
 lavagis.no, 0
@@ -3338,6 +3369,7 @@
 lecco.it, 0
 leclerc, 0
 leg.br, 0
+legal, 0
 legnica.pl, 0
 leikanger.no, 0
 leirfjord.no, 0
@@ -3357,6 +3389,7 @@
 lgbt, 0
 li, 0
 li.it, 0
+liaison, 0
 lib.ak.us, 0
 lib.al.us, 0
 lib.ar.us, 0
@@ -3412,6 +3445,7 @@
 lib.wa.us, 0
 lib.wi.us, 0
 lib.wy.us, 0
+lidl, 0
 lier.no, 0
 lierne.no, 0
 life, 0
@@ -3463,6 +3497,7 @@
 lt, 0
 lt.it, 0
 lt.ua, 0
+ltd, 0
 ltd.co.im, 0
 ltd.gi, 0
 ltd.lk, 0
@@ -3505,6 +3540,7 @@
 magazine.aero, 0
 magnitka.ru, 0
 maibara.shiga.jp, 0
+maif, 0
 mail.pl, 0
 maintenance.aero, 0
 maison, 0
@@ -3542,6 +3578,7 @@
 marketing, 0
 marketplace.aero, 0
 marnardal.no, 0
+marriott, 0
 marugame.kagawa.jp, 0
 marumori.miyagi.jp, 0
 maryland.museum, 0
@@ -3578,7 +3615,6 @@
 mazury.pl, 0
 mb.ca, 0
 mb.it, 0
-mbone.pl, 0
 mc, 0
 mc.it, 0
 md, 0
@@ -3596,7 +3632,7 @@
 med.ly, 0
 med.om, 0
 med.pa, 0
-med.pl, 0
+med.pl, 4
 med.pro, 0
 med.sa, 0
 med.sd, 0
@@ -3622,6 +3658,7 @@
 melhus.no, 0
 meloy.no, 0
 meme, 0
+memorial, 0
 memorial.museum, 0
 menu, 0
 meraker.no, 0
@@ -3840,6 +3877,7 @@
 moma.museum, 0
 mombetsu.hokkaido.jp, 0
 monash, 0
+money, 0
 money.museum, 0
 monmouth.museum, 0
 montblanc, 0
@@ -3867,7 +3905,6 @@
 moseushi.hokkaido.jp, 0
 mosjoen.no, 0
 moskenes.no, 0
-mosreg.ru, 0
 moss.no, 0
 mosvik.no, 0
 motegi.tochigi.jp, 0
@@ -3877,6 +3914,7 @@
 motosu.gifu.jp, 0
 motoyama.kochi.jp, 0
 mov, 0
+movistar, 0
 mp, 0
 mp.br, 0
 mq, 0
@@ -4228,7 +4266,6 @@
 ngo, 0
 ngo.lk, 0
 ngo.ph, 0
-ngo.pl, 0
 nh.us, 0
 nhk, 0
 nhs.uk, 0
@@ -4340,6 +4377,7 @@
 novara.it, 0
 novosibirsk.ru, 0
 nowaruda.pl, 0
+nowruz, 0
 nozawaonsen.nagano.jp, 0
 np, 2
 nr, 0
@@ -4357,6 +4395,7 @@
 nt.no, 0
 nt.ro, 0
 ntr.br, 0
+ntt, 0
 nu, 0
 nu.ca, 0
 nu.it, 0
@@ -4383,6 +4422,7 @@
 obama.fukui.jp, 0
 obama.nagasaki.jp, 0
 obanazawa.yamagata.jp, 0
+obi, 0
 obihiro.hokkaido.jp, 0
 obira.hokkaido.jp, 0
 obu.aichi.jp, 0
@@ -4672,6 +4712,7 @@
 oryol.ru, 0
 os.hedmark.no, 0
 os.hordaland.no, 0
+osaka, 0
 osaka.jp, 0
 osakasayama.osaka.jp, 0
 osaki.miyagi.jp, 0
@@ -4757,9 +4798,11 @@
 parliament.nz, 0
 parma.it, 0
 paroch.k12.ma.us, 0
+pars, 0
 parti.se, 0
 partners, 0
 parts, 0
+party, 0
 pasadena.museum, 0
 passenger-association.aero, 0
 pavia.it, 0
@@ -4802,6 +4845,7 @@
 physio, 0
 pi.it, 0
 piacenza.it, 0
+piaget, 0
 pics, 0
 pictet, 0
 pictures, 0
@@ -4851,6 +4895,7 @@
 pomorskie.pl, 0
 pomorze.pl, 0
 pordenone.it, 0
+porn, 0
 porsanger.no, 0
 porsangu.no, 0
 porsgrunn.no, 0
@@ -4862,7 +4907,7 @@
 posts-and-telecommunications.museum, 0
 potenza.it, 0
 powiat.pl, 0
-poznan.pl, 0
+poznan.pl, 4
 pp.az, 0
 pp.ru, 0
 pp.se, 0
@@ -4989,6 +5034,7 @@
 recreation.aero, 0
 red, 0
 red.sv, 0
+redstone, 0
 reggio-calabria.it, 0
 reggio-emilia.it, 0
 reggiocalabria.it, 0
@@ -4996,6 +5042,7 @@
 rehab, 0
 reise, 0
 reisen, 0
+reit, 0
 reklam.hu, 0
 rel.ht, 0
 rel.pl, 0
@@ -5158,6 +5205,7 @@
 sakyo.kyoto.jp, 0
 salangen.no, 0
 salat.no, 0
+sale, 0
 salem.museum, 0
 salerno.it, 0
 saltdal.no, 0
@@ -5184,6 +5232,7 @@
 sannan.hyogo.jp, 0
 sannohe.aomori.jp, 0
 sano.tochigi.jp, 0
+sanofi, 0
 sanok.pl, 0
 santabarbara.museum, 0
 santacruz.museum, 0
@@ -5214,6 +5263,7 @@
 savannahga.museum, 0
 saves-the-whales.com, 4
 savona.it, 0
+saxo, 0
 sayama.osaka.jp, 0
 sayama.saitama.jp, 0
 sayo.hyogo.jp, 0
@@ -5246,8 +5296,10 @@
 school.na, 0
 school.nz, 0
 schule, 0
+schwarz, 0
 schweiz.museum, 0
 sci.eg, 0
+science, 0
 science-fiction.museum, 0
 science.museum, 0
 scienceandhistory.museum, 0
@@ -5258,6 +5310,7 @@
 sciences.museum, 0
 sciencesnaturelles.museum, 0
 scientist.aero, 0
+scor, 0
 scot, 0
 scotland.museum, 0
 scrapper-site.net, 4
@@ -5297,6 +5350,7 @@
 semboku.akita.jp, 0
 semine.miyagi.jp, 0
 sendai.jp, 2
+sener, 0
 sennan.osaka.jp, 0
 seoul.kr, 0
 sera.hiroshima.jp, 0
@@ -5331,6 +5385,7 @@
 sharp, 0
 shell.museum, 0
 sherbrooke.museum, 0
+shia, 0
 shibata.miyagi.jp, 0
 shibata.niigata.jp, 0
 shibecha.hokkaido.jp, 0
@@ -5435,7 +5490,6 @@
 sic.it, 0
 sicilia.it, 0
 sicily.it, 0
-siedlce.pl, 0
 siellak.no, 0
 siena.it, 0
 sigdal.no, 0
@@ -5514,7 +5568,7 @@
 songdalen.no, 0
 soni.nara.jp, 0
 soo.kagoshima.jp, 0
-sopot.pl, 0
+sopot.pl, 4
 sor-aurdal.no, 0
 sor-fron.no, 0
 sor-odal.no, 0
@@ -5565,6 +5619,8 @@
 stavanger.no, 0
 stavern.no, 0
 stavropol.ru, 0
+stc, 0
+stcgroup, 0
 steam.museum, 0
 steiermark.museum, 0
 steigen.no, 0
@@ -5640,9 +5696,11 @@
 swidnica.pl, 0
 swiebodzin.pl, 0
 swinoujscie.pl, 0
+swiss, 0
 sx, 0
 sx.cn, 0
 sy, 0
+sydney, 0
 sydney.museum, 0
 sykkylven.no, 0
 systems, 0
@@ -5758,6 +5816,7 @@
 taxi.aero, 0
 taxi.br, 0
 tc, 0
+tci, 0
 tcm.museum, 0
 td, 0
 te.it, 0
@@ -5769,6 +5828,7 @@
 tel, 0
 tel.tr, 0
 teledata.mz, 1
+telefonica, 0
 telekommunikation.museum, 0
 television.museum, 0
 temasek, 0
@@ -5977,6 +6037,7 @@
 tromsa.no, 0
 tromso.no, 0
 trondheim.no, 0
+trust, 0
 trust.museum, 0
 trustee.museum, 0
 trysil.no, 0
@@ -6127,7 +6188,6 @@
 uscountryestate.museum, 0
 usculture.museum, 0
 usdecorativearts.museum, 0
-usenet.pl, 0
 usgarden.museum, 0
 ushiku.ibaraki.jp, 0
 ushistory.museum, 0
@@ -6235,6 +6295,7 @@
 vic.edu.au, 0
 vic.gov.au, 0
 vicenza.it, 0
+video, 0
 video.hu, 0
 vik.no, 0
 viking.museum, 0
@@ -6244,10 +6305,13 @@
 vindafjord.no, 0
 vinnica.ua, 0
 vinnytsia.ua, 0
+virgin, 0
 virginia.museum, 0
 virtual.museum, 0
 virtuel.museum, 0
 vision, 0
+vista, 0
+vistaprint, 0
 viterbo.it, 0
 vlaanderen, 0
 vlaanderen.museum, 0
@@ -6360,7 +6424,7 @@
 world, 0
 worse-than.tv, 4
 writesthisblog.com, 4
-wroc.pl, 0
+wroc.pl, 4
 wroclaw.pl, 0
 ws, 0
 ws.na, 0
@@ -6372,27 +6436,45 @@
 wy.us, 0
 x.bg, 0
 x.se, 0
+xerox, 0
 xj.cn, 0
+xn--0trq7p7nn.jp, 0
+xn--1ctwo.jp, 0
+xn--1lqs03n.jp, 0
+xn--1lqs71d.jp, 0
 xn--1qqw23a, 0
+xn--2m4a15e.jp, 0
 xn--30rr7y, 0
+xn--32vp30h.jp, 0
 xn--3bst00m, 0
 xn--3ds443g, 0
 xn--3e0b707e, 0
 xn--45brj9c, 0
 xn--45q11c, 0
 xn--4gbrim, 0
+xn--4it168d.jp, 0
+xn--4it797k.jp, 0
+xn--4pvxs.jp, 0
 xn--54b7fta0cc, 0
 xn--55qw42g, 0
 xn--55qx5d, 0
 xn--55qx5d.cn, 0
 xn--55qx5d.hk, 0
+xn--5js045d.jp, 0
+xn--5rtp49c.jp, 0
+xn--5rtq34k.jp, 0
+xn--6btw5a.jp, 0
 xn--6frz82g, 0
+xn--6orx2r.jp, 0
 xn--6qq986b3xl, 0
+xn--7t0a264c.jp, 0
 xn--80adxhks, 0
 xn--80ao21a, 0
 xn--80asehdb, 0
 xn--80aswg, 0
 xn--80au.xn--90a3ac, 0
+xn--8ltr62k.jp, 0
+xn--8pvr4u.jp, 0
 xn--90a3ac, 0
 xn--90azh.xn--90a3ac, 0
 xn--9dbhblg6di.museum, 0
@@ -6423,6 +6505,7 @@
 xn--btsfjord-9za.no, 0
 xn--c1avg, 0
 xn--c1avg.xn--90a3ac, 0
+xn--c3s14m.jp, 0
 xn--cg4bki, 0
 xn--ciqpn.hk, 0
 xn--clchc0ea0b2g2a9gcd, 0
@@ -6434,12 +6517,19 @@
 xn--czrw28b.tw, 0
 xn--d1acj3b, 0
 xn--d1at.xn--90a3ac, 0
+xn--d5qv7z876c.jp, 0
 xn--davvenjrga-y4a.no, 0
+xn--djrs72d6uy.jp, 0
+xn--djty4k.jp, 0
 xn--dnna-gra.no, 0
 xn--drbak-wua.no, 0
 xn--dyry-ira.no, 0
+xn--efvn9s.jp, 0
 xn--efvy88h, 0
+xn--ehqz56n.jp, 0
+xn--elqq16h.jp, 0
 xn--eveni-0qa01ga.no, 0
+xn--f6qx53a.jp, 0
 xn--finny-yua.no, 0
 xn--fiq228c5hs, 0
 xn--fiq64b, 0
@@ -6488,9 +6578,15 @@
 xn--j6w193g, 0
 xn--jlster-bya.no, 0
 xn--jrpeland-54a.no, 0
+xn--k7yn95e.jp, 0
 xn--karmy-yua.no, 0
+xn--kbrq7o.jp, 0
 xn--kfjord-iua.no, 0
 xn--klbu-woa.no, 0
+xn--klt787d.jp, 0
+xn--kltp7d.jp, 0
+xn--kltx9a.jp, 0
+xn--klty5x.jp, 0
 xn--koluokta-7ya57h.no, 0
 xn--kprw13d, 0
 xn--kpry57d, 0
@@ -6540,10 +6636,12 @@
 xn--mgberp4a5d4ar, 0
 xn--mgbqly7c0a67fbc, 0
 xn--mgbqly7cvafr, 0
+xn--mgbt3dhd, 0
 xn--mgbtf8fl, 0
 xn--mgbx4cd0ab, 0
 xn--mjndalen-64a.no, 0
 xn--mk0axi.hk, 0
+xn--mkru45i.jp, 0
 xn--mlatvuopmi-s4a.no, 0
 xn--mli-tla.no, 0
 xn--mlselv-iua.no, 0
@@ -6557,12 +6655,15 @@
 xn--mxtq1m, 0
 xn--mxtq1m.hk, 0
 xn--ngbc5azd, 0
+xn--nit225k.jp, 0
 xn--nmesjevuemie-tcba.no, 0
 xn--nnx388a, 0
 xn--node, 0
 xn--nqv7f, 0
 xn--nqv7fs00ema, 0
 xn--nry-yla5g.no, 0
+xn--ntso0iqx3a.jp, 0
+xn--ntsq17g.jp, 0
 xn--nttery-byae.no, 0
 xn--nvuotna-hwa.no, 0
 xn--o1ac.xn--90a3ac, 0
@@ -6579,8 +6680,10 @@
 xn--p1ai, 0
 xn--pgbs0dh, 0
 xn--porsgu-sta26f.no, 0
+xn--pssu33l.jp, 0
 xn--q9jyb4c, 0
 xn--qcka1pmc, 0
+xn--qqqt11m.jp, 0
 xn--rady-ira.no, 0
 xn--rdal-poa.no, 0
 xn--rde-ula.no, 0
@@ -6589,11 +6692,15 @@
 xn--rhkkervju-01af.no, 0
 xn--rholt-mra.no, 0
 xn--rhqv96g, 0
+xn--rht27z.jp, 0
+xn--rht3d.jp, 0
+xn--rht61e.jp, 0
 xn--risa-5na.no, 0
 xn--risr-ira.no, 0
 xn--rland-uua.no, 0
 xn--rlingen-mxa.no, 0
 xn--rmskog-bya.no, 0
+xn--rny31h.jp, 0
 xn--rros-gra.no, 0
 xn--rskog-uua.no, 0
 xn--rst-0na.no, 0
@@ -6633,6 +6740,7 @@
 xn--tjme-hra.no, 0
 xn--tn0ag.hk, 0
 xn--tnsberg-q1a.no, 0
+xn--tor131o.jp, 0
 xn--trany-yua.no, 0
 xn--trgstad-r1a.no, 0
 xn--trna-woa.no, 0
@@ -6641,8 +6749,11 @@
 xn--uc0atv.hk, 0
 xn--uc0atv.tw, 0
 xn--uc0ay4a.hk, 0
+xn--uist22h.jp, 0
+xn--uisz3g.jp, 0
 xn--unjrga-rta.no, 0
 xn--unup4y, 0
+xn--uuwu58a.jp, 0
 xn--vads-jra.no, 0
 xn--vard-jra.no, 0
 xn--vegrshei-c0a.no, 0
@@ -6652,12 +6763,14 @@
 xn--vg-yiab.no, 0
 xn--vgan-qoa.no, 0
 xn--vgsy-qoa0j.no, 0
+xn--vgu402c.jp, 0
 xn--vhquv, 0
 xn--vler-qoa.hedmark.no, 0
 xn--vler-qoa.xn--stfold-9xa.no, 0
 xn--vre-eiker-k8a.no, 0
 xn--vrggt-xqad.no, 0
 xn--vry-yla5g.no, 0
+xn--vuq861b, 0
 xn--wcvs22d.hk, 0
 xn--wgbh1c, 0
 xn--wgbl6a, 0
@@ -6669,6 +6782,7 @@
 xn--ygarden-p1a.no, 0
 xn--ygbi2ammx, 0
 xn--ystre-slidre-ujb.no, 0
+xn--zbx025d.jp, 0
 xn--zf0ao64a.tw, 0
 xn--zf0avx.hk, 0
 xn--zfr164b, 0
@@ -6805,7 +6919,7 @@
 za.org, 4
 zachpomor.pl, 0
 zagan.pl, 0
-zakopane.pl, 0
+zakopane.pl, 4
 zama.kanagawa.jp, 0
 zamami.okinawa.jp, 0
 zao.miyagi.jp, 0
diff --git a/net/base/request_priority.h b/net/base/request_priority.h
index e663610..dcf7793 100644
--- a/net/base/request_priority.h
+++ b/net/base/request_priority.h
@@ -11,6 +11,10 @@
 
 // Prioritization used in various parts of the networking code such
 // as connection prioritization and resource loading prioritization.
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net
+// GENERATED_JAVA_CLASS_NAME_OVERRIDE: RequestPriority
+// GENERATED_JAVA_PREFIX_TO_STRIP:
 enum RequestPriority {
   IDLE = 0,
   MINIMUM_PRIORITY = IDLE,
diff --git a/net/cert/ct_known_logs_static.h b/net/cert/ct_known_logs_static.h
index 7171271..a99944d 100644
--- a/net/cert/ct_known_logs_static.h
+++ b/net/cert/ct_known_logs_static.h
@@ -27,9 +27,17 @@
     "\x6b\xbd\x27\xbc\x96\x21\x3e\x34\xf5\x87\x76\x31\xb1\x7f\x1d\xc9\x85"
     "\x3b\x0d\xf7\x1f\x3f\xe9",
     "Google 'Aviator' log"
+  },
+  {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
+    "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xa2\xf7\xed\x13\xe1\xd3\x5c"
+    "\x02\x08\xc4\x8e\x8b\x9b\x8b\x3b\x39\x68\xc7\x92\x6a\x38\xa1\x4f\x23"
+    "\xc5\xa5\x6f\x6f\xd7\x65\x81\xf8\xc1\x9b\xf4\x9f\xa9\x8b\x45\xf4\xb9"
+    "\x4e\x1b\xc9\xa2\x69\x17\xa5\x78\x87\xd9\xce\x88\x6f\x41\x03\xbb\xa3"
+    "\x2a\xe3\x77\x97\x8d\x78",
+    "SSLWatcher.com CT log 'alpha'"
   }
 };
 
-const size_t kNumKnownCTLogs = 2;
+const size_t kNumKnownCTLogs = 3;
 
 #endif  // NET_CERT_CT_KNOWN_LOGS_STATIC_H_
diff --git a/net/cert/ct_log_verifier_openssl.cc b/net/cert/ct_log_verifier_openssl.cc
index 884ae8a..55bc3e1 100644
--- a/net/cert/ct_log_verifier_openssl.cc
+++ b/net/cert/ct_log_verifier_openssl.cc
@@ -56,13 +56,10 @@
                          const base::StringPiece& description) {
   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
 
-  crypto::ScopedBIO bio(
-      BIO_new_mem_buf(const_cast<char*>(public_key.data()), public_key.size()));
-  if (!bio.get())
-    return false;
-
-  public_key_ = d2i_PUBKEY_bio(bio.get(), NULL);
-  if (!public_key_)
+  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(public_key.data());
+  const uint8_t* end = ptr + public_key.size();
+  public_key_ = d2i_PUBKEY(nullptr, &ptr, public_key.size());
+  if (!public_key_ || ptr != end)
     return false;
 
   key_id_ = crypto::SHA256HashString(public_key);
diff --git a/net/cert/ct_log_verifier_unittest.cc b/net/cert/ct_log_verifier_unittest.cc
index 373f69e..e8d1bc4 100644
--- a/net/cert/ct_log_verifier_unittest.cc
+++ b/net/cert/ct_log_verifier_unittest.cc
@@ -89,4 +89,13 @@
   ASSERT_FALSE(log_->SetSignedTreeHead(sth.Pass()));
 }
 
+// Test that excess data after the public key is rejected.
+TEST_F(CTLogVerifierTest, ExcessDataInPublicKey) {
+  std::string key = ct::GetTestPublicKey();
+  key += "extra";
+
+  scoped_ptr<CTLogVerifier> log = CTLogVerifier::Create(key, "testlog");
+  EXPECT_FALSE(log);
+}
+
 }  // namespace net
diff --git a/net/data/url_request_unittest/simple.html b/net/data/url_request_unittest/simple.html
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/net/data/url_request_unittest/simple.html
@@ -0,0 +1 @@
+hello
diff --git a/net/data/url_request_unittest/simple.html.mock-http-headers b/net/data/url_request_unittest/simple.html.mock-http-headers
new file mode 100644
index 0000000..be8f7b5
--- /dev/null
+++ b/net/data/url_request_unittest/simple.html.mock-http-headers
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Content-Length: 5
diff --git a/net/data/url_request_unittest/two-content-lengths.html b/net/data/url_request_unittest/two-content-lengths.html
new file mode 100644
index 0000000..364322d
--- /dev/null
+++ b/net/data/url_request_unittest/two-content-lengths.html
@@ -0,0 +1 @@
+This file is boring; all the action's in the .mock-http-headers.
diff --git a/net/data/url_request_unittest/two-content-lengths.html.mock-http-headers b/net/data/url_request_unittest/two-content-lengths.html.mock-http-headers
new file mode 100644
index 0000000..707c0b0
--- /dev/null
+++ b/net/data/url_request_unittest/two-content-lengths.html.mock-http-headers
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Content-Length: 42
+Content-Length: 41
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 8913f17..fe63820 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -329,11 +329,9 @@
 
 // Creates NetLog parameters containing the information in a RequestInfo object,
 // along with the associated NetLog::Source.
-base::Value* NetLogRequestInfoCallback(const NetLog::Source& source,
-                                       const HostResolver::RequestInfo* info,
+base::Value* NetLogRequestInfoCallback(const HostResolver::RequestInfo* info,
                                        NetLog::LogLevel /* log_level */) {
   base::DictionaryValue* dict = new base::DictionaryValue();
-  source.AddToEventParameters(dict);
 
   dict->SetString("host", info->host_port_pair().ToString());
   dict->SetInteger("address_family",
@@ -374,34 +372,25 @@
 
 // Logs when a request has just been started.
 void LogStartRequest(const BoundNetLog& source_net_log,
-                     const BoundNetLog& request_net_log,
                      const HostResolver::RequestInfo& info) {
   source_net_log.BeginEvent(
-      NetLog::TYPE_HOST_RESOLVER_IMPL,
-      request_net_log.source().ToEventParametersCallback());
-
-  request_net_log.BeginEvent(
       NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
-      base::Bind(&NetLogRequestInfoCallback, source_net_log.source(), &info));
+      base::Bind(&NetLogRequestInfoCallback, &info));
 }
 
 // Logs when a request has just completed (before its callback is run).
 void LogFinishRequest(const BoundNetLog& source_net_log,
-                      const BoundNetLog& request_net_log,
                       const HostResolver::RequestInfo& info,
                       int net_error) {
-  request_net_log.EndEventWithNetErrorCode(
+  source_net_log.EndEventWithNetErrorCode(
       NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
-  source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
 }
 
 // Logs when a request has been cancelled.
 void LogCancelRequest(const BoundNetLog& source_net_log,
-                      const BoundNetLog& request_net_log,
                       const HostResolverImpl::RequestInfo& info) {
-  request_net_log.AddEvent(NetLog::TYPE_CANCELLED);
-  request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST);
-  source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
+  source_net_log.AddEvent(NetLog::TYPE_CANCELLED);
+  source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST);
 }
 
 //-----------------------------------------------------------------------------
@@ -461,13 +450,11 @@
 class HostResolverImpl::Request {
  public:
   Request(const BoundNetLog& source_net_log,
-          const BoundNetLog& request_net_log,
           const RequestInfo& info,
           RequestPriority priority,
           const CompletionCallback& callback,
           AddressList* addresses)
       : source_net_log_(source_net_log),
-        request_net_log_(request_net_log),
         info_(info),
         priority_(priority),
         job_(NULL),
@@ -511,11 +498,6 @@
     return source_net_log_;
   }
 
-  // NetLog for this request.
-  const BoundNetLog& request_net_log() {
-    return request_net_log_;
-  }
-
   const RequestInfo& info() const {
     return info_;
   }
@@ -525,8 +507,7 @@
   base::TimeTicks request_time() const { return request_time_; }
 
  private:
-  BoundNetLog source_net_log_;
-  BoundNetLog request_net_log_;
+  const BoundNetLog source_net_log_;
 
   // The request info that started the request.
   const RequestInfo info_;
@@ -1200,7 +1181,7 @@
   Job(const base::WeakPtr<HostResolverImpl>& resolver,
       const Key& key,
       RequestPriority priority,
-      const BoundNetLog& request_net_log)
+      const BoundNetLog& source_net_log)
       : resolver_(resolver),
         key_(key),
         priority_tracker_(priority),
@@ -1210,14 +1191,14 @@
         dns_task_error_(OK),
         creation_time_(base::TimeTicks::Now()),
         priority_change_time_(creation_time_),
-        net_log_(BoundNetLog::Make(request_net_log.net_log(),
+        net_log_(BoundNetLog::Make(source_net_log.net_log(),
                                    NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
-    request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
+    source_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
 
     net_log_.BeginEvent(
         NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
         base::Bind(&NetLogJobCreationCallback,
-                   request_net_log.source(),
+                   source_net_log.source(),
                    &key_.hostname));
   }
 
@@ -1248,8 +1229,7 @@
       if (req->was_canceled())
         continue;
       DCHECK_EQ(this, req->job());
-      LogCancelRequest(req->source_net_log(), req->request_net_log(),
-                       req->info());
+      LogCancelRequest(req->source_net_log(), req->info());
     }
   }
 
@@ -1278,14 +1258,14 @@
     req->set_job(this);
     priority_tracker_.Add(req->priority());
 
-    req->request_net_log().AddEvent(
+    req->source_net_log().AddEvent(
         NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
         net_log_.source().ToEventParametersCallback());
 
     net_log_.AddEvent(
         NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
         base::Bind(&NetLogJobAttachCallback,
-                   req->request_net_log().source(),
+                   req->source_net_log().source(),
                    priority()));
 
     // TODO(szym): Check if this is still needed.
@@ -1308,13 +1288,12 @@
 
     // Don't remove it from |requests_| just mark it canceled.
     req->MarkAsCanceled();
-    LogCancelRequest(req->source_net_log(), req->request_net_log(),
-                     req->info());
+    LogCancelRequest(req->source_net_log(), req->info());
 
     priority_tracker_.Remove(req->priority());
     net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
                       base::Bind(&NetLogJobAttachCallback,
-                                 req->request_net_log().source(),
+                                 req->source_net_log().source(),
                                  priority()));
 
     if (num_active_requests() > 0) {
@@ -1700,8 +1679,7 @@
 
       DCHECK_EQ(this, req->job());
       // Update the net log and notify registered observers.
-      LogFinishRequest(req->source_net_log(), req->request_net_log(),
-                       req->info(), entry.error);
+      LogFinishRequest(req->source_net_log(), req->info(), entry.error);
       if (did_complete) {
         // Record effective total time from creation to completion.
         RecordTotalTime(had_dns_config_, req->info().is_speculative(),
@@ -1871,19 +1849,15 @@
   if (!DNSDomainFromDot(info.hostname(), &labeled_hostname))
     return ERR_NAME_NOT_RESOLVED;
 
-  // Make a log item for the request.
-  BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
-      NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
-
-  LogStartRequest(source_net_log, request_net_log, info);
+  LogStartRequest(source_net_log, info);
 
   // Build a key that identifies the request in the cache and in the
   // outstanding jobs map.
-  Key key = GetEffectiveKeyForRequest(info, request_net_log);
+  Key key = GetEffectiveKeyForRequest(info, source_net_log);
 
-  int rv = ResolveHelper(key, info, addresses, request_net_log);
+  int rv = ResolveHelper(key, info, addresses, source_net_log);
   if (rv != ERR_DNS_CACHE_MISS) {
-    LogFinishRequest(source_net_log, request_net_log, info, rv);
+    LogFinishRequest(source_net_log, info, rv);
     RecordTotalTime(HaveDnsConfig(), info.is_speculative(), base::TimeDelta());
     return rv;
   }
@@ -1895,7 +1869,7 @@
   Job* job;
   if (jobit == jobs_.end()) {
     job =
-        new Job(weak_ptr_factory_.GetWeakPtr(), key, priority, request_net_log);
+        new Job(weak_ptr_factory_.GetWeakPtr(), key, priority, source_net_log);
     job->Schedule(false);
 
     // Check for queue overflow.
@@ -1905,7 +1879,7 @@
       evicted->OnEvicted();  // Deletes |evicted|.
       if (evicted == job) {
         rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
-        LogFinishRequest(source_net_log, request_net_log, info, rv);
+        LogFinishRequest(source_net_log, info, rv);
         return rv;
       }
     }
@@ -1916,7 +1890,7 @@
 
   // Can't complete synchronously. Create and attach request.
   scoped_ptr<Request> req(new Request(
-      source_net_log, request_net_log, info, priority, callback, addresses));
+      source_net_log, info, priority, callback, addresses));
   if (out_req)
     *out_req = reinterpret_cast<RequestHandle>(req.get());
 
@@ -1928,7 +1902,7 @@
 int HostResolverImpl::ResolveHelper(const Key& key,
                                     const RequestInfo& info,
                                     AddressList* addresses,
-                                    const BoundNetLog& request_net_log) {
+                                    const BoundNetLog& source_net_log) {
   // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
   // On Windows it gives the default interface's address, whereas on Linux it
   // gives an error. We will make it fail on all platforms for consistency.
@@ -1939,13 +1913,13 @@
   if (ResolveAsIP(key, info, &net_error, addresses))
     return net_error;
   if (ServeFromCache(key, info, &net_error, addresses)) {
-    request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
+    source_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
     return net_error;
   }
   // TODO(szym): Do not do this if nsswitch.conf instructs not to.
   // http://crbug.com/117655
   if (ServeFromHosts(key, info, addresses)) {
-    request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
+    source_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
     return OK;
   }
   return ERR_DNS_CACHE_MISS;
@@ -1957,17 +1931,13 @@
   DCHECK(CalledOnValidThread());
   DCHECK(addresses);
 
-  // Make a log item for the request.
-  BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
-      NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
-
   // Update the net log and notify registered observers.
-  LogStartRequest(source_net_log, request_net_log, info);
+  LogStartRequest(source_net_log, info);
 
-  Key key = GetEffectiveKeyForRequest(info, request_net_log);
+  Key key = GetEffectiveKeyForRequest(info, source_net_log);
 
-  int rv = ResolveHelper(key, info, addresses, request_net_log);
-  LogFinishRequest(source_net_log, request_net_log, info, rv);
+  int rv = ResolveHelper(key, info, addresses, source_net_log);
+  LogFinishRequest(source_net_log, info, rv);
   return rv;
 }
 
diff --git a/net/http/disk_cache_based_quic_server_info.cc b/net/http/disk_cache_based_quic_server_info.cc
index 2e116da..148df3f 100644
--- a/net/http/disk_cache_based_quic_server_info.cc
+++ b/net/http/disk_cache_based_quic_server_info.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "net/base/completion_callback.h"
@@ -17,44 +18,6 @@
 
 namespace net {
 
-// Histogram that tracks number of times data read/parse/write API calls of
-// QuicServerInfo to and from disk cache is called.
-enum QuicServerInfoAPICall {
-  QUIC_SERVER_INFO_START = 0,
-  QUIC_SERVER_INFO_WAIT_FOR_DATA_READY = 1,
-  QUIC_SERVER_INFO_PARSE = 2,
-  QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL = 3,
-  QUIC_SERVER_INFO_READY_TO_PERSIST = 4,
-  QUIC_SERVER_INFO_PERSIST = 5,
-  QUIC_SERVER_INFO_NUM_OF_API_CALLS = 6,
-};
-
-// Histogram that tracks failure reasons to read/load/write of QuicServerInfo to
-// and from disk cache.
-enum FailureReason {
-  WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE = 0,
-  GET_BACKEND_FAILURE = 1,
-  OPEN_FAILURE = 2,
-  CREATE_OR_OPEN_FAILURE = 3,
-  PARSE_NO_DATA_FAILURE = 4,
-  PARSE_FAILURE = 5,
-  READ_FAILURE = 6,
-  READY_TO_PERSIST_FAILURE = 7,
-  PERSIST_NO_BACKEND_FAILURE = 8,
-  WRITE_FAILURE = 9,
-  NUM_OF_FAILURES = 10,
-};
-
-void RecordQuicServerInfoStatus(QuicServerInfoAPICall call) {
-  UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall", call,
-                            QUIC_SERVER_INFO_NUM_OF_API_CALLS);
-}
-
-void RecordQuicServerInfoFailure(FailureReason failure) {
-  UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason", failure,
-                            NUM_OF_FAILURES);
-}
-
 // Some APIs inside disk_cache take a handle that the caller must keep alive
 // until the API has finished its asynchronous execution.
 //
@@ -94,6 +57,7 @@
       http_cache_(http_cache),
       backend_(NULL),
       entry_(NULL),
+      last_failure_(NO_FAILURE),
       weak_factory_(this) {
       io_callback_ =
           base::Bind(&DiskCacheBasedQuicServerInfo::OnIOComplete,
@@ -104,6 +68,7 @@
 void DiskCacheBasedQuicServerInfo::Start() {
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(GET_BACKEND, state_);
+  DCHECK_EQ(last_failure_, NO_FAILURE);
   RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START);
   load_start_time_ = base::TimeTicks::Now();
   DoLoop(OK);
@@ -115,17 +80,19 @@
   DCHECK_NE(GET_BACKEND, state_);
 
   RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY);
-  if (ready_)
+  if (ready_) {
+    RecordLastFailure();
     return OK;
+  }
 
   if (!callback.is_null()) {
     // Prevent a new callback for WaitForDataReady overwriting an existing
-    // pending callback (|user_callback_|).
-    if (!user_callback_.is_null()) {
+    // pending callback (|wait_for_ready_callback_|).
+    if (!wait_for_ready_callback_.is_null()) {
       RecordQuicServerInfoFailure(WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE);
       return ERR_INVALID_ARGUMENT;
     }
-    user_callback_ = callback;
+    wait_for_ready_callback_ = callback;
   }
 
   return ERR_IO_PENDING;
@@ -135,8 +102,10 @@
   DCHECK(CalledOnValidThread());
 
   RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL);
-  if (!user_callback_.is_null())
-    user_callback_.Reset();
+  if (!wait_for_ready_callback_.is_null()) {
+    RecordLastFailure();
+    wait_for_ready_callback_.Reset();
+  }
 }
 
 bool DiskCacheBasedQuicServerInfo::IsDataReady() {
@@ -144,10 +113,6 @@
 }
 
 bool DiskCacheBasedQuicServerInfo::IsReadyToPersist() {
-  // TODO(rtenneti): Handle updates while a write is pending. Change
-  // Persist() to save the data to be written into a temporary buffer
-  // and then persist that data when we are ready to persist.
-  //
   // The data can be persisted if it has been loaded from the disk cache
   // and there are no pending writes.
   RecordQuicServerInfoStatus(QUIC_SERVER_INFO_READY_TO_PERSIST);
@@ -159,12 +124,29 @@
 
 void DiskCacheBasedQuicServerInfo::Persist() {
   DCHECK(CalledOnValidThread());
-  DCHECK_NE(GET_BACKEND, state_);
+  if (!IsReadyToPersist()) {
+    // Handle updates while a write is pending or if we haven't loaded from disk
+    // cache. Save the data to be written into a temporary buffer and then
+    // persist that data when we are ready to persist.
+    pending_write_data_ = Serialize();
+    return;
+  }
+  PersistInternal();
+}
 
+void DiskCacheBasedQuicServerInfo::PersistInternal() {
+  DCHECK(CalledOnValidThread());
+  DCHECK_NE(GET_BACKEND, state_);
   DCHECK(new_data_.empty());
   CHECK(ready_);
-  DCHECK(user_callback_.is_null());
-  new_data_ = Serialize();
+  DCHECK(wait_for_ready_callback_.is_null());
+
+  if (pending_write_data_.empty()) {
+    new_data_ = Serialize();
+  } else {
+    new_data_ = pending_write_data_;
+    pending_write_data_.clear();
+  }
 
   RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PERSIST);
   if (!backend_) {
@@ -176,8 +158,21 @@
   DoLoop(OK);
 }
 
+void DiskCacheBasedQuicServerInfo::OnExternalCacheHit() {
+  DCHECK(CalledOnValidThread());
+  DCHECK_NE(GET_BACKEND, state_);
+
+  RecordQuicServerInfoStatus(QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT);
+  if (!backend_) {
+    RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE);
+    return;
+  }
+
+  backend_->OnExternalCacheHit(key());
+}
+
 DiskCacheBasedQuicServerInfo::~DiskCacheBasedQuicServerInfo() {
-  DCHECK(user_callback_.is_null());
+  DCHECK(wait_for_ready_callback_.is_null());
   if (entry_)
     entry_->Close();
 }
@@ -190,10 +185,15 @@
                                                 int rv) {
   DCHECK_NE(NONE, state_);
   rv = DoLoop(rv);
-  if (rv != ERR_IO_PENDING && !user_callback_.is_null()) {
-    CompletionCallback callback = user_callback_;
-    user_callback_.Reset();
-    callback.Run(rv);
+  if (rv == ERR_IO_PENDING)
+    return;
+  if (!wait_for_ready_callback_.is_null()) {
+    RecordLastFailure();
+    base::ResetAndReturn(&wait_for_ready_callback_).Run(rv);
+  }
+  if (ready_ && !pending_write_data_.empty()) {
+    DCHECK_EQ(NONE, state_);
+    PersistInternal();
   }
 }
 
@@ -381,4 +381,43 @@
   return OK;
 }
 
+void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoStatus(
+    QuicServerInfoAPICall call) {
+  if (!backend_) {
+    UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.NoBackend", call,
+                              QUIC_SERVER_INFO_NUM_OF_API_CALLS);
+  } else if (backend_->GetCacheType() == net::MEMORY_CACHE) {
+    UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.MemoryCache", call,
+                              QUIC_SERVER_INFO_NUM_OF_API_CALLS);
+  } else {
+    UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.DiskCache", call,
+                              QUIC_SERVER_INFO_NUM_OF_API_CALLS);
+  }
+}
+
+void DiskCacheBasedQuicServerInfo::RecordLastFailure() {
+  if (last_failure_ != NO_FAILURE) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "Net.QuicDiskCache.FailureReason.WaitForDataReady",
+        last_failure_, NUM_OF_FAILURES);
+  }
+  last_failure_ = NO_FAILURE;
+}
+
+void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoFailure(
+    FailureReason failure) {
+  last_failure_ = failure;
+
+  if (!backend_) {
+    UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.NoBackend",
+                              failure, NUM_OF_FAILURES);
+  } else if (backend_->GetCacheType() == net::MEMORY_CACHE) {
+    UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.MemoryCache",
+                              failure, NUM_OF_FAILURES);
+  } else {
+    UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.DiskCache",
+                              failure, NUM_OF_FAILURES);
+  }
+}
+
 }  // namespace net
diff --git a/net/http/disk_cache_based_quic_server_info.h b/net/http/disk_cache_based_quic_server_info.h
index 97fe95e..e95d535 100644
--- a/net/http/disk_cache_based_quic_server_info.h
+++ b/net/http/disk_cache_based_quic_server_info.h
@@ -38,9 +38,11 @@
   bool IsDataReady() override;
   bool IsReadyToPersist() override;
   void Persist() override;
+  void OnExternalCacheHit() override;
 
  private:
   struct CacheOperationDataShim;
+
   enum State {
     GET_BACKEND,
     GET_BACKEND_COMPLETE,
@@ -57,8 +59,42 @@
     NONE,
   };
 
+  // Enum to track number of times data read/parse/write API calls of
+  // QuicServerInfo to and from disk cache is called.
+  enum QuicServerInfoAPICall {
+    QUIC_SERVER_INFO_START = 0,
+    QUIC_SERVER_INFO_WAIT_FOR_DATA_READY = 1,
+    QUIC_SERVER_INFO_PARSE = 2,
+    QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL = 3,
+    QUIC_SERVER_INFO_READY_TO_PERSIST = 4,
+    QUIC_SERVER_INFO_PERSIST = 5,
+    QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT = 6,
+    QUIC_SERVER_INFO_NUM_OF_API_CALLS = 7,
+  };
+
+  // Enum to track failure reasons to read/load/write of QuicServerInfo to
+  // and from disk cache.
+  enum FailureReason {
+    WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE = 0,
+    GET_BACKEND_FAILURE = 1,
+    OPEN_FAILURE = 2,
+    CREATE_OR_OPEN_FAILURE = 3,
+    PARSE_NO_DATA_FAILURE = 4,
+    PARSE_FAILURE = 5,
+    READ_FAILURE = 6,
+    READY_TO_PERSIST_FAILURE = 7,
+    PERSIST_NO_BACKEND_FAILURE = 8,
+    WRITE_FAILURE = 9,
+    NO_FAILURE = 10,
+    NUM_OF_FAILURES = 11,
+  };
+
   ~DiskCacheBasedQuicServerInfo() override;
 
+  // Persists |pending_write_data_| if it is not empty, otherwise serializes the
+  // data and pesists it.
+  void PersistInternal();
+
   std::string key() const;
 
   // The |unused| parameter is a small hack so that we can have the
@@ -86,23 +122,39 @@
   // DoSetDone is the terminal state of the write operation.
   int DoSetDone();
 
+  // Tracks in a histogram the number of times data read/parse/write API calls
+  // of QuicServerInfo to and from disk cache is called.
+  void RecordQuicServerInfoStatus(QuicServerInfoAPICall call);
+
+  // Tracks in a histogram the failure reasons to read/load/write of
+  // QuicServerInfo to and from disk cache. It also saves the |failure| in
+  // |last_failure_|.
+  void RecordQuicServerInfoFailure(FailureReason failure);
+
+  // Tracks in a histogram if |last_failure_| is not NO_FAILURE.
+  void RecordLastFailure();
+
   CacheOperationDataShim* data_shim_;  // Owned by |io_callback_|.
   CompletionCallback io_callback_;
   State state_;
   bool ready_;
   bool found_entry_;  // Controls the behavior of DoCreateOrOpen.
   std::string new_data_;
+  std::string pending_write_data_;
   const QuicServerId server_id_;
   HttpCache* const http_cache_;
   disk_cache::Backend* backend_;
   disk_cache::Entry* entry_;
-  CompletionCallback user_callback_;
+  CompletionCallback wait_for_ready_callback_;
   scoped_refptr<IOBuffer> read_buffer_;
   scoped_refptr<IOBuffer> write_buffer_;
   std::string data_;
   base::TimeTicks load_start_time_;
+  FailureReason last_failure_;
 
   base::WeakPtrFactory<DiskCacheBasedQuicServerInfo> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(DiskCacheBasedQuicServerInfo);
 };
 
 }  // namespace net
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 845fdc9..847b3d8 100644
--- a/net/http/disk_cache_based_quic_server_info_unittest.cc
+++ b/net/http/disk_cache_based_quic_server_info_unittest.cc
@@ -395,4 +395,191 @@
   RemoveMockTransaction(&kHostInfoTransaction1);
 }
 
+// Test Start() followed by Persist() without calling WaitForDataReady.
+TEST(DiskCacheBasedQuicServerInfo, StartAndPersist) {
+  MockHttpCache cache;
+  AddMockTransaction(&kHostInfoTransaction1);
+
+  QuicServerId server_id("www.google.com", 443, true, PRIVACY_MODE_DISABLED);
+  scoped_ptr<QuicServerInfo> quic_server_info(
+      new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+  EXPECT_FALSE(quic_server_info->IsDataReady());
+  quic_server_info->Start();
+  // Wait until Start() does the work.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(quic_server_info->IsDataReady());
+
+  QuicServerInfo::State* state = quic_server_info->mutable_state();
+  EXPECT_TRUE(state->certs.empty());
+  const string server_config_a = "server_config_a";
+  const string source_address_token_a = "source_address_token_a";
+  const string server_config_sig_a = "server_config_sig_a";
+  const string cert_a = "cert_a";
+
+  state->server_config = server_config_a;
+  state->source_address_token = source_address_token_a;
+  state->server_config_sig = server_config_sig_a;
+  state->certs.push_back(cert_a);
+  EXPECT_TRUE(quic_server_info->IsReadyToPersist());
+  quic_server_info->Persist();
+  quic_server_info->OnExternalCacheHit();
+
+  // Once we call Persist, IsReadyToPersist should return false until Persist
+  // has completed.
+  EXPECT_FALSE(quic_server_info->IsReadyToPersist());
+
+  // Wait until Persist() does the work.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(quic_server_info->IsReadyToPersist());
+
+  // Verify that the state was updated.
+  quic_server_info.reset(
+      new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+  quic_server_info->Start();
+  TestCompletionCallback callback;
+  int rv = quic_server_info->WaitForDataReady(callback.callback());
+  EXPECT_EQ(OK, callback.GetResult(rv));
+  EXPECT_TRUE(quic_server_info->IsDataReady());
+
+  const QuicServerInfo::State& state1 = quic_server_info->state();
+  EXPECT_EQ(server_config_a, state1.server_config);
+  EXPECT_EQ(source_address_token_a, state1.source_address_token);
+  EXPECT_EQ(server_config_sig_a, state1.server_config_sig);
+  EXPECT_EQ(1U, state1.certs.size());
+  EXPECT_EQ(cert_a, state1.certs[0]);
+
+  RemoveMockTransaction(&kHostInfoTransaction1);
+}
+
+// Test Persisting data when we are not ready to persist and then verify it
+// persists the data when Start() finishes.
+TEST(DiskCacheBasedQuicServerInfo, PersistWhenNotReadyToPersist) {
+  MockBlockingBackendFactory* factory = new MockBlockingBackendFactory();
+  MockHttpCache cache(factory);
+  AddMockTransaction(&kHostInfoTransaction1);
+  TestCompletionCallback callback;
+
+  QuicServerId server_id("www.google.com", 443, true, PRIVACY_MODE_DISABLED);
+  scoped_ptr<QuicServerInfo> quic_server_info(
+      new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+  EXPECT_FALSE(quic_server_info->IsDataReady());
+  // We do a Start(), but don't call WaitForDataReady(). Because we haven't
+  // created the backend, we will wait and data wouldn't be ready.
+  quic_server_info->Start();
+  EXPECT_FALSE(quic_server_info->IsDataReady());
+
+  // Persist data once, even though the backend is not ready.
+  QuicServerInfo::State* state = quic_server_info->mutable_state();
+  EXPECT_TRUE(state->certs.empty());
+  const string server_config_init = "server_config_init";
+  const string source_address_token_init = "source_address_token_init";
+  const string server_config_sig_init = "server_config_sig_init";
+  const string cert_init = "cert_init";
+
+  state->server_config = server_config_init;
+  state->source_address_token = source_address_token_init;
+  state->server_config_sig = server_config_sig_init;
+  state->certs.push_back(cert_init);
+  EXPECT_FALSE(quic_server_info->IsReadyToPersist());
+  quic_server_info->Persist();
+  EXPECT_FALSE(quic_server_info->IsReadyToPersist());
+
+  // Now complete the backend creation and let the callback run.
+  factory->FinishCreation();
+  EXPECT_TRUE(quic_server_info->IsDataReady());
+
+  // Wait until Persist() does the work.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Verify that the state was updated.
+  quic_server_info.reset(
+      new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+  quic_server_info->Start();
+  int rv = quic_server_info->WaitForDataReady(callback.callback());
+  EXPECT_EQ(OK, callback.GetResult(rv));
+  EXPECT_TRUE(quic_server_info->IsDataReady());
+
+  const QuicServerInfo::State& state1 = quic_server_info->state();
+  EXPECT_EQ(server_config_init, state1.server_config);
+  EXPECT_EQ(source_address_token_init, state1.source_address_token);
+  EXPECT_EQ(server_config_sig_init, state1.server_config_sig);
+  EXPECT_EQ(1U, state1.certs.size());
+  EXPECT_EQ(cert_init, state1.certs[0]);
+  RemoveMockTransaction(&kHostInfoTransaction1);
+}
+
+// Test multiple calls to Persist without waiting for the data to be written.
+TEST(DiskCacheBasedQuicServerInfo, MultiplePersistsWithoutWaiting) {
+  MockHttpCache cache;
+  AddMockTransaction(&kHostInfoTransaction1);
+  TestCompletionCallback callback;
+
+  QuicServerId server_id("www.google.com", 443, true, PRIVACY_MODE_DISABLED);
+  scoped_ptr<QuicServerInfo> quic_server_info(
+      new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+  EXPECT_FALSE(quic_server_info->IsDataReady());
+  quic_server_info->Start();
+  int rv = quic_server_info->WaitForDataReady(callback.callback());
+  EXPECT_EQ(OK, callback.GetResult(rv));
+  EXPECT_TRUE(quic_server_info->IsDataReady());
+
+  // Persist data once.
+  QuicServerInfo::State* state = quic_server_info->mutable_state();
+  EXPECT_TRUE(state->certs.empty());
+  const string server_config_init = "server_config_init";
+  const string source_address_token_init = "source_address_token_init";
+  const string server_config_sig_init = "server_config_sig_init";
+  const string cert_init = "cert_init";
+
+  state->server_config = server_config_init;
+  state->source_address_token = source_address_token_init;
+  state->server_config_sig = server_config_sig_init;
+  state->certs.push_back(cert_init);
+  EXPECT_TRUE(quic_server_info->IsReadyToPersist());
+  quic_server_info->Persist();
+
+  // Once we call Persist, IsReadyToPersist should return false until Persist
+  // has completed.
+  EXPECT_FALSE(quic_server_info->IsReadyToPersist());
+
+  // Persist one more time using the same |quic_server_info| object and without
+  // doing another Start() and WaitForDataReady.
+  const string server_config_a = "server_config_a";
+  const string source_address_token_a = "source_address_token_a";
+  const string server_config_sig_a = "server_config_sig_a";
+  const string cert_a = "cert_a";
+
+  state->server_config = server_config_a;
+  state->source_address_token = source_address_token_a;
+  state->server_config_sig = server_config_sig_a;
+  state->certs.push_back(cert_a);
+  EXPECT_FALSE(quic_server_info->IsReadyToPersist());
+  quic_server_info->Persist();
+
+  // Wait until Persist() does the work.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  EXPECT_TRUE(quic_server_info->IsReadyToPersist());
+
+  // Verify that the state was updated.
+  quic_server_info.reset(
+      new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+  quic_server_info->Start();
+  rv = quic_server_info->WaitForDataReady(callback.callback());
+  EXPECT_EQ(OK, callback.GetResult(rv));
+  EXPECT_TRUE(quic_server_info->IsDataReady());
+
+  // Verify the second time persisted data is persisted.
+  const QuicServerInfo::State& state1 = quic_server_info->state();
+  EXPECT_EQ(server_config_a, state1.server_config);
+  EXPECT_EQ(source_address_token_a, state1.source_address_token);
+  EXPECT_EQ(server_config_sig_a, state1.server_config_sig);
+  EXPECT_EQ(1U, state1.certs.size());
+  EXPECT_EQ(cert_a, state1.certs[0]);
+
+  RemoveMockTransaction(&kHostInfoTransaction1);
+}
+
 }  // namespace net
diff --git a/net/http/http_auth_handler.cc b/net/http/http_auth_handler.cc
index 7369ea5..4de2226 100644
--- a/net/http/http_auth_handler.cc
+++ b/net/http/http_auth_handler.cc
@@ -64,7 +64,7 @@
 int HttpAuthHandler::GenerateAuthToken(
     const AuthCredentials* credentials, const HttpRequestInfo* request,
     const CompletionCallback& callback, std::string* auth_token) {
-  // TODO(cbentzel): Enforce non-NULL callback after cleaning up SocketStream.
+  DCHECK(!callback.is_null());
   DCHECK(request);
   DCHECK(credentials != NULL || AllowsDefaultCredentials());
   DCHECK(auth_token != NULL);
@@ -96,8 +96,8 @@
 void HttpAuthHandler::OnGenerateAuthTokenComplete(int rv) {
   CompletionCallback callback = callback_;
   FinishGenerateAuthToken();
-  if (!callback.is_null())
-    callback.Run(rv);
+  DCHECK(!callback.is_null());
+  callback.Run(rv);
 }
 
 void HttpAuthHandler::FinishGenerateAuthToken() {
diff --git a/net/http/http_auth_handler_basic_unittest.cc b/net/http/http_auth_handler_basic_unittest.cc
index a369df3..60e5882 100644
--- a/net/http/http_auth_handler_basic_unittest.cc
+++ b/net/http/http_auth_handler_basic_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
 #include "net/http/http_auth_challenge_tokenizer.h"
 #include "net/http/http_auth_handler_basic.h"
 #include "net/http/http_request_info.h"
@@ -41,8 +42,9 @@
                                 base::ASCIIToUTF16(tests[i].password));
     HttpRequestInfo request_info;
     std::string auth_token;
+    TestCompletionCallback callback;
     int rv = basic->GenerateAuthToken(&credentials, &request_info,
-                                      CompletionCallback(), &auth_token);
+                                      callback.callback(), &auth_token);
     EXPECT_EQ(OK, rv);
     EXPECT_STREQ(tests[i].expected_credentials, auth_token.c_str());
   }
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 3ec607e..28b3b22 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -89,7 +89,6 @@
       force_spdy_always(false),
       use_alternate_protocols(false),
       alternate_protocol_probability_threshold(1),
-      enable_websocket_over_spdy(false),
       enable_quic(false),
       enable_quic_port_selection(true),
       quic_always_require_handshake_confirmation(false),
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index a3f70aa..557b84e 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -109,7 +109,6 @@
     // trying SSL and then falling back to http.
     bool use_alternate_protocols;
     double alternate_protocol_probability_threshold;
-    bool enable_websocket_over_spdy;
 
     bool enable_quic;
     bool enable_quic_port_selection;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index eea7294..20ffdd1 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -90,19 +90,6 @@
       *session);
 }
 
-// Returns true if |error| is a client certificate authentication error.
-bool IsClientCertificateError(int error) {
-  switch (error) {
-    case ERR_BAD_SSL_CLIENT_AUTH_CERT:
-    case ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED:
-    case ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY:
-    case ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED:
-      return true;
-    default:
-      return false;
-  }
-}
-
 base::Value* NetLogSSLVersionFallbackCallback(
     const GURL* url,
     int net_error,
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 938f1b0..d08d162 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -408,7 +408,7 @@
     NextProto,
     HttpNetworkTransactionTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 namespace {
 
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index 19df6a0..694d394 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -351,9 +351,12 @@
         HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31),
         HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31),
         HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31),
-        HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4),
-        HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4),
-        HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4)));
+        HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4_14),
+        HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4_14),
+        HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4_14),
+        HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4_15),
+        HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4_15),
+        HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4_15)));
 
 TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
   Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index 2ec0fb5..6967d79 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -369,8 +369,10 @@
     case kProtoSPDY3:
     case kProtoSPDY31:
       return CONNECTION_INFO_SPDY3;
-    case kProtoSPDY4:
-      return CONNECTION_INFO_SPDY4;
+    case kProtoSPDY4_14:
+      return CONNECTION_INFO_HTTP2_14;
+    case kProtoSPDY4_15:
+      return CONNECTION_INFO_HTTP2_15;
     case kProtoQUIC1SPDY3:
       return CONNECTION_INFO_QUIC1_SPDY3;
 
@@ -395,9 +397,12 @@
       return "spdy/2";
     case CONNECTION_INFO_SPDY3:
       return "spdy/3";
-    case CONNECTION_INFO_SPDY4:
-      // This is the HTTP/2 draft-15 identifier. For internal
-      // consistency, HTTP/2 is named SPDY4 within Chromium.
+    case CONNECTION_INFO_HTTP2_14:
+      // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
+      // This is the HTTP/2 draft-14 identifier.
+      return "h2-14";
+    case CONNECTION_INFO_HTTP2_15:
+      // This is the HTTP/2 draft-15 identifier.
       return "h2-15";
     case CONNECTION_INFO_QUIC1_SPDY3:
       return "quic/1+spdy/3";
diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h
index efd76fe..df3e300 100644
--- a/net/http/http_response_info.h
+++ b/net/http/http_response_info.h
@@ -37,8 +37,10 @@
     CONNECTION_INFO_HTTP1 = 1,
     CONNECTION_INFO_DEPRECATED_SPDY2 = 2,
     CONNECTION_INFO_SPDY3 = 3,
-    CONNECTION_INFO_SPDY4 = 4,
+    // CONNECTION_INFO_HTTP2 = 4,  // TODO(bnc):  This will be HTTP/2.
     CONNECTION_INFO_QUIC1_SPDY3 = 5,
+    CONNECTION_INFO_HTTP2_14 = 6,  // HTTP/2 draft-14.
+    CONNECTION_INFO_HTTP2_15 = 7,  // HTTP/2 draft-15.
     NUM_OF_CONNECTION_INFOS,
   };
 
diff --git a/net/http/http_server_properties.cc b/net/http/http_server_properties.cc
index cc41ea8..25725a8 100644
--- a/net/http/http_server_properties.cc
+++ b/net/http/http_server_properties.cc
@@ -20,6 +20,7 @@
   "npn-spdy/2",
   "npn-spdy/3",
   "npn-spdy/3.1",
+  "npn-h2-14",  // HTTP/2 draft-14. Called SPDY4 internally.
   "npn-h2-15",  // HTTP/2 draft-15. Called SPDY4 internally.
   "quic"
 };
@@ -51,7 +52,8 @@
     case DEPRECATED_NPN_SPDY_2:
     case NPN_SPDY_3:
     case NPN_SPDY_3_1:
-    case NPN_SPDY_4:
+    case NPN_SPDY_4_14:
+    case NPN_SPDY_4_15:
     case QUIC:
       DCHECK(IsAlternateProtocolValid(protocol));
       return kAlternateProtocolStrings[
@@ -81,8 +83,10 @@
       return NPN_SPDY_3;
     case kProtoSPDY31:
       return NPN_SPDY_3_1;
-    case kProtoSPDY4:
-      return NPN_SPDY_4;
+    case kProtoSPDY4_14:
+      return NPN_SPDY_4_14;
+    case kProtoSPDY4_15:
+      return NPN_SPDY_4_15;
     case kProtoQUIC1SPDY3:
       return QUIC;
 
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h
index 337f22d..a63dc6a 100644
--- a/net/http/http_server_properties.h
+++ b/net/http/http_server_properties.h
@@ -57,8 +57,9 @@
   NPN_SPDY_MINIMUM_VERSION = DEPRECATED_NPN_SPDY_2,
   NPN_SPDY_3,
   NPN_SPDY_3_1,
-  NPN_SPDY_4,  // SPDY4 is HTTP/2.
-  NPN_SPDY_MAXIMUM_VERSION = NPN_SPDY_4,
+  NPN_SPDY_4_14,  // HTTP/2 draft-14
+  NPN_SPDY_4_15,  // HTTP/2 draft-15
+  NPN_SPDY_MAXIMUM_VERSION = NPN_SPDY_4_15,
   QUIC,
   ALTERNATE_PROTOCOL_MAXIMUM_VALID_VERSION = QUIC,
   UNINITIALIZED_ALTERNATE_PROTOCOL,
diff --git a/net/http/http_stream_factory_impl_request_unittest.cc b/net/http/http_stream_factory_impl_request_unittest.cc
index 4695067..587358d 100644
--- a/net/http/http_stream_factory_impl_request_unittest.cc
+++ b/net/http/http_stream_factory_impl_request_unittest.cc
@@ -20,7 +20,7 @@
     NextProto,
     HttpStreamFactoryImplRequestTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 namespace {
 
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 4bf1659..68e9114 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -425,7 +425,7 @@
     NextProto,
     HttpStreamFactoryTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 TEST_P(HttpStreamFactoryTest, PreconnectDirect) {
   for (size_t i = 0; i < arraysize(kTests); ++i) {
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index 907e6d8..baf38bf 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -415,7 +415,8 @@
   // hostname_offset contains the number of bytes from the start of the given
   // hostname where the name of the matching entry starts.
   size_t hostname_offset;
-  bool include_subdomains;
+  bool sts_include_subdomains;
+  bool pkp_include_subdomains;
   bool force_https;
   bool has_pins;
 };
@@ -509,15 +510,19 @@
 
       if (c == kEndOfString) {
         PreloadResult tmp;
-        if (!reader.Next(&tmp.include_subdomains) ||
+        if (!reader.Next(&tmp.sts_include_subdomains) ||
             !reader.Next(&tmp.force_https) ||
             !reader.Next(&tmp.has_pins)) {
           return false;
         }
 
+        tmp.pkp_include_subdomains = tmp.sts_include_subdomains;
+
         if (tmp.has_pins) {
           if (!reader.Read(4, &tmp.pinset_id) ||
-              !reader.Read(9, &tmp.domain_id)) {
+              !reader.Read(9, &tmp.domain_id) ||
+              (!tmp.sts_include_subdomains &&
+               !reader.Next(&tmp.pkp_include_subdomains))) {
             return false;
           }
         }
@@ -525,13 +530,16 @@
         tmp.hostname_offset = hostname_offset;
 
         if (hostname_offset == 0 || hostname[hostname_offset - 1] == '.') {
-          *out_found = tmp.include_subdomains;
+          *out_found =
+              tmp.sts_include_subdomains || tmp.pkp_include_subdomains;
           *out = tmp;
-        }
 
-        if (hostname_offset == 0) {
-          *out_found = true;
-          return true;
+          if (hostname_offset > 0) {
+            out->force_https &= tmp.sts_include_subdomains;
+          } else {
+            *out_found = true;
+            return true;
+          }
         }
 
         continue;
@@ -768,7 +776,7 @@
     return false;
 
   out->domain = host.substr(result.hostname_offset);
-  out->sts.include_subdomains = result.include_subdomains;
+  out->sts.include_subdomains = result.sts_include_subdomains;
   out->sts.last_observed = base::GetBuildTime();
   out->sts.upgrade_mode =
       TransportSecurityState::DomainState::MODE_DEFAULT;
@@ -778,7 +786,7 @@
   }
 
   if (enable_static_pins_ && result.has_pins) {
-    out->pkp.include_subdomains = result.include_subdomains;
+    out->pkp.include_subdomains = result.pkp_include_subdomains;
     out->pkp.last_observed = base::GetBuildTime();
 
     if (result.pinset_id >= arraysize(kPinsets))
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h
index e757950..867cafd 100644
--- a/net/http/transport_security_state_static.h
+++ b/net/http/transport_security_state_static.h
@@ -698,10 +698,10 @@
   0xf6, 0x07, 0xeb, 0x08, 0xed, 0x09, 0xae, 0xe3,
   0x0a, 0x0b, 0x03, 0x0c, 0x02, 0x0d, 0xe2, 0xe8,
   0x0f, 0xf3, 0xee, 0xf4, 0x10, 0x11, 0xff, 0x12,
-  0xb8, 0xb9, 0xb6, 0x14, 0xb7, 0x15, 0xb5, 0x16,
-  0xb0, 0x17, 0xb2, 0x18, 0x19, 0xea, 0xf8, 0x1a,
-  0x1b, 0xe6, 0xf5, 0x1c, 0xad, 0xf9, 0xe4, 0x1e,
-  0x1d, 0x1f, 0xe5, 0x20, 0xe9, 0xf2, 0xef, 0x22,
+  0xad, 0xe6, 0x14, 0xf5, 0xb8, 0xb9, 0xb6, 0x16,
+  0xb7, 0x17, 0xb5, 0x18, 0xb0, 0x19, 0xb2, 0x1a,
+  0x1b, 0xea, 0xf8, 0x1c, 0x1d, 0xf9, 0xe4, 0x1e,
+  0x15, 0x1f, 0xe5, 0x20, 0xe9, 0xf2, 0xef, 0x22,
   0x21, 0x23, 0x13, 0x24, 0x0e, 0x25,
 };
 
@@ -711,11 +711,11 @@
   0x4a, 0x54, 0x80, 0x26, 0x94, 0x02, 0xd3, 0xfa,
   0xf8, 0x20, 0x67, 0xaa, 0x53, 0x8d, 0x34, 0xfc,
   0xfb, 0x79, 0xb6, 0x34, 0x74, 0x29, 0xf9, 0x72,
-  0x14, 0x9d, 0x89, 0x86, 0xea, 0x43, 0xb6, 0x7f,
+  0x14, 0x9d, 0x89, 0x86, 0xee, 0x43, 0xb6, 0x7f,
   0x3b, 0x05, 0x3b, 0x90, 0xd1, 0x51, 0x4f, 0xff,
-  0x5b, 0xd6, 0x76, 0xbc, 0xca, 0x36, 0x5c, 0xd8,
+  0x5b, 0xd6, 0x76, 0x9c, 0xca, 0x36, 0x5c, 0xd8,
   0xe9, 0xf0, 0xa7, 0x72, 0x1a, 0x2b, 0xd9, 0xf7,
-  0x9b, 0xd3, 0x4a, 0x0e, 0x93, 0xb0, 0xf7, 0x04,
+  0x9b, 0xd3, 0x5a, 0x0e, 0x93, 0xb0, 0xf7, 0x04,
   0xc2, 0x7f, 0xe7, 0x73, 0xdd, 0x82, 0x9d, 0xc8,
   0x68, 0x91, 0xa7, 0xff, 0x39, 0x9c, 0xf7, 0x60,
   0xa7, 0x72, 0x1a, 0x27, 0x89, 0xff, 0xce, 0x67,
@@ -725,18 +725,18 @@
   0xc8, 0x68, 0xa2, 0x27, 0xfd, 0xcf, 0x76, 0x0a,
   0x77, 0x21, 0xa2, 0x91, 0x9f, 0xff, 0xb3, 0x6b,
   0x2e, 0xf7, 0x5f, 0xfc, 0x0a, 0xd5, 0x40, 0x54,
-  0x9c, 0xc4, 0x51, 0xea, 0x23, 0x4f, 0xfc, 0xee,
+  0x9c, 0xc4, 0x51, 0xee, 0x23, 0x4f, 0xfc, 0xee,
   0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x12, 0x84, 0x50,
-  0xba, 0x70, 0xf8, 0xd2, 0x10, 0xc7, 0x56, 0x76,
+  0xba, 0x70, 0xf8, 0xd2, 0x10, 0xc7, 0x76, 0x76,
   0x30, 0xaf, 0x61, 0x35, 0x93, 0x00, 0xa4, 0xdd,
-  0xa9, 0x55, 0x4b, 0x48, 0x7a, 0xb7, 0x96, 0x4f,
+  0xa9, 0x55, 0x4b, 0x58, 0x7a, 0xb7, 0x96, 0x4f,
   0xfe, 0x73, 0x39, 0xee, 0xc1, 0x4e, 0xe4, 0x34,
   0x4e, 0x73, 0xff, 0x9c, 0xce, 0x7b, 0xb0, 0x53,
   0xb9, 0x0d, 0x14, 0x4c, 0xff, 0xc2, 0xf7, 0x5b,
   0xd5, 0x69, 0xfe, 0x01, 0xd0, 0x28, 0xea, 0xaa,
-  0x96, 0x8a, 0x53, 0xf9, 0xd8, 0x29, 0xdc, 0x86,
+  0x96, 0xaa, 0x53, 0xf9, 0xd8, 0x29, 0xdc, 0x86,
   0x88, 0x72, 0x7c, 0x29, 0xdc, 0x86, 0x88, 0xbe,
-  0x7d, 0xd7, 0x7a, 0xeb, 0x2a, 0x4e, 0xc3, 0xd8,
+  0x7d, 0xd7, 0x7a, 0xe9, 0x2a, 0x4e, 0xc3, 0xd8,
   0xf9, 0x84, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14,
   0xee, 0x43, 0x44, 0xc9, 0x3f, 0x9d, 0x82, 0x9d,
   0xc8, 0x68, 0xb7, 0xa7, 0xff, 0x39, 0x9c, 0xf7,
@@ -745,1449 +745,1501 @@
   0xfc, 0xec, 0x14, 0xee, 0x43, 0x44, 0x3b, 0x3f,
   0xf9, 0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1,
   0x2c, 0x4f, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x23,
-  0x09, 0xff, 0x9d, 0xcf, 0x76, 0x0a, 0x77, 0x21,
-  0xa2, 0x3d, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
+  0x09, 0xf0, 0xa7, 0x72, 0x1a, 0x23, 0xd9, 0xea,
+  0xf5, 0x2d, 0x8e, 0x9e, 0x77, 0x3d, 0xd8, 0x7a,
+  0x97, 0x30, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
   0x58, 0x73, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b,
-  0x9e, 0x15, 0x38, 0xaa, 0x0e, 0xde, 0xa5, 0xe3,
-  0xb6, 0x26, 0x5c, 0xee, 0x7f, 0x3b, 0x05, 0x3b,
-  0x90, 0xd1, 0x0f, 0x4f, 0x85, 0x3b, 0x90, 0xd1,
-  0x13, 0x4d, 0x76, 0x1d, 0x3f, 0xfb, 0x2d, 0xbe,
-  0x8a, 0xaf, 0xa9, 0xba, 0xb0, 0xe8, 0xa4, 0xf8,
-  0xec, 0x2d, 0x3d, 0x7d, 0x3b, 0x79, 0xa2, 0x17,
-  0x93, 0xb1, 0x1c, 0xf5, 0x84, 0x9e, 0x84, 0x73,
-  0xd7, 0xb7, 0xae, 0x74, 0xff, 0xef, 0x34, 0xfc,
-  0xa5, 0xfb, 0x99, 0xdd, 0xf3, 0xa6, 0xe6, 0xf3,
-  0xa5, 0xaa, 0x62, 0x21, 0xec, 0x45, 0xc9, 0xb3,
-  0xeb, 0x75, 0xf9, 0xe7, 0x4f, 0x7a, 0xbe, 0x01,
-  0xd3, 0x82, 0x10, 0x95, 0x3e, 0xef, 0xde, 0xd8,
-  0x53, 0x8b, 0xc9, 0xf7, 0x5d, 0xac, 0xb9, 0xd1,
-  0xb2, 0x26, 0x80, 0x7d, 0xf3, 0x59, 0xff, 0x81,
-  0xe6, 0xb7, 0x59, 0x7c, 0x3a, 0x6a, 0xce, 0x9f,
-  0xf7, 0xb5, 0xaf, 0xd6, 0xab, 0xe6, 0x1d, 0x3f,
-  0x63, 0x6d, 0x1f, 0x95, 0x3a, 0x7b, 0x36, 0xca,
-  0x0e, 0x8c, 0x4f, 0x37, 0xd0, 0xc0, 0x68, 0xc6,
-  0xc9, 0x9f, 0x3f, 0xb9, 0x7c, 0xfd, 0x81, 0x5c,
-  0xdb, 0xc7, 0x4f, 0xff, 0xfe, 0xff, 0xe9, 0x5d,
-  0x7f, 0xcd, 0xad, 0xe6, 0xb7, 0x57, 0x29, 0x78,
-  0xe0, 0x4e, 0x9f, 0x7a, 0xfa, 0x2d, 0x07, 0x4f,
-  0xea, 0x5f, 0x5d, 0x7a, 0x2d, 0x27, 0x4f, 0xee,
-  0x0e, 0x8d, 0x2d, 0xf8, 0xe8, 0xf1, 0xf5, 0xfc,
-  0xe2, 0x15, 0x33, 0x5c, 0x7f, 0x18, 0x4a, 0x4d,
-  0xa3, 0xce, 0x9d, 0xd7, 0xa9, 0xd3, 0x69, 0x41,
-  0xd3, 0xcb, 0xfb, 0xb4, 0xf3, 0x66, 0x23, 0x73,
-  0xff, 0xed, 0x16, 0xfb, 0xbf, 0xa3, 0x7e, 0xec,
-  0xbe, 0xa6, 0x5c, 0xe9, 0xff, 0xac, 0xba, 0xf7,
-  0x5f, 0xfd, 0x75, 0xb9, 0xd3, 0xfb, 0x75, 0x2f,
-  0xf5, 0xb4, 0x61, 0xd0, 0x03, 0xff, 0xfa, 0x3c,
-  0xff, 0x85, 0xad, 0xd5, 0x5f, 0x51, 0xd7, 0x3a,
-  0x14, 0xf8, 0xf4, 0x22, 0x9f, 0xff, 0xfe, 0xd3,
-  0xf5, 0x1f, 0xab, 0x5b, 0xb7, 0xdf, 0xcf, 0xca,
-  0x6f, 0x8d, 0xbf, 0x95, 0x3a, 0x4a, 0x74, 0xfe,
-  0x7f, 0x0f, 0xaa, 0xb4, 0x9d, 0x3f, 0xff, 0xff,
-  0xbc, 0x0a, 0xff, 0x3a, 0x9d, 0xdb, 0x5b, 0x4d,
-  0xdf, 0xca, 0x5f, 0x9a, 0x51, 0xfc, 0xea, 0x4e,
-  0x9d, 0xdc, 0x86, 0x8a, 0x62, 0x31, 0x17, 0xe9,
-  0x09, 0x99, 0xff, 0x67, 0xe9, 0x7d, 0x6e, 0xa2,
-  0xd1, 0xd3, 0xea, 0x7f, 0x8d, 0xb0, 0xe8, 0xf1,
-  0xf4, 0x71, 0xfc, 0xff, 0x73, 0x36, 0xb2, 0xd1,
-  0x81, 0x3a, 0x7f, 0xff, 0x7f, 0x12, 0xf7, 0x5b,
-  0xd5, 0xaf, 0xe0, 0x77, 0x2b, 0x75, 0x3a, 0x7f,
-  0xc8, 0xac, 0xb6, 0x57, 0x3d, 0xf3, 0xa1, 0x51,
-  0x49, 0x66, 0x89, 0xf0, 0xab, 0x65, 0x13, 0xa7,
-  0xee, 0xfe, 0xed, 0x97, 0xe7, 0x46, 0x1f, 0xbf,
-  0x88, 0xb4, 0x26, 0x8a, 0x17, 0x67, 0xf6, 0x4a,
-  0xd6, 0x70, 0x91, 0xa1, 0xd2, 0x45, 0xe8, 0x43,
-  0x34, 0x1e, 0x30, 0xf1, 0x64, 0x23, 0xbe, 0x43,
-  0x78, 0xd5, 0x27, 0xfd, 0xac, 0x78, 0x3b, 0xbb,
-  0x6e, 0xa0, 0xe9, 0xec, 0xfe, 0xbd, 0x59, 0xd3,
-  0xff, 0xff, 0xeb, 0x7a, 0xf6, 0xc1, 0x56, 0xdb,
-  0x99, 0xa3, 0x7e, 0xec, 0xa5, 0xf9, 0xa7, 0xc1,
-  0x53, 0xa5, 0x7f, 0x22, 0xda, 0xa4, 0xf3, 0xff,
-  0xec, 0xcb, 0x79, 0x2d, 0x9b, 0xab, 0xa5, 0x97,
-  0x56, 0x74, 0xff, 0xf5, 0xed, 0x80, 0xdc, 0xc5,
-  0xcb, 0xed, 0x9f, 0x3a, 0x7f, 0xa9, 0xdc, 0xc5,
-  0xcf, 0xdf, 0x50, 0xe9, 0x57, 0x11, 0x1f, 0xca,
-  0x32, 0xf7, 0xd3, 0x10, 0xbc, 0x3a, 0x67, 0xcf,
-  0x5a, 0x5f, 0x53, 0xa7, 0xff, 0xff, 0xfd, 0x9f,
-  0xd7, 0xbb, 0xd6, 0xd1, 0xcd, 0x7a, 0xea, 0xcf,
-  0xf6, 0xbb, 0x79, 0xd9, 0x6a, 0x40, 0xbb, 0x15,
-  0x3f, 0xff, 0xf2, 0x78, 0x3b, 0x68, 0x3b, 0xb4,
-  0x5a, 0x2a, 0x96, 0xd2, 0xd4, 0xf0, 0x4e, 0x9b,
-  0x4a, 0x29, 0x4d, 0x1b, 0xc5, 0x15, 0x85, 0x2c,
-  0x2a, 0xaf, 0x3b, 0x46, 0x73, 0xf8, 0xdd, 0x67,
-  0xff, 0x31, 0x37, 0x5b, 0x9f, 0x8c, 0xef, 0x80,
-  0xe9, 0xff, 0xf7, 0xbf, 0x7b, 0x63, 0x7d, 0xda,
-  0xcd, 0x5f, 0x7c, 0x07, 0x4f, 0xfc, 0xbf, 0xa3,
-  0xf8, 0xda, 0xba, 0x2d, 0x27, 0x45, 0x51, 0x4b,
-  0xa2, 0xec, 0xf6, 0x5f, 0x1b, 0xb3, 0xa7, 0x6a,
-  0x65, 0x8e, 0x9b, 0x36, 0x3a, 0x28, 0x4d, 0xb1,
-  0xf0, 0xef, 0xa9, 0x25, 0xc9, 0x5b, 0x0f, 0x4f,
-  0xdb, 0x2f, 0xed, 0xcf, 0x3a, 0x72, 0xec, 0xa7,
-  0x4f, 0xe6, 0x9f, 0x97, 0xaf, 0x35, 0xb8, 0xf2,
-  0x18, 0x5b, 0x3f, 0x37, 0xdb, 0xb5, 0x6a, 0x03,
-  0xa7, 0xf0, 0xb5, 0xfc, 0xb7, 0x5c, 0xe8, 0xc3,
-  0xe5, 0xf1, 0x9c, 0xfc, 0xa0, 0xcb, 0xef, 0xa0,
-  0xe8, 0x79, 0xe8, 0x7c, 0x86, 0x7f, 0xff, 0xd7,
-  0xff, 0x02, 0xb4, 0x67, 0xbf, 0x7f, 0xe3, 0x6d,
-  0xd5, 0x0f, 0xce, 0x9f, 0xf7, 0xb1, 0xad, 0xd5,
-  0x5b, 0x76, 0xac, 0xe9, 0xfd, 0xd4, 0xd6, 0xd9,
-  0xc2, 0x74, 0x6c, 0x7e, 0xb7, 0x44, 0x93, 0x0e,
-  0x9d, 0xfc, 0xd8, 0xe8, 0x53, 0x59, 0x48, 0x84,
-  0xfd, 0x4d, 0x73, 0x3f, 0xac, 0xe9, 0xe6, 0x6f,
-  0x50, 0x1d, 0x18, 0x7a, 0x5e, 0x2f, 0x85, 0x4f,
-  0x2b, 0x21, 0xcf, 0xe4, 0xf1, 0x73, 0x9f, 0xd7,
-  0xf5, 0x19, 0x6d, 0x2e, 0x74, 0xf6, 0x52, 0xad,
-  0x1d, 0x3f, 0x5b, 0x9e, 0xc1, 0xf1, 0xd3, 0xef,
-  0x00, 0x72, 0x93, 0xa3, 0x5a, 0x2a, 0xbc, 0x6a,
-  0x02, 0x2d, 0x0b, 0x27, 0xff, 0xe1, 0x7d, 0xb1,
-  0xab, 0x2f, 0xf5, 0xff, 0x2f, 0x6d, 0x0e, 0x9f,
-  0xff, 0xde, 0xca, 0x5f, 0x5b, 0xd9, 0x58, 0xbe,
-  0xdb, 0x72, 0xb7, 0x53, 0xa7, 0xff, 0xff, 0xda,
-  0x7f, 0x70, 0x7a, 0x97, 0x8f, 0x03, 0x75, 0x74,
-  0x5a, 0x6d, 0x9e, 0xfe, 0x6b, 0x3a, 0x7f, 0xfd,
-  0xa0, 0x8e, 0x5e, 0xb6, 0xf6, 0x6e, 0xb0, 0x14,
-  0xe8, 0xc4, 0x71, 0x5a, 0x11, 0x93, 0xff, 0xcf,
-  0x6f, 0xb6, 0x2f, 0xda, 0xfe, 0x5e, 0xbc, 0x74,
-  0xff, 0xfb, 0x6c, 0x66, 0xe6, 0xfb, 0xad, 0x5a,
-  0x7f, 0x0d, 0x07, 0x4f, 0xf6, 0x7e, 0x8d, 0xc0,
-  0xee, 0x68, 0xe9, 0xff, 0x57, 0x4f, 0xee, 0xae,
-  0x9a, 0x9a, 0x09, 0xd3, 0xff, 0xa8, 0xdd, 0x5b,
-  0x69, 0xba, 0xf5, 0xaa, 0x89, 0xd3, 0xff, 0xfe,
-  0xca, 0x6b, 0xec, 0x0e, 0xeb, 0x65, 0xeb, 0x94,
-  0x6e, 0xcf, 0x6c, 0x74, 0x62, 0x30, 0xbc, 0xa1,
-  0x14, 0x2b, 0x87, 0x48, 0xd3, 0x29, 0x27, 0xf2,
-  0x93, 0x17, 0x2a, 0x77, 0x78, 0xc2, 0x67, 0xfd,
-  0xc3, 0x6c, 0xba, 0xff, 0xc0, 0x3a, 0x7f, 0xb0,
-  0x34, 0xbe, 0xbb, 0xaf, 0xe3, 0xa7, 0xff, 0xfc,
-  0xa8, 0xac, 0xdc, 0xd5, 0xbd, 0xfd, 0xb7, 0x6f,
-  0x4f, 0xe5, 0xb0, 0xe8, 0x44, 0x75, 0x7c, 0xf1,
-  0xbc, 0xf2, 0x7b, 0xd7, 0xf2, 0x9d, 0x3f, 0xff,
-  0xff, 0x5d, 0x59, 0xff, 0x6b, 0xb7, 0x35, 0xbb,
-  0xfa, 0x37, 0xee, 0xca, 0x5f, 0x9a, 0x7c, 0x15,
-  0x3a, 0x1e, 0x8b, 0x8f, 0x10, 0xc2, 0xaf, 0x27,
-  0xe4, 0xbe, 0x5f, 0x46, 0xbb, 0xd0, 0xea, 0x9e,
-  0xbd, 0x78, 0x07, 0x4f, 0xfd, 0x6f, 0x6e, 0xf0,
-  0xe9, 0x47, 0x0a, 0x1d, 0x3f, 0x5f, 0x87, 0xf4,
-  0xf8, 0xe8, 0xc4, 0x4a, 0x6b, 0x21, 0xba, 0x34,
-  0xf6, 0xfd, 0x3a, 0xa7, 0x4f, 0xff, 0xde, 0x1d,
-  0xd9, 0xec, 0xfe, 0xbb, 0x7b, 0x19, 0x88, 0x74,
-  0xff, 0xff, 0x7a, 0x81, 0x56, 0x57, 0x45, 0xdc,
-  0xa2, 0xbb, 0x59, 0x58, 0x74, 0x62, 0x31, 0x05,
-  0x72, 0x7f, 0xff, 0xf0, 0x8f, 0xa8, 0xdd, 0x6c,
-  0xbf, 0xd5, 0xab, 0x65, 0x0b, 0x4d, 0xf4, 0x43,
-  0xa7, 0xff, 0xfe, 0x5d, 0x76, 0x5d, 0xdf, 0xcd,
-  0x35, 0xee, 0xa5, 0xf5, 0xf7, 0xf7, 0xad, 0x07,
-  0x4f, 0xa9, 0xaf, 0xb3, 0xe7, 0x46, 0x22, 0x9f,
-  0x47, 0xf8, 0xf2, 0x68, 0xd6, 0x8c, 0x8e, 0x7f,
-  0xbf, 0xa3, 0x5f, 0xcb, 0x75, 0xce, 0x9f, 0xed,
-  0xac, 0xa1, 0xda, 0xdc, 0xc3, 0xa7, 0xff, 0xfb,
-  0x86, 0xd9, 0x7f, 0x67, 0xe8, 0xaa, 0xe7, 0xf6,
-  0xb2, 0x9d, 0x3d, 0x7d, 0xd4, 0x09, 0xd1, 0x4a,
-  0x22, 0x79, 0x96, 0x7e, 0x6a, 0x97, 0xe8, 0xb7,
-  0x3a, 0x7f, 0xad, 0xcc, 0xfe, 0x5b, 0xae, 0x74,
-  0x29, 0xf3, 0xd4, 0xc2, 0x7e, 0xcb, 0x88, 0xe3,
-  0xce, 0x9f, 0xbf, 0x96, 0xfe, 0x21, 0xd3, 0xdf,
-  0xca, 0xee, 0x68, 0xf5, 0x6e, 0x55, 0x1b, 0x2b,
-  0xca, 0x48, 0xd9, 0xfc, 0x54, 0x27, 0x56, 0x86,
-  0x1d, 0xe1, 0x14, 0xd9, 0xda, 0x7f, 0xef, 0xff,
-  0x37, 0x0e, 0x5b, 0xf8, 0xd1, 0xd0, 0xab, 0xad,
-  0xd9, 0x39, 0x65, 0xce, 0xf3, 0xef, 0xab, 0x3b,
-  0x63, 0xa7, 0xf6, 0x35, 0x6c, 0xba, 0xec, 0x74,
-  0xff, 0xff, 0xf5, 0xb2, 0xf5, 0xe6, 0xb7, 0x7f,
-  0x29, 0x7e, 0x69, 0x47, 0xf3, 0x6b, 0x79, 0xa3,
-  0xa6, 0xd3, 0x59, 0xd0, 0x28, 0x9e, 0xbc, 0x21,
-  0x67, 0xec, 0xa3, 0xf9, 0x4d, 0x4e, 0x9f, 0xfc,
-  0x34, 0xbe, 0xb8, 0xca, 0x56, 0xd6, 0x53, 0xa5,
-  0x53, 0xa3, 0x43, 0xda, 0xde, 0x95, 0x3f, 0x95,
-  0x9f, 0xcb, 0x75, 0xce, 0x9f, 0xff, 0xf5, 0xfe,
-  0xa0, 0xa5, 0xf5, 0xd1, 0x6f, 0xfc, 0xdb, 0xd8,
-  0x2d, 0x1d, 0x1e, 0x54, 0xd8, 0xd1, 0x3f, 0x43,
-  0x47, 0xe4, 0xf5, 0x84, 0x46, 0x84, 0xbb, 0xcc,
-  0x67, 0xcf, 0xf0, 0xe5, 0x27, 0x4f, 0xb2, 0xb4,
-  0x60, 0x4e, 0x8a, 0x4f, 0x3a, 0xc4, 0xf3, 0xff,
-  0xef, 0x51, 0x89, 0xb5, 0xbd, 0x9a, 0xf7, 0x6b,
-  0xd1, 0x4e, 0x9e, 0x6f, 0xbe, 0x58, 0xe9, 0xff,
-  0xff, 0x9b, 0xe9, 0x7f, 0x53, 0xbb, 0xfa, 0x37,
-  0xee, 0xca, 0x5f, 0x9a, 0x7c, 0x15, 0x3a, 0x28,
-  0x45, 0x36, 0x12, 0x4f, 0xff, 0xff, 0x96, 0x9a,
-  0xe8, 0xb4, 0xee, 0xb6, 0x6d, 0xbb, 0xf9, 0xa6,
-  0xbd, 0xd5, 0x00, 0x3d, 0x73, 0xa7, 0xcb, 0xfa,
-  0x7a, 0x83, 0xa7, 0xff, 0xff, 0xff, 0x63, 0x31,
-  0x16, 0xca, 0xcb, 0xe5, 0x6a, 0xa2, 0x2b, 0xfc,
-  0xa3, 0x34, 0xae, 0x8d, 0x7d, 0x58, 0x74, 0xff,
-  0x03, 0x36, 0xfe, 0x5b, 0xae, 0x74, 0xfe, 0xa3,
-  0x45, 0xbb, 0x3d, 0x73, 0xa7, 0xfc, 0xba, 0xdb,
-  0xf4, 0xcf, 0xb5, 0xbd, 0x87, 0x46, 0x1f, 0xe5,
-  0x26, 0xb3, 0xff, 0xd9, 0x7d, 0xb3, 0x01, 0x5d,
-  0xc3, 0x5d, 0xaa, 0x74, 0xf5, 0x1e, 0xfd, 0xce,
-  0x85, 0x57, 0xe1, 0x84, 0x7e, 0x8c, 0x0c, 0x48,
-  0xd9, 0x09, 0x1b, 0x14, 0x74, 0x28, 0xff, 0x0b,
-  0x4a, 0x91, 0x68, 0xa5, 0x3b, 0x6d, 0xcd, 0x1d,
-  0x3f, 0xfd, 0x4b, 0xfe, 0xbb, 0x99, 0xf5, 0xd7,
-  0x7f, 0x50, 0x74, 0x61, 0xfb, 0x78, 0x82, 0x7e,
-  0xa1, 0xa7, 0xb7, 0x06, 0x83, 0xa7, 0xcc, 0xf6,
-  0xd9, 0xb1, 0xd2, 0x68, 0xe9, 0x95, 0x87, 0x4a,
-  0xe7, 0x40, 0x9a, 0x5e, 0x15, 0x8d, 0x8f, 0x56,
-  0xc6, 0xd3, 0xd7, 0xaf, 0x52, 0x74, 0xcd, 0x71,
-  0xd3, 0xfa, 0xde, 0x1a, 0x5f, 0xf5, 0x3a, 0x35,
-  0x52, 0x68, 0x0a, 0x69, 0x8f, 0xde, 0x23, 0x61,
-  0x16, 0x82, 0xd3, 0xfa, 0xbe, 0xa4, 0x3d, 0xf0,
-  0x1d, 0x3f, 0xfe, 0x51, 0x54, 0xc6, 0x2a, 0x3f,
-  0xd5, 0xd1, 0x87, 0x43, 0x48, 0x86, 0xd4, 0x34,
-  0x9d, 0xfe, 0x61, 0xd3, 0x01, 0x4e, 0x8f, 0x1b,
-  0x0f, 0x8d, 0xc9, 0xcd, 0xc7, 0x59, 0x1e, 0xb2,
-  0x81, 0xa8, 0x5d, 0xda, 0x36, 0x1c, 0x9d, 0xd2,
-  0xd7, 0x0b, 0xa4, 0x97, 0xd7, 0x4c, 0x75, 0x3e,
-  0x84, 0xdb, 0x51, 0x81, 0x8c, 0x7d, 0x8c, 0x87,
-  0x55, 0xa7, 0xa3, 0xfa, 0x1c, 0x7f, 0x9d, 0x9f,
-  0xac, 0xaa, 0x4b, 0xce, 0x58, 0xb6, 0x8c, 0x57,
-  0x52, 0x36, 0x1d, 0xf0, 0xe3, 0x6f, 0x57, 0x9f,
-  0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x53, 0xb3, 0xe1,
-  0x4e, 0xe4, 0x34, 0x54, 0x73, 0xfe, 0xe7, 0xbb,
-  0x05, 0x3b, 0x90, 0xd1, 0x34, 0x49, 0xd8, 0x7e,
-  0xcc, 0x30, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
-  0x55, 0xf3, 0xe1, 0x4e, 0xe4, 0x34, 0x56, 0xd3,
-  0xfc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x24, 0x19,
-  0x3b, 0x0f, 0xc7, 0x8c, 0x27, 0xfe, 0x77, 0x3d,
-  0xd8, 0x29, 0xdc, 0x86, 0x89, 0x0e, 0x7c, 0x29,
-  0xdc, 0x86, 0x8b, 0x12, 0x7d, 0x82, 0xbf, 0xd6,
-  0x74, 0xff, 0xcb, 0x95, 0xcf, 0xed, 0xe0, 0x2f,
-  0xce, 0x9d, 0xf5, 0xa0, 0xe9, 0x3f, 0xe7, 0xbf,
-  0xa2, 0x1c, 0xed, 0x4f, 0x00, 0xe9, 0xc2, 0xaf,
-  0x3a, 0x7d, 0xcf, 0xdf, 0x65, 0x3a, 0x7e, 0xad,
-  0x47, 0xc1, 0xd5, 0x9d, 0x1e, 0x3d, 0x9e, 0x28,
-  0x9f, 0xeb, 0x27, 0xf1, 0xb7, 0xf2, 0xa7, 0x4f,
-  0xe0, 0x2e, 0x5f, 0xdf, 0x09, 0x51, 0x89, 0xfe,
-  0xeb, 0x30, 0xa6, 0x10, 0xde, 0x29, 0x11, 0xfb,
-  0x39, 0xf1, 0x08, 0x0e, 0x67, 0xfe, 0xb7, 0x96,
-  0xf6, 0xed, 0x79, 0xf0, 0x1d, 0x3f, 0xfd, 0x94,
-  0xbe, 0xfa, 0x50, 0xeb, 0x73, 0x3d, 0x53, 0xa6,
-  0xb3, 0xb1, 0x13, 0x1f, 0x45, 0x87, 0x26, 0x7a,
-  0xb1, 0x87, 0xcf, 0xe7, 0x60, 0xa7, 0x72, 0x1a,
-  0x2c, 0xd9, 0xff, 0xce, 0x67, 0x3d, 0xd8, 0x29,
-  0xdc, 0x86, 0x8a, 0x02, 0x7f, 0x7f, 0x2e, 0x0d,
-  0xff, 0x68, 0xe9, 0xb7, 0x54, 0xe9, 0xe4, 0xee,
-  0x43, 0x45, 0xbf, 0x3f, 0x6f, 0xbf, 0x27, 0x09,
-  0xd0, 0x27, 0xae, 0x02, 0xb9, 0xf5, 0xdf, 0x5d,
-  0xf5, 0x3a, 0x7f, 0x2b, 0x6d, 0xf7, 0xfa, 0x80,
-  0xe9, 0xee, 0xf7, 0xee, 0x74, 0xfe, 0xd2, 0x9a,
-  0xaa, 0x63, 0x0e, 0x9d, 0xfc, 0x79, 0xd2, 0x72,
-  0xa7, 0x2a, 0xf3, 0x6c, 0x6f, 0x12, 0x1b, 0x15,
-  0x00, 0xdb, 0xe4, 0x37, 0x33, 0x9f, 0xf7, 0x3d,
-  0xd8, 0x29, 0xdc, 0x86, 0x8a, 0x52, 0x7f, 0x9e,
-  0xec, 0x14, 0xee, 0x43, 0x44, 0x9d, 0x27, 0x31,
-  0x10, 0xfc, 0x8d, 0x0a, 0xee, 0x2e, 0x68, 0x8c,
-  0x8b, 0x6b, 0x5a, 0xa3, 0x91, 0xd3, 0xa4, 0x2c,
-  0x7c, 0x4f, 0xab, 0x85, 0x63, 0x44, 0xcc, 0x97,
-  0x0d, 0x62, 0x90, 0x1d, 0xd6, 0x3e, 0x76, 0xd0,
-  0xfc, 0x9f, 0x0a, 0x77, 0x21, 0xa2, 0x1f, 0x9f,
-  0xf7, 0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x89, 0x4e,
-  0x4e, 0xc3, 0xf6, 0x61, 0x84, 0xfe, 0x76, 0x0a,
-  0x77, 0x21, 0xa2, 0x27, 0x9f, 0xce, 0xc1, 0x4e,
-  0xe4, 0x34, 0x46, 0x33, 0xff, 0x9c, 0xce, 0x7b,
-  0xb0, 0x53, 0xb9, 0x0d, 0x13, 0xcc, 0x2a, 0x3b,
-  0xe8, 0x27, 0x79, 0xdd, 0x8e, 0xe7, 0xc2, 0x9d,
-  0xc8, 0x68, 0x88, 0x27, 0xfd, 0xcf, 0x76, 0x0a,
-  0x77, 0x21, 0xa2, 0x54, 0x93, 0xb0, 0xfd, 0x98,
-  0x61, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0x8a,
-  0x27, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x11, 0x94,
-  0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14, 0xee, 0x43,
-  0x44, 0xcb, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68,
-  0xa9, 0x27, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x15,
-  0xd4, 0xfe, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xc5,
-  0x9f, 0xf9, 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a,
-  0x27, 0xa9, 0xfe, 0x0b, 0xb9, 0x7d, 0xa9, 0xe6,
-  0xf3, 0xa1, 0xc8, 0x8a, 0x54, 0xc9, 0xfb, 0x55,
-  0xd9, 0x7f, 0x69, 0x53, 0xa7, 0x85, 0x97, 0xa4,
-  0xe9, 0xc9, 0x96, 0x2a, 0x7f, 0xfe, 0xb7, 0xfb,
-  0x5f, 0x85, 0x5e, 0xfc, 0xa8, 0x00, 0xa7, 0x4f,
-  0xff, 0xc3, 0xe6, 0xfe, 0x63, 0x94, 0x47, 0xcd,
-  0xe9, 0xa5, 0x07, 0x4f, 0x93, 0xd6, 0xde, 0xc3,
-  0xa7, 0xff, 0x75, 0x7f, 0x80, 0x75, 0xbc, 0x9c,
-  0x27, 0x4f, 0xaf, 0x65, 0x62, 0x1d, 0x3f, 0xfb,
-  0xfb, 0x95, 0x7e, 0xac, 0xdd, 0xba, 0xda, 0x87,
-  0x4d, 0xd4, 0x9d, 0x3f, 0xba, 0xbd, 0x6d, 0x3f,
-  0x41, 0xd1, 0xf3, 0xca, 0xd0, 0x5a, 0x3c, 0xa8,
-  0x40, 0x56, 0xd8, 0xc1, 0x62, 0x9f, 0xa3, 0xdc,
-  0x99, 0xbe, 0x13, 0x93, 0xbf, 0xd7, 0x35, 0x42,
-  0xd3, 0xbf, 0xea, 0x9d, 0x20, 0xea, 0x87, 0x88,
-  0xa5, 0x13, 0xc2, 0xdb, 0x98, 0x74, 0x61, 0xe7,
-  0x78, 0xb2, 0x7f, 0xde, 0xb7, 0x5d, 0x5a, 0xaf,
-  0x98, 0x74, 0xfd, 0xef, 0xeb, 0xf6, 0x54, 0xe9,
-  0xef, 0xed, 0xbb, 0x59, 0xd3, 0xf6, 0x54, 0x3d,
-  0xfa, 0x0e, 0x8e, 0x3d, 0x4f, 0x93, 0xcf, 0xb4,
-  0xd7, 0x5d, 0x94, 0xe8, 0xc4, 0x67, 0xfa, 0x10,
-  0x76, 0x21, 0x9f, 0xff, 0xfd, 0x65, 0xf0, 0x8a,
-  0xef, 0xbf, 0xbf, 0xa3, 0xf2, 0xbb, 0x69, 0xc2,
-  0xf3, 0xa7, 0xd4, 0x6c, 0x3e, 0x09, 0xd3, 0xf6,
-  0xdc, 0x20, 0xd4, 0xc3, 0xa7, 0xfd, 0xff, 0x3e,
-  0xf6, 0xc1, 0xf5, 0x4e, 0x9f, 0xf7, 0x60, 0x17,
-  0xfd, 0xb6, 0x6b, 0x3a, 0x1e, 0x7f, 0x80, 0x3e,
-  0x9f, 0xfc, 0xb9, 0x4d, 0xec, 0xb7, 0xfa, 0x82,
-  0xa7, 0x4e, 0xad, 0x98, 0x74, 0x5c, 0xf9, 0x74,
-  0x49, 0x9f, 0xb4, 0xad, 0xeb, 0x97, 0x3a, 0x70,
-  0x42, 0x12, 0xa7, 0xff, 0x5f, 0xd7, 0xad, 0xbd,
-  0xa9, 0xbc, 0x55, 0xe5, 0x38, 0xbc, 0x8f, 0x22,
-  0xa3, 0x44, 0xa8, 0x7a, 0xac, 0x4c, 0x7a, 0xf1,
-  0x48, 0xc2, 0xaf, 0xf0, 0x87, 0xbc, 0x32, 0xe6,
-  0xd7, 0x87, 0x4f, 0x83, 0x75, 0xa4, 0x27, 0x4f,
-  0xe5, 0xe1, 0xb0, 0x7b, 0x62, 0xa6, 0x08, 0x4a,
-  0x8d, 0x8f, 0x1c, 0x26, 0x33, 0xd5, 0xbf, 0xb5,
-  0x65, 0x38, 0xd1, 0xcf, 0xfe, 0xd2, 0xb5, 0xdb,
-  0xeb, 0xb5, 0x96, 0xf5, 0x3a, 0x7f, 0xd7, 0xf0,
-  0xf0, 0x1b, 0xef, 0x96, 0x3a, 0x1e, 0x88, 0xdf,
-  0x26, 0xcf, 0xb2, 0x8c, 0xf0, 0x9d, 0x3f, 0x5d,
-  0x47, 0x6c, 0xf9, 0xd3, 0xfb, 0x6b, 0x2f, 0xc3,
-  0xd4, 0x9d, 0x3f, 0xff, 0xef, 0x33, 0xbf, 0x4b,
-  0xdc, 0x1c, 0xf3, 0x6c, 0xfe, 0x6d, 0xcf, 0x3c,
-  0x5e, 0xb0, 0xa8, 0xdc, 0xe2, 0xcd, 0x0d, 0x27,
-  0xff, 0xb2, 0xf5, 0xc6, 0xac, 0xad, 0xb2, 0xd6,
-  0x53, 0xa7, 0xff, 0xff, 0xde, 0xca, 0x6b, 0xec,
-  0x0e, 0xec, 0xa5, 0xf5, 0xf5, 0xeb, 0xea, 0x76,
-  0xdb, 0x4a, 0x0e, 0x8f, 0xa3, 0x7a, 0xea, 0x13,
-  0x78, 0x27, 0x4d, 0xbc, 0x07, 0x43, 0x46, 0xb8,
-  0x02, 0xd3, 0x9f, 0xdb, 0x1d, 0x30, 0x42, 0x74,
-  0x78, 0xf5, 0x2a, 0x44, 0x11, 0xc9, 0xd7, 0xde,
-  0x02, 0x9c, 0x6b, 0xe7, 0xff, 0xff, 0x5d, 0x76,
-  0xb6, 0x9d, 0xad, 0x9d, 0xb6, 0x67, 0xf5, 0xd6,
-  0xb9, 0xf0, 0x1d, 0x14, 0xa2, 0xaf, 0xc5, 0xd3,
-  0xfd, 0x97, 0xb2, 0x8d, 0xf1, 0x0e, 0x9c, 0xa2,
-  0xd1, 0xd1, 0x89, 0xf9, 0xf4, 0x6f, 0xff, 0x24,
-  0xd4, 0x35, 0x9f, 0x7f, 0x2f, 0xcd, 0xe7, 0x4f,
-  0xfd, 0x82, 0x38, 0xd5, 0xb2, 0xbd, 0xf3, 0xa7,
-  0xf7, 0xd4, 0x74, 0x4b, 0x29, 0xd3, 0xef, 0x6b,
-  0xb7, 0x3c, 0xe9, 0xfb, 0xca, 0xca, 0x30, 0x27,
-  0x4c, 0x10, 0x9d, 0x08, 0x7d, 0x82, 0x52, 0x12,
-  0xd9, 0xfe, 0xc6, 0xb9, 0xae, 0xa5, 0xf5, 0x29,
-  0xc6, 0xb6, 0x7f, 0xf6, 0x7c, 0x19, 0x6f, 0x53,
-  0x5b, 0x69, 0x53, 0xa7, 0xef, 0xf0, 0x36, 0xcf,
-  0x9d, 0x3f, 0x33, 0xda, 0x98, 0x3a, 0xce, 0x9c,
-  0x10, 0x84, 0xa9, 0xff, 0x94, 0x7f, 0xa7, 0x6f,
-  0xc6, 0x95, 0x87, 0x38, 0xbc, 0x8d, 0x5a, 0xa2,
-  0xe6, 0xa1, 0x95, 0x54, 0xab, 0xa6, 0x68, 0x5a,
-  0x14, 0xd9, 0xdc, 0x34, 0x1e, 0x41, 0x29, 0xe7,
-  0xe5, 0x2f, 0x3c, 0x82, 0x53, 0xab, 0xed, 0x8f,
-  0x20, 0x94, 0xc1, 0x09, 0xe4, 0x12, 0x84, 0x45,
-  0x23, 0x45, 0x17, 0x2f, 0x09, 0x54, 0xdd, 0x72,
-  0xc8, 0x24, 0xe3, 0x7b, 0x3f, 0x65, 0xb3, 0x3f,
-  0xac, 0xe9, 0xdd, 0xf0, 0x7c, 0xf7, 0xee, 0x65,
-  0x3d, 0xa9, 0x9d, 0x63, 0xa5, 0x9a, 0xb3, 0xd6,
-  0x01, 0x9c, 0xfe, 0x69, 0xfa, 0x51, 0x7f, 0x50,
-  0x54, 0xfe, 0xf3, 0xf4, 0xea, 0xdb, 0xc7, 0x49,
-  0xe5, 0x4e, 0xe1, 0xa0, 0xa8, 0x2a, 0x14, 0xda,
-  0xa0, 0x83, 0x06, 0xe7, 0xbe, 0xa0, 0x42, 0x9c,
-  0x6b, 0x21, 0x51, 0x8b, 0x90, 0x95, 0x9e, 0xd3,
-  0x85, 0xe7, 0x49, 0x87, 0x4d, 0x8f, 0xd8, 0xd8,
-  0xb4, 0x43, 0x3e, 0x0e, 0x35, 0xe6, 0x1d, 0x3f,
-  0x22, 0xb4, 0xf5, 0x01, 0x52, 0xf1, 0xd3, 0xfd,
-  0x46, 0x8f, 0xda, 0xda, 0x77, 0xce, 0x9f, 0xbc,
-  0xac, 0xa3, 0x02, 0x74, 0xfb, 0x28, 0x66, 0x30,
-  0xe9, 0xd5, 0xf0, 0x9d, 0x1f, 0x3c, 0x2b, 0x93,
-  0xcf, 0xdf, 0xe0, 0x03, 0x4a, 0x9d, 0x3f, 0x7b,
-  0x5e, 0xf5, 0x63, 0xb6, 0x4c, 0x33, 0x04, 0x04,
-  0xf6, 0xad, 0xf7, 0x22, 0x8c, 0x4f, 0x47, 0xc5,
-  0x1f, 0x8c, 0xe2, 0x7b, 0xf9, 0x46, 0x87, 0x43,
-  0xd5, 0xeb, 0xe1, 0x5d, 0xa1, 0xfb, 0xf5, 0x7a,
-  0xc7, 0xff, 0x73, 0x69, 0xff, 0xf5, 0x02, 0x39,
-  0xb7, 0x32, 0xdd, 0x7f, 0xab, 0x47, 0x4e, 0x08,
-  0x42, 0x54, 0xcf, 0x52, 0x9c, 0x5e, 0x42, 0xa2,
-  0x54, 0x5c, 0x67, 0xea, 0x1a, 0x7b, 0x70, 0x68,
-  0x3a, 0x7a, 0xdd, 0x48, 0x4e, 0x9f, 0x50, 0x3e,
-  0x56, 0x1d, 0x3f, 0xfc, 0xbb, 0xef, 0xf5, 0x07,
-  0x5c, 0x1b, 0xfe, 0xf3, 0xa3, 0x55, 0x23, 0x43,
-  0xc6, 0x9c, 0x45, 0x72, 0x79, 0xcf, 0xf7, 0xce,
-  0x9f, 0xae, 0xad, 0x7f, 0x4a, 0x9d, 0x0f, 0x3c,
-  0xbb, 0x8e, 0x4e, 0xd3, 0x46, 0xec, 0xe9, 0xb9,
-  0xcd, 0xd1, 0xb9, 0x08, 0xd5, 0x63, 0x6d, 0x57,
-  0xe4, 0x4b, 0x28, 0xaa, 0x88, 0x7f, 0xbc, 0x87,
-  0x68, 0xc3, 0xb2, 0x57, 0xc6, 0xb6, 0x64, 0x17,
-  0xf4, 0x24, 0x9a, 0x86, 0x18, 0x91, 0xb2, 0x30,
-  0x2b, 0x4b, 0x00, 0xe4, 0x5f, 0x94, 0xd6, 0x53,
-  0x7d, 0xe7, 0x74, 0x74, 0x87, 0xc6, 0xa4, 0x3c,
-  0x77, 0xc2, 0x35, 0xbc, 0x8a, 0x7f, 0xf3, 0x99,
-  0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x8a, 0x9f,
-  0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x5d, 0x13, 0xff,
-  0x3b, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x97,
-  0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xbc, 0xa1,
-  0x5b, 0xe1, 0xaa, 0x09, 0xde, 0x77, 0x87, 0x68,
-  0xa4, 0xd1, 0xdb, 0x0e, 0xed, 0x0c, 0x5f, 0xd7,
-  0x25, 0x55, 0x8e, 0xca, 0xea, 0x5a, 0x1d, 0xb6,
-  0x4c, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d,
-  0xc8, 0x68, 0x96, 0x67, 0x93, 0xb9, 0x0d, 0x11,
-  0x9c, 0xfd, 0xe5, 0x65, 0x18, 0x13, 0xa6, 0xfb,
-  0xce, 0x93, 0x0e, 0x9f, 0x78, 0x6d, 0xce, 0x13,
-  0xd3, 0x61, 0x6e, 0xf1, 0x69, 0xfb, 0x9f, 0xe1,
-  0xe1, 0x3a, 0x75, 0x56, 0x93, 0xa0, 0x53, 0x10,
-  0x63, 0xf7, 0xd3, 0x2e, 0x55, 0x3f, 0xf5, 0xfc,
-  0x3c, 0x0d, 0xd4, 0xbd, 0x58, 0x74, 0xfb, 0xea,
-  0xfa, 0xf1, 0xd1, 0xe3, 0xec, 0x6c, 0x8d, 0x3f,
-  0xff, 0x7b, 0x6d, 0x2f, 0x5a, 0x5e, 0xbf, 0x05,
-  0x77, 0x69, 0xf3, 0xa7, 0xfe, 0xc6, 0x5f, 0xc1,
-  0xaa, 0xdb, 0xb5, 0x67, 0x4f, 0xfa, 0xcb, 0xeb,
-  0x79, 0x7e, 0xd6, 0x87, 0x49, 0xd8, 0x9d, 0xbb,
-  0x50, 0xa9, 0xe2, 0x4f, 0xb1, 0xd5, 0x1e, 0x7f,
-  0xf3, 0x99, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2,
-  0x69, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d,
-  0xc8, 0x68, 0x9c, 0x67, 0xff, 0x39, 0x9c, 0xf7,
-  0x60, 0xa7, 0x72, 0x1a, 0x28, 0x19, 0xf0, 0xa7,
-  0x72, 0x1a, 0x2e, 0x09, 0x97, 0xc7, 0x4f, 0xef,
-  0xbd, 0x7d, 0xb6, 0x30, 0xe9, 0x3b, 0x0f, 0xe2,
-  0xc6, 0x1a, 0x0a, 0xcf, 0xef, 0x3b, 0x7a, 0x83,
-  0x02, 0x74, 0xff, 0x3d, 0xd8, 0x29, 0xdc, 0x86,
-  0x89, 0x26, 0x4e, 0xb1, 0xfa, 0xf1, 0xa4, 0x50,
-  0xbb, 0x5a, 0xf9, 0x63, 0x28, 0xaa, 0xd2, 0x90,
-  0x14, 0xab, 0x0c, 0xab, 0xc2, 0xaa, 0x7f, 0xda,
-  0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x52, 0x7f,
-  0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x25, 0x58,
-  0x3a, 0x4e, 0xd6, 0x89, 0x86, 0x24, 0x37, 0xa3,
-  0x4f, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x22, 0x99,
-  0xfc, 0xec, 0x14, 0xee, 0x43, 0x44, 0x69, 0x3f,
-  0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xa7, 0xe7, 0xff,
-  0x39, 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x26,
-  0xa9, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45, 0x77,
-  0x3c, 0x9d, 0xc8, 0x68, 0xaf, 0xa7, 0x04, 0x21,
-  0x2a, 0x5f, 0x29, 0xc5, 0xe4, 0x09, 0xf3, 0x31,
-  0x1e, 0x73, 0xd6, 0x93, 0xa7, 0xfd, 0x96, 0x0f,
-  0x5e, 0xab, 0x94, 0x1d, 0x3f, 0xee, 0xf0, 0xe5,
-  0x1e, 0x7e, 0x6c, 0x74, 0x9d, 0x88, 0xb8, 0x68,
-  0x87, 0xe3, 0x95, 0x3d, 0x9f, 0xfc, 0xe6, 0x73,
-  0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x9e, 0xe7, 0xf3,
-  0xb0, 0x53, 0xb9, 0x0d, 0x17, 0x0c, 0xff, 0xce,
-  0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x27, 0xc2,
-  0xab, 0xb3, 0xa0, 0xed, 0xe7, 0x7a, 0xce, 0xd0,
-  0xed, 0xa5, 0x21, 0x8d, 0x66, 0xc8, 0x75, 0x52,
-  0x6c, 0x77, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68,
-  0x8a, 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x14,
-  0xcc, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14, 0xee,
-  0x43, 0x44, 0xcf, 0x3f, 0xf9, 0xcc, 0xe7, 0xbb,
-  0x05, 0x3b, 0x90, 0xd1, 0x46, 0xc5, 0x09, 0x8d,
-  0x6c, 0x77, 0xac, 0xee, 0xea, 0x53, 0xff, 0x3b,
-  0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x75, 0x3f,
-  0x7b, 0x3f, 0xb6, 0x50, 0x74, 0xf8, 0x53, 0xb9,
-  0x0d, 0x14, 0xd4, 0xfd, 0xe5, 0x65, 0x18, 0x13,
-  0xa7, 0xff, 0xb2, 0xf6, 0xc7, 0x8f, 0x7e, 0xf6,
-  0xe7, 0x9d, 0x32, 0x80, 0xe9, 0xfe, 0xaf, 0x52,
-  0xa9, 0xe4, 0x70, 0xa2, 0x3f, 0xe5, 0xbb, 0xd3,
-  0x64, 0xed, 0x93, 0x4b, 0xc2, 0xeb, 0xc2, 0xfe,
-  0x7c, 0x29, 0xdc, 0x86, 0x8a, 0xaa, 0x7f, 0xdc,
-  0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x26, 0xd9, 0x3b,
-  0x0f, 0xd9, 0x86, 0x13, 0xf9, 0xd8, 0x29, 0xdc,
-  0x86, 0x8a, 0xfe, 0x7f, 0x3b, 0x05, 0x3b, 0x90,
-  0xd1, 0x63, 0x4f, 0x85, 0x3b, 0x90, 0xd1, 0x6a,
-  0xcf, 0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x45,
-  0x05, 0x27, 0x61, 0xfb, 0x30, 0xc2, 0x7f, 0x3b,
-  0x05, 0x3b, 0x90, 0xd1, 0x71, 0x4f, 0xe7, 0x60,
-  0xa7, 0x72, 0x1a, 0x2e, 0x99, 0xff, 0xfc, 0xb6,
-  0xfe, 0x9d, 0xab, 0xc7, 0xdb, 0x35, 0xe6, 0xcd,
-  0x68, 0x74, 0xff, 0x9f, 0x82, 0x3c, 0xfa, 0x30,
-  0x27, 0x4e, 0xff, 0x38, 0x51, 0x4b, 0x76, 0x99,
-  0xff, 0x0a, 0xd3, 0x6e, 0xad, 0xd4, 0x27, 0x4f,
-  0xda, 0xa7, 0xf2, 0xdd, 0x73, 0xa7, 0xe0, 0x73,
-  0x4f, 0xf5, 0xce, 0x9f, 0xff, 0xf6, 0xb5, 0xda,
-  0xd9, 0x4d, 0xff, 0xd6, 0x07, 0x56, 0xbc, 0x28,
-  0x74, 0xf2, 0x77, 0x21, 0xa2, 0x4c, 0x9f, 0xe1,
-  0xca, 0x6f, 0x7e, 0x7d, 0x4e, 0x81, 0x3e, 0x36,
-  0x15, 0xcf, 0xdb, 0x03, 0x54, 0xa8, 0x35, 0x0e,
-  0x9f, 0x65, 0xfc, 0xce, 0x3a, 0x7f, 0xfd, 0xc8,
-  0x2b, 0x6f, 0xe5, 0xf1, 0xc1, 0x08, 0x4a, 0x87,
-  0x9f, 0xc5, 0xc9, 0xa7, 0xff, 0x69, 0xfe, 0xba,
-  0x8d, 0x6c, 0xbf, 0xb9, 0xd3, 0x82, 0x10, 0x95,
-  0x3f, 0x0f, 0x50, 0xcf, 0x54, 0xa7, 0x17, 0x93,
-  0xec, 0x60, 0xe6, 0xac, 0xe9, 0xff, 0x31, 0x52,
-  0xdf, 0xd2, 0xeb, 0x53, 0xa7, 0xfb, 0x38, 0x1b,
-  0xb3, 0x6e, 0x79, 0xd3, 0xff, 0xba, 0x8b, 0x79,
-  0x7f, 0x8d, 0x78, 0x7c, 0x74, 0x62, 0x30, 0x6e,
-  0x7c, 0x13, 0x99, 0xf7, 0xf2, 0xdd, 0x73, 0xa7,
-  0xfc, 0xf5, 0xfd, 0x1b, 0xc7, 0xfa, 0x3c, 0xe8,
-  0xd5, 0x9f, 0x43, 0x44, 0xd3, 0xd7, 0xa3, 0x36,
-  0x3a, 0x7f, 0xbd, 0xaf, 0x78, 0x81, 0x9e, 0xa9,
-  0xd0, 0xd1, 0xf0, 0x6a, 0x11, 0xce, 0x08, 0x42,
-  0x74, 0xff, 0xfb, 0x19, 0x7f, 0xa8, 0x33, 0x6a,
-  0xe3, 0x15, 0x0a, 0x71, 0x79, 0x18, 0x99, 0x5f,
-  0xa1, 0x0f, 0x64, 0x29, 0xfa, 0xcb, 0xb9, 0x3d,
-  0x41, 0xd3, 0xf0, 0xf0, 0xfd, 0x5e, 0x74, 0x6c,
-  0x7b, 0x22, 0x5f, 0x33, 0xdc, 0xdc, 0x5e, 0x1e,
-  0x53, 0x17, 0x97, 0x64, 0x34, 0x35, 0x90, 0xd3,
-  0x0a, 0xf6, 0x88, 0xb9, 0x97, 0xe7, 0x95, 0x87,
-  0x55, 0xe3, 0xc2, 0xdf, 0x08, 0xe9, 0xf6, 0x30,
-  0x73, 0x56, 0x74, 0xff, 0xd9, 0x6f, 0xad, 0x1b,
-  0xed, 0x6e, 0xd5, 0x9d, 0x3f, 0x72, 0x38, 0x21,
-  0x09, 0xd2, 0x72, 0x32, 0x00, 0x84, 0xcf, 0xa7,
-  0x96, 0xff, 0x0d, 0x5a, 0x94, 0xb6, 0x4a, 0x87,
-  0xb3, 0x43, 0x76, 0x8e, 0x5e, 0x98, 0x59, 0x09,
-  0x3b, 0x0e, 0xc1, 0x0b, 0x1a, 0x93, 0xdc, 0xef,
-  0x4a, 0x47, 0x14, 0xfe, 0x76, 0x0a, 0x77, 0x21,
-  0xa2, 0x35, 0x9f, 0x0a, 0x77, 0x21, 0xa2, 0xa5,
-  0x9b, 0x90, 0xd1, 0x0d, 0x49, 0xd8, 0x7a, 0x3c,
-  0x61, 0x3f, 0xf3, 0xb9, 0xee, 0xc1, 0x4e, 0xe4,
-  0x34, 0x47, 0xd3, 0xf9, 0xd8, 0x29, 0xdc, 0x86,
-  0x8b, 0x1e, 0x7e, 0xd5, 0x3f, 0x96, 0xeb, 0x9d,
-  0x3f, 0xdf, 0xe0, 0x57, 0xaf, 0x7e, 0x3a, 0x78,
-  0x0c, 0xf0, 0x9d, 0x3f, 0xff, 0xca, 0x3f, 0xcd,
-  0xb2, 0xd6, 0xf2, 0x5b, 0xd7, 0xaf, 0x52, 0x74,
-  0x79, 0x10, 0xf6, 0x21, 0x9d, 0xdc, 0x86, 0x8b,
-  0x42, 0x7f, 0xdc, 0x16, 0xf4, 0xe1, 0xa3, 0x02,
-  0x74, 0x85, 0x0f, 0x94, 0x49, 0xa7, 0xe6, 0xdb,
-  0xef, 0xf5, 0x01, 0xd3, 0xe5, 0xbe, 0x59, 0x4e,
-  0x9f, 0xfe, 0xcb, 0xd7, 0x1a, 0xb2, 0xb6, 0xcb,
-  0x59, 0x4e, 0x8a, 0x0f, 0xd7, 0xe4, 0xb0, 0xa8,
-  0xc9, 0xc8, 0x53, 0x4f, 0xfd, 0x95, 0xf6, 0x9f,
-  0x78, 0xae, 0x6c, 0x74, 0xfa, 0xf6, 0xef, 0xeb,
-  0x3a, 0x7f, 0xbf, 0xa5, 0x1b, 0x5b, 0x3e, 0xa7,
-  0x4d, 0xfc, 0xc3, 0xe4, 0x42, 0x99, 0xfd, 0x96,
-  0x6b, 0xd6, 0xf3, 0x0e, 0x9f, 0xcf, 0xc1, 0xaf,
-  0xd6, 0x83, 0xa7, 0xb6, 0xcb, 0x71, 0xd3, 0xfd,
-  0x98, 0x1c, 0x44, 0xc0, 0x9d, 0x18, 0x8b, 0xba,
-  0x4d, 0x38, 0xca, 0xa4, 0x33, 0xd9, 0x6e, 0xb9,
-  0xd3, 0xfb, 0x5f, 0xbf, 0xa3, 0xf2, 0xa7, 0x49,
-  0xcd, 0xc5, 0xca, 0xb5, 0x31, 0xda, 0x17, 0xd9,
-  0x08, 0x8b, 0x43, 0xbb, 0xe4, 0xd5, 0x85, 0x45,
-  0xe1, 0xcd, 0xa8, 0x79, 0xbc, 0x82, 0x7e, 0x6f,
-  0xf6, 0xdf, 0x56, 0x8e, 0x9e, 0xcb, 0x75, 0xce,
-  0x96, 0xa9, 0x87, 0xa5, 0xf3, 0x29, 0xf0, 0xa7,
-  0x72, 0x1a, 0x2d, 0x69, 0xff, 0x73, 0xdd, 0x82,
-  0x9d, 0xc8, 0x68, 0xa0, 0xe4, 0xe6, 0xe2, 0x28,
-  0xb0, 0xb1, 0x86, 0x13, 0xff, 0x9c, 0xce, 0x7b,
-  0xb0, 0x53, 0xb9, 0x0d, 0x14, 0x5c, 0xfe, 0x76,
-  0x0a, 0x77, 0x21, 0xa2, 0xea, 0x87, 0xb2, 0x14,
-  0xd2, 0x11, 0x9e, 0x26, 0x62, 0x65, 0xa7, 0x39,
-  0x81, 0x1d, 0x4d, 0x4e, 0x6e, 0xa5, 0x3e, 0x14,
-  0xee, 0x43, 0x44, 0x43, 0x3a, 0xd9, 0xb1, 0xd2,
-  0x76, 0x1e, 0x65, 0x26, 0x13, 0xf9, 0xd8, 0x29,
-  0xdc, 0x86, 0x88, 0xda, 0x7f, 0x3b, 0x05, 0x3b,
-  0x90, 0xd1, 0x4d, 0xcf, 0xe7, 0x60, 0xa7, 0x72,
-  0x1a, 0x2a, 0x09, 0xfc, 0xec, 0x14, 0xee, 0x43,
-  0x45, 0x4d, 0x3e, 0x14, 0xee, 0x43, 0x45, 0x61,
-  0x3e, 0xf0, 0x76, 0xd0, 0x4e, 0x9f, 0xe7, 0xbb,
-  0x05, 0x3b, 0x90, 0xd1, 0x1f, 0xce, 0xc5, 0xa0,
-  0xe9, 0x3b, 0x11, 0x6a, 0x86, 0x1c, 0x53, 0xf4,
-  0x19, 0xff, 0xce, 0x67, 0x3d, 0xd8, 0x29, 0xdc,
-  0x86, 0x89, 0xbe, 0x7f, 0xe6, 0x73, 0xdd, 0x82,
-  0x9d, 0xc8, 0x68, 0x9f, 0xa7, 0xe6, 0xeb, 0xaa,
-  0xb5, 0x4d, 0x4c, 0xa4, 0xe9, 0xff, 0xe5, 0x55,
-  0x55, 0x55, 0x55, 0x5a, 0x6a, 0x74, 0xf8, 0x7d,
-  0x47, 0x30, 0xa9, 0x82, 0x12, 0xa3, 0x0d, 0xe8,
-  0x49, 0xe5, 0xa1, 0x4e, 0x34, 0x10, 0xa8, 0xc7,
-  0xac, 0x29, 0xa7, 0xe1, 0xe4, 0xb7, 0x84, 0xe9,
-  0xea, 0x19, 0xe7, 0x9d, 0x3e, 0xaf, 0xf4, 0xe7,
-  0x9d, 0x3f, 0xac, 0xac, 0x70, 0x00, 0xa7, 0x48,
-  0x54, 0xff, 0x70, 0x8f, 0xc5, 0x13, 0x81, 0x5c,
-  0x3a, 0x7f, 0xed, 0x96, 0xfd, 0x5c, 0xb5, 0xbc,
-  0xc3, 0xa7, 0x5f, 0xcd, 0x1d, 0x0a, 0x7c, 0x35,
-  0x44, 0x85, 0x4e, 0x77, 0xc4, 0xe3, 0x0a, 0x7f,
-  0x99, 0x5d, 0xf2, 0x7b, 0x9a, 0xde, 0xc3, 0xa6,
-  0xef, 0x9d, 0x02, 0x6e, 0x58, 0x49, 0x38, 0x21,
-  0x09, 0xd3, 0xd4, 0x7f, 0xca, 0x53, 0x8b, 0xc9,
-  0xea, 0x6f, 0xe4, 0x3a, 0x15, 0x11, 0xf6, 0x3c,
-  0xd0, 0xc6, 0x7f, 0xea, 0x34, 0x06, 0x7f, 0x46,
-  0x96, 0xfc, 0x74, 0xf2, 0xde, 0xa8, 0x68, 0x83,
-  0xa7, 0xee, 0xb2, 0xea, 0xf4, 0x79, 0xd0, 0x28,
-  0xa5, 0xba, 0x3b, 0x62, 0xd9, 0x87, 0x63, 0xa6,
-  0x08, 0x4e, 0x87, 0x9a, 0xc0, 0x8b, 0x4f, 0x55,
-  0x7c, 0xd8, 0xa7, 0x1a, 0x19, 0xf5, 0x77, 0xec,
-  0x0a, 0x9d, 0x1e, 0x3d, 0xed, 0xe6, 0x73, 0x82,
-  0x10, 0x95, 0x05, 0x38, 0xbc, 0x9e, 0xf0, 0x7c,
-  0xd1, 0x50, 0x86, 0xf3, 0xc3, 0x31, 0xe4, 0xde,
-  0x2d, 0x0d, 0xcf, 0xbe, 0x4e, 0xff, 0xaa, 0x74,
-  0xf6, 0xdd, 0xf0, 0x1d, 0x3f, 0xf2, 0xfc, 0x1f,
-  0x5a, 0x5a, 0x5f, 0x80, 0xe8, 0xf2, 0x20, 0xc0,
-  0x39, 0x52, 0x29, 0xf9, 0xa5, 0xc1, 0xb7, 0x8e,
-  0x9f, 0xaf, 0x8d, 0x7d, 0x58, 0x78, 0x80, 0xa7,
-  0xdd, 0xfd, 0xac, 0xa6, 0x88, 0x09, 0xc6, 0xea,
-  0x7c, 0xa0, 0xf5, 0x35, 0x3a, 0x7f, 0x0b, 0x55,
-  0xf7, 0xef, 0xe3, 0xa7, 0xa9, 0x00, 0xa9, 0x53,
-  0x04, 0x25, 0x42, 0x9b, 0x70, 0x90, 0xcf, 0xdc,
-  0x2f, 0x7f, 0xfc, 0x53, 0x8d, 0x04, 0x2a, 0x79,
-  0x38, 0x61, 0xe6, 0x6f, 0xa2, 0x5c, 0xa3, 0x48,
-  0x45, 0xcf, 0xb4, 0xbe, 0x9d, 0xbc, 0xd1, 0x03,
-  0xcf, 0xfa, 0xda, 0x50, 0xbb, 0x96, 0xeb, 0xb1,
-  0xd3, 0xb8, 0x68, 0x3a, 0x60, 0x84, 0xe9, 0xfc,
-  0x3e, 0xc6, 0xdb, 0xde, 0xe4, 0x36, 0x21, 0x1b,
-  0x8d, 0x91, 0x7e, 0x2e, 0x73, 0xff, 0x7f, 0x35,
-  0xdb, 0x9f, 0xbf, 0xa9, 0x53, 0xa1, 0x4f, 0xab,
-  0x08, 0xe7, 0xff, 0x63, 0x19, 0xcf, 0xc1, 0x4e,
-  0xe4, 0x34, 0x43, 0x11, 0x63, 0xf1, 0xf9, 0x04,
-  0xfd, 0x82, 0x9d, 0xc8, 0x68, 0x82, 0xa7, 0xaf,
-  0x55, 0x01, 0x53, 0xb8, 0x68, 0x2a, 0x7b, 0x4f,
-  0xf6, 0xb2, 0xa7, 0xf7, 0xa8, 0xcb, 0xd5, 0x40,
-  0x54, 0x15, 0x3f, 0x62, 0x2d, 0x95, 0x85, 0x4c,
-  0x10, 0x95, 0x3f, 0x7d, 0x7f, 0x47, 0x84, 0xa8,
-  0xc4, 0xc2, 0x90, 0x85, 0x83, 0x76, 0x24, 0x01,
-  0x9f, 0xc2, 0x82, 0x55, 0xbc, 0x5a, 0x6f, 0x09,
-  0x4e, 0x3f, 0x29, 0x73, 0xd3, 0xd7, 0xb4, 0x76,
-  0x33, 0xfe, 0x57, 0xf7, 0xf2, 0xa2, 0xb5, 0x3a,
-  0x7f, 0xaf, 0x65, 0x6d, 0xb2, 0x81, 0x4e, 0x9f,
-  0xe5, 0xa5, 0xfa, 0x8a, 0x98, 0xc3, 0xa1, 0x4f,
-  0xd2, 0xc7, 0x53, 0xff, 0xf3, 0x5d, 0xcf, 0xeb,
-  0x6e, 0xca, 0x34, 0xbe, 0x9d, 0xbc, 0xd1, 0x7d,
-  0xcf, 0xbd, 0x7f, 0xe3, 0xce, 0x9f, 0xf7, 0xfc,
-  0xfb, 0xdb, 0x07, 0xd5, 0x3a, 0x7f, 0x5c, 0x1b,
-  0xfe, 0xfb, 0x61, 0xe2, 0x01, 0x9d, 0xc2, 0xf3,
-  0xc4, 0x03, 0x18, 0x7d, 0x3a, 0x21, 0x4d, 0xcf,
-  0x3c, 0x40, 0x33, 0xdd, 0xfa, 0x5e, 0x78, 0x80,
-  0x67, 0xf7, 0x92, 0xd8, 0x00, 0x29, 0xe2, 0x01,
-  0x9d, 0xef, 0xec, 0x78, 0x80, 0x63, 0x64, 0x5c,
-  0xb0, 0x8a, 0xc5, 0xed, 0x8f, 0xa7, 0x0a, 0xdc,
-  0xf1, 0x00, 0xc1, 0xe2, 0x01, 0x99, 0x58, 0x78,
-  0x80, 0x63, 0x63, 0x73, 0xe1, 0x79, 0xef, 0x33,
-  0x65, 0x3c, 0x40, 0x33, 0xaf, 0xc8, 0x78, 0x80,
-  0x67, 0xfd, 0xfe, 0x7b, 0xad, 0xe4, 0xe1, 0x3c,
-  0x40, 0x33, 0x76, 0xc7, 0x88, 0x06, 0x7f, 0x7f,
-  0x83, 0x5a, 0xa8, 0x0f, 0x10, 0x0c, 0xfb, 0xda,
-  0xfb, 0xe0, 0x3c, 0x40, 0x33, 0x7a, 0xa7, 0x88,
-  0x06, 0x04, 0xf6, 0x6e, 0x6d, 0x3e, 0xbf, 0xd6,
-  0x97, 0x9a, 0x20, 0x19, 0x80, 0xa7, 0x88, 0x05,
-  0xc6, 0xd6, 0x7d, 0xe5, 0x67, 0x6c, 0x78, 0x80,
-  0x67, 0xb4, 0xef, 0xa1, 0xe2, 0x01, 0x9c, 0xa2,
-  0x87, 0x88, 0x06, 0x7f, 0xd9, 0x4d, 0x76, 0x5c,
-  0xf8, 0x2a, 0x78, 0x80, 0x67, 0xda, 0x73, 0xde,
-  0xa7, 0x88, 0x06, 0x31, 0x10, 0x16, 0x4c, 0x98,
-  0x40, 0x78, 0x80, 0x61, 0xea, 0xa3, 0xf6, 0x23,
-  0xc8, 0x4c, 0x79, 0x5a, 0xc6, 0x40, 0x34, 0xa9,
-  0x75, 0xe1, 0x4d, 0xa1, 0x14, 0xfb, 0x2f, 0x5e,
-  0xa4, 0xf1, 0x00, 0xcf, 0xed, 0x95, 0x1a, 0x15,
-  0xb9, 0xe2, 0x01, 0xd8, 0xda, 0x4e, 0x15, 0x09,
-  0xe2, 0x01, 0x84, 0x3f, 0x71, 0x50, 0x9e, 0xf7,
-  0xdf, 0x53, 0xc4, 0x03, 0x3f, 0x73, 0x4f, 0xca,
-  0x5e, 0x78, 0x80, 0x63, 0x11, 0x14, 0x02, 0x0d,
-  0x0b, 0xe7, 0xfa, 0xcb, 0x57, 0x57, 0x41, 0x01,
-  0xe2, 0x01, 0x97, 0x8f, 0x10, 0x0c, 0xdd, 0x46,
-  0xc7, 0xc7, 0x64, 0x69, 0x84, 0x07, 0x88, 0x06,
-  0x7d, 0xd7, 0xaf, 0xa9, 0x3c, 0x40, 0x33, 0xf7,
-  0xbf, 0xa3, 0xf2, 0xa7, 0x88, 0x06, 0x15, 0x12,
-  0x5f, 0x22, 0xb9, 0xac, 0x6c, 0xc8, 0x0e, 0xc8,
-  0x6d, 0xb4, 0x80, 0x2c, 0x16, 0x22, 0xe2, 0xf0,
-  0x13, 0xd6, 0x56, 0xc5, 0xe3, 0xc0, 0xd4, 0x84,
-  0x9e, 0xf8, 0x60, 0xce, 0xee, 0x43, 0x44, 0x02,
-  0xe4, 0x5e, 0x4f, 0x6b, 0xd5, 0x6d, 0x98, 0x74,
-  0xc0, 0x52, 0xa5, 0xac, 0xa9, 0xd6, 0x5a, 0x0e,
-  0x98, 0x21, 0x2a, 0x3c, 0x7b, 0x3a, 0xb1, 0x56,
-  0x84, 0x82, 0x39, 0x39, 0x9e, 0xa9, 0x4e, 0x3c,
-  0x19, 0xeb, 0xd5, 0xbf, 0x43, 0xa2, 0x86, 0x57,
-  0x4b, 0xc9, 0xd2, 0x92, 0xe3, 0xe3, 0x80, 0x43,
-  0x1b, 0x79, 0x6c, 0xfc, 0x2d, 0x3d, 0x46, 0x83,
-  0xa7, 0xfc, 0xfa, 0xee, 0xfe, 0x31, 0x47, 0x59,
-  0xd3, 0xff, 0x0d, 0xbb, 0x1e, 0xa2, 0x0d, 0xec,
-  0x3a, 0x7e, 0xde, 0x11, 0xf6, 0x58, 0xa9, 0xe6,
-  0xad, 0xcd, 0x1d, 0x3e, 0xc6, 0x9e, 0xb4, 0x9d,
-  0x3d, 0x9f, 0x57, 0x95, 0x02, 0x7d, 0x7f, 0x23,
-  0x6f, 0x28, 0x85, 0x4d, 0xef, 0x0b, 0x7c, 0x83,
-  0x64, 0x3e, 0x84, 0xcc, 0xf7, 0xbf, 0x7a, 0x9d,
-  0x3b, 0x46, 0xee, 0xa7, 0x4f, 0xfc, 0x06, 0x62,
-  0x5b, 0xdb, 0x5b, 0x4d, 0x67, 0x4f, 0xfd, 0x7a,
-  0xe6, 0xcb, 0x4d, 0x72, 0x9b, 0x9d, 0x3f, 0x9f,
-  0x95, 0xdf, 0x5b, 0xe1, 0xd0, 0xa8, 0xe4, 0xf1,
-  0x17, 0x24, 0x68, 0x8d, 0x3e, 0xe6, 0xdb, 0x6c,
-  0xa7, 0x4d, 0x5a, 0x9d, 0x38, 0x21, 0x09, 0xd3,
-  0x03, 0x8a, 0x71, 0x79, 0x02, 0x7a, 0xd5, 0x32,
-  0x9d, 0xc0, 0xc2, 0xa1, 0xe8, 0xbb, 0x64, 0x20,
-  0x35, 0x08, 0x67, 0xf5, 0xff, 0x94, 0x83, 0x7b,
-  0xce, 0x9f, 0xef, 0xe3, 0x6c, 0x70, 0x42, 0x12,
-  0xa7, 0x33, 0xae, 0x74, 0x58, 0xf5, 0x5b, 0x1d,
-  0x42, 0xa3, 0x9f, 0xc7, 0x1d, 0x08, 0xb9, 0xad,
-  0xc7, 0x4c, 0xd5, 0x4e, 0x9f, 0x9d, 0x8d, 0xbd,
-  0xfd, 0xb0, 0xd6, 0x6f, 0x15, 0x9e, 0xdb, 0x2d,
-  0xc7, 0x4f, 0xfc, 0xb9, 0xf7, 0xdb, 0x3f, 0xf5,
-  0x09, 0xd2, 0xf0, 0xa2, 0xaf, 0xe9, 0x17, 0x21,
-  0x8a, 0x1b, 0x67, 0x77, 0xc7, 0xa5, 0xb4, 0x7f,
-  0x3a, 0xcb, 0xd2, 0x15, 0xfe, 0x21, 0x1a, 0x5a,
-  0xbd, 0xa3, 0xe6, 0x02, 0x6f, 0xe3, 0x06, 0xbc,
-  0x7b, 0xcd, 0xa3, 0x0a, 0x9f, 0xec, 0x1f, 0xad,
-  0xdf, 0x96, 0x3a, 0x7e, 0xf8, 0x33, 0x6e, 0x79,
-  0xd3, 0xed, 0xed, 0x3d, 0x75, 0x65, 0x42, 0xa2,
-  0x47, 0x0d, 0xb7, 0x96, 0xcf, 0xfe, 0x1d, 0x7f,
-  0xd3, 0xb7, 0xe5, 0x7c, 0xbf, 0x3a, 0x5b, 0xcd,
-  0x10, 0x2c, 0xae, 0x6a, 0x05, 0x25, 0xeb, 0x9b,
-  0xc0, 0x8f, 0xcf, 0xfb, 0xda, 0x96, 0xf6, 0xf7,
-  0x00, 0x0a, 0x54, 0xff, 0xeb, 0xd7, 0xa9, 0xdc,
-  0xc5, 0xcf, 0xdf, 0x50, 0xe8, 0x54, 0x49, 0xf9,
-  0x12, 0x75, 0x1f, 0x79, 0xd0, 0xa9, 0xc1, 0x32,
-  0x11, 0x36, 0x85, 0xd6, 0x84, 0x53, 0xf9, 0xed,
-  0x67, 0xfa, 0xd8, 0x74, 0xff, 0xe1, 0x4f, 0xe3,
-  0x6f, 0xe2, 0x8a, 0xd4, 0xe9, 0xfd, 0xcd, 0x5b,
-  0x19, 0x95, 0x3a, 0x30, 0xfe, 0x5b, 0x23, 0xcf,
-  0xde, 0xd7, 0x7c, 0xc6, 0x1d, 0x3e, 0xcd, 0xbc,
-  0x35, 0x3a, 0x7f, 0xfa, 0xb7, 0xa5, 0x3d, 0x6d,
-  0xcd, 0xf9, 0x6f, 0x30, 0xe9, 0x2d, 0x07, 0xfa,
-  0x12, 0x78, 0xf2, 0x3d, 0xac, 0x47, 0x78, 0x55,
-  0xce, 0xdb, 0x84, 0xe9, 0xf0, 0x3b, 0xf8, 0xde,
-  0x74, 0x29, 0xe2, 0x68, 0x37, 0x3c, 0xac, 0xa5,
-  0xa3, 0xa1, 0x55, 0x2f, 0xbe, 0x3a, 0x1a, 0xbc,
-  0xdc, 0x8a, 0x78, 0x1d, 0x4d, 0x4e, 0x98, 0x21,
-  0x3a, 0x2a, 0x6e, 0x02, 0x45, 0x3f, 0x57, 0xd6,
-  0xec, 0xb1, 0x4e, 0x34, 0x33, 0x82, 0x10, 0x95,
-  0x3c, 0xfb, 0xe2, 0x14, 0xe2, 0xf2, 0x7d, 0x9b,
-  0x78, 0x15, 0x3a, 0x5c, 0x27, 0xaf, 0xf2, 0xf9,
-  0xfb, 0xf4, 0xd5, 0xac, 0xb9, 0xd3, 0xea, 0x35,
-  0x7e, 0xca, 0x4e, 0x9f, 0x7a, 0xab, 0x43, 0x0f,
-  0x97, 0xec, 0xf9, 0x78, 0x41, 0xa1, 0xf2, 0xfd,
-  0x9b, 0x9e, 0x7c, 0xbf, 0x67, 0xb4, 0x7e, 0x54,
-  0xf9, 0x7e, 0xc6, 0xc7, 0xa3, 0xf2, 0x29, 0xf2,
-  0xe5, 0x73, 0xe7, 0xcb, 0xf6, 0x0f, 0x97, 0xec,
-  0xdd, 0x73, 0xe5, 0xfa, 0xc2, 0xde, 0x4f, 0xf9,
-  0xfd, 0x68, 0x93, 0x3d, 0x9a, 0x9e, 0x01, 0xf2,
-  0xfd, 0x83, 0xe5, 0xfb, 0x30, 0x14, 0xf9, 0x7e,
-  0xcf, 0xf6, 0x03, 0x87, 0x1b, 0x66, 0xc7, 0xcb,
-  0xf6, 0x7e, 0xcb, 0x7a, 0xba, 0x50, 0x7c, 0xbf,
-  0x60, 0x08, 0xa3, 0xf9, 0x15, 0x51, 0x67, 0x86,
-  0x85, 0xb9, 0xf2, 0xfd, 0x83, 0xe5, 0xfb, 0x86,
-  0xba, 0x60, 0x84, 0xf9, 0x7e, 0xc3, 0xd5, 0x88,
-  0xec, 0x6b, 0x90, 0x84, 0xa6, 0x13, 0xa2, 0x52,
-  0xc3, 0x1a, 0xc2, 0xea, 0xeb, 0xc1, 0x26, 0x9e,
-  0xc7, 0xae, 0xb2, 0xe5, 0xfa, 0xe4, 0x47, 0xcf,
-  0xfb, 0x13, 0x6c, 0x10, 0xf5, 0x9a, 0x3a, 0x67,
-  0xd0, 0x54, 0x50, 0x89, 0x5a, 0x50, 0x7e, 0x7b,
-  0x02, 0xb9, 0x29, 0xd3, 0x8c, 0x53, 0xff, 0xf5,
-  0x2f, 0x15, 0x6d, 0xcd, 0x2e, 0xd6, 0x56, 0x73,
-  0x47, 0x42, 0xae, 0xb9, 0xe1, 0x37, 0x4e, 0x61,
-  0xe8, 0x59, 0x3f, 0xed, 0x6b, 0x4f, 0xd6, 0xd6,
-  0xd1, 0x0e, 0x9f, 0xbf, 0xda, 0xed, 0xcf, 0x3a,
-  0x70, 0x42, 0x12, 0xa7, 0x6f, 0x50, 0x14, 0xe2,
-  0xf2, 0x7f, 0xdf, 0xe7, 0xef, 0x1c, 0x6d, 0xc2,
-  0x74, 0xff, 0x7f, 0x81, 0xb9, 0xea, 0x0a, 0x4e,
-  0x8d, 0x93, 0x31, 0x62, 0x08, 0x12, 0xbe, 0x59,
-  0x73, 0xf9, 0xff, 0x7f, 0xfe, 0xd1, 0xbb, 0xae,
-  0xa2, 0xdc, 0xe9, 0xc1, 0x08, 0x4b, 0x10, 0x84,
-  0xf8, 0x53, 0xb9, 0x0b, 0x10, 0x83, 0x8d, 0x4c,
-  0xe0, 0x84, 0x25, 0x88, 0x3e, 0x0b, 0x10, 0x7b,
-  0x8d, 0x4c, 0xca, 0xcc, 0x44, 0x82, 0x34, 0xcf,
-  0xae, 0xb7, 0x56, 0x1d, 0x3d, 0xff, 0x2e, 0xb3,
-  0xa7, 0x6f, 0x50, 0x1d, 0x14, 0x1e, 0x03, 0x08,
-  0xe7, 0xc8, 0xb6, 0x56, 0x15, 0x3e, 0xff, 0x7f,
-  0xf8, 0x54, 0xd8, 0x85, 0x4c, 0x10, 0x95, 0x18,
-  0x7e, 0xb5, 0x25, 0xb9, 0x30, 0x45, 0x27, 0xf7,
-  0xf7, 0xa8, 0x2d, 0x8d, 0xe5, 0x38, 0xdd, 0xc2,
-  0xa7, 0x01, 0xe6, 0x6e, 0x86, 0x9c, 0xff, 0xeb,
-  0x28, 0x2b, 0x99, 0xb7, 0x7f, 0xb5, 0x9d, 0x3f,
-  0xab, 0xbd, 0x95, 0x0f, 0x52, 0x74, 0x2a, 0xba,
-  0xdc, 0x4c, 0xf4, 0x60, 0x23, 0x1d, 0x67, 0x1a,
-  0x55, 0x2a, 0x70, 0x42, 0x12, 0xa7, 0xcf, 0x07,
-  0x7f, 0x62, 0x9c, 0x5e, 0x4f, 0xff, 0x7e, 0x9d,
-  0xd4, 0x81, 0x7e, 0x9d, 0x47, 0xf8, 0xe9, 0xff,
-  0xec, 0x57, 0x6d, 0xf5, 0xd1, 0x33, 0x5f, 0x84,
-  0xe9, 0xe6, 0xfb, 0x01, 0xb1, 0xd0, 0xf3, 0xf7,
-  0xe5, 0x09, 0xff, 0xcf, 0xc1, 0x03, 0x3d, 0x5d,
-  0xf5, 0x5c, 0x3a, 0x7b, 0xdb, 0x63, 0x0e, 0x85,
-  0x4e, 0x39, 0xe6, 0xfd, 0x0c, 0xaf, 0x90, 0xe8,
-  0x95, 0x3f, 0x6a, 0xeb, 0xef, 0xd2, 0xf3, 0xa7,
-  0xfd, 0xc3, 0xa9, 0xeb, 0x67, 0x52, 0x03, 0xa7,
-  0xfd, 0x5a, 0xa8, 0xdd, 0x5d, 0xb7, 0x8e, 0x9f,
-  0xf7, 0xf9, 0xab, 0x70, 0x8f, 0xb6, 0x3a, 0x31,
-  0x1d, 0xe8, 0x67, 0xe4, 0x06, 0x1f, 0x4f, 0x3f,
-  0x7e, 0x34, 0x74, 0xf8, 0x76, 0xcc, 0xf9, 0xd3,
-  0xff, 0x6a, 0xfd, 0x96, 0x56, 0xd5, 0xb2, 0xd2,
-  0x74, 0x71, 0xf8, 0x54, 0x9a, 0x7f, 0xfb, 0x2f,
-  0x5c, 0x6a, 0xca, 0xdb, 0x2d, 0x65, 0x3a, 0x7f,
-  0x5d, 0xba, 0xb5, 0xf6, 0xe9, 0x46, 0x87, 0x46,
-  0xc8, 0xb4, 0xf9, 0x0d, 0xd4, 0x27, 0xff, 0xbd,
-  0x5c, 0xda, 0xf5, 0xf6, 0xbb, 0x77, 0xfc, 0x74,
-  0xff, 0xfe, 0xfd, 0xf2, 0xde, 0x5b, 0xf8, 0x0a,
-  0xf7, 0x04, 0x21, 0x2a, 0x7b, 0x6c, 0xcd, 0x65,
-  0x4e, 0x7f, 0xf4, 0x34, 0x43, 0x33, 0x82, 0x10,
-  0x95, 0x3b, 0x3e, 0x85, 0x38, 0xbc, 0x9f, 0xf6,
-  0x51, 0x9b, 0x73, 0xfe, 0xb4, 0x1d, 0x00, 0x3e,
-  0x8f, 0x94, 0xcf, 0xe7, 0xff, 0x2f, 0x7d, 0x28,
-  0x3a, 0x15, 0x38, 0x9a, 0x18, 0x69, 0x23, 0x18,
-  0x57, 0x71, 0x14, 0xf7, 0xaf, 0xe5, 0x3a, 0x7f,
-  0x69, 0x82, 0x00, 0x7b, 0xe7, 0x4f, 0xff, 0x95,
-  0xfe, 0xda, 0xdb, 0xeb, 0x82, 0x9d, 0xc8, 0x68,
-  0x83, 0x22, 0xc8, 0x94, 0xb9, 0x9c, 0xfe, 0xd4,
-  0xca, 0xea, 0x60, 0xa9, 0xd0, 0xf4, 0xc3, 0xbd,
-  0x0b, 0x5b, 0x91, 0xcf, 0xff, 0x2f, 0xe8, 0xdc,
-  0xd7, 0xbf, 0x9b, 0x67, 0xf5, 0x9d, 0x39, 0x45,
-  0xa3, 0xa1, 0x57, 0x65, 0x36, 0x3b, 0xc8, 0xd2,
-  0x10, 0xc7, 0xd1, 0xee, 0x74, 0x6b, 0xba, 0x1b,
-  0x6a, 0x2b, 0x4f, 0xef, 0xfd, 0x5e, 0xc5, 0xf1,
-  0xd3, 0xfa, 0xfe, 0x6d, 0xeb, 0xbd, 0x4a, 0x93,
-  0x0e, 0x9f, 0xb3, 0xfa, 0xc5, 0x5d, 0xe3, 0xc5,
-  0xde, 0x6b, 0x1e, 0x45, 0xf5, 0x5d, 0xe7, 0x87,
-  0x4a, 0x5e, 0x74, 0xfe, 0xfb, 0xff, 0x8c, 0x54,
-  0x3a, 0x73, 0x36, 0xc3, 0xa1, 0x4f, 0xc3, 0x08,
-  0xf8, 0xc6, 0x75, 0xfd, 0x41, 0xd3, 0xfe, 0xd2,
-  0xf5, 0xde, 0x20, 0x67, 0xaa, 0x74, 0xff, 0xcb,
-  0xfe, 0xb2, 0x81, 0xc3, 0x5a, 0x95, 0x1b, 0x22,
-  0x11, 0x88, 0x53, 0xeb, 0x7b, 0xd4, 0xd4, 0xe8,
-  0x2a, 0x7e, 0xae, 0xf5, 0x15, 0x61, 0x50, 0x54,
-  0x15, 0x05, 0x41, 0x50, 0xf3, 0xdf, 0xf0, 0x50,
-  0x0b, 0x74, 0x0a, 0xd4, 0x0a, 0x6f, 0x0a, 0x9a,
-  0xd8, 0x54, 0xfd, 0xdd, 0x76, 0x95, 0x85, 0x6e,
-  0x2d, 0x64, 0xdd, 0x95, 0x05, 0x41, 0x50, 0xf2,
-  0xd3, 0xc1, 0x50, 0x54, 0x15, 0x05, 0x41, 0x50,
-  0x54, 0x15, 0x14, 0x1b, 0xcd, 0x82, 0xbc, 0x14,
-  0x00, 0xaa, 0x85, 0x36, 0x0a, 0x82, 0xa0, 0xa8,
-  0x79, 0x69, 0x50, 0xa8, 0x2a, 0x0a, 0x82, 0xa0,
-  0xa8, 0x79, 0xa8, 0x00, 0x55, 0xc2, 0x9b, 0xc2,
-  0xa0, 0xa8, 0x2a, 0x0a, 0x82, 0xa2, 0x83, 0x51,
-  0xac, 0x28, 0x42, 0xac, 0x15, 0x2d, 0x65, 0x41,
-  0x50, 0x54, 0x15, 0x05, 0x46, 0xc6, 0xa2, 0x90,
-  0xa0, 0x05, 0x68, 0x15, 0x05, 0x41, 0x50, 0x54,
-  0xfa, 0xca, 0x0a, 0xe1, 0x50, 0x54, 0x3c, 0xf3,
-  0x90, 0x2a, 0xc1, 0x5c, 0x14, 0x02, 0x69, 0x21,
-  0x50, 0x54, 0x15, 0x05, 0x41, 0x50, 0xf3, 0x51,
-  0x48, 0x57, 0x82, 0x9b, 0x05, 0x41, 0x50, 0x54,
-  0x15, 0x05, 0x43, 0xcd, 0x46, 0xc1, 0x56, 0x0a,
-  0xf8, 0x54, 0xac, 0x54, 0x15, 0x05, 0x49, 0xe5,
-  0x41, 0x54, 0x96, 0x10, 0x54, 0x15, 0x05, 0x41,
-  0x51, 0x41, 0xf3, 0x3c, 0x2b, 0x58, 0xd2, 0x0d,
-  0x34, 0x14, 0x00, 0xab, 0x85, 0x4b, 0x0a, 0x82,
-  0xa0, 0xa9, 0x3c, 0xa8, 0x2a, 0x92, 0xc2, 0x0a,
-  0x82, 0xa1, 0x4f, 0x49, 0xe1, 0x5e, 0x1a, 0x11,
-  0xa6, 0x05, 0x41, 0x50, 0x54, 0x15, 0x05, 0x41,
-  0x50, 0xa6, 0xca, 0x90, 0xa1, 0x0a, 0x60, 0x57,
-  0xc2, 0xa0, 0xa8, 0x2a, 0x0a, 0x81, 0x2f, 0xaa,
-  0x15, 0x70, 0xa8, 0x2a, 0x0a, 0x82, 0xa1, 0x85,
-  0xf7, 0xc2, 0xae, 0x15, 0x26, 0x15, 0x05, 0x41,
-  0x50, 0x02, 0xd3, 0x40, 0xa8, 0x2a, 0x0a, 0x82,
-  0xa0, 0xa8, 0x53, 0x50, 0xd0, 0x55, 0x82, 0xb4,
-  0x0a, 0x85, 0x5f, 0xad, 0xa1, 0xc9, 0xe7, 0xbb,
-  0x14, 0xe2, 0xe2, 0x36, 0xd2, 0x91, 0xe6, 0x6d,
-  0x59, 0xeb, 0x47, 0x43, 0x08, 0xc6, 0x23, 0xd8,
-  0xdf, 0x99, 0x80, 0x79, 0xf7, 0x6a, 0xb3, 0x5d,
-  0x87, 0x47, 0x96, 0xcc, 0xa1, 0x4a, 0xd4, 0x2d,
-  0xde, 0x48, 0xde, 0x93, 0x3e, 0x7f, 0xd7, 0x2a,
-  0x53, 0x93, 0x57, 0x9d, 0xe5, 0x61, 0x53, 0xde,
-  0x4e, 0x13, 0xa7, 0x7b, 0x6c, 0x3a, 0x72, 0xef,
-  0x75, 0x28, 0x8f, 0x13, 0x9b, 0x0d, 0xdc, 0x7e,
-  0x7f, 0x5b, 0xc1, 0xd8, 0x56, 0x83, 0xa2, 0x94,
-  0x42, 0x34, 0xa1, 0x30, 0x14, 0xe9, 0xf8, 0x7b,
-  0xfb, 0xd4, 0x07, 0x4d, 0xc2, 0x74, 0xbc, 0x72,
-  0x16, 0x92, 0x43, 0xa4, 0xc3, 0xa7, 0x66, 0xa3,
-  0xbc, 0x89, 0x31, 0x15, 0xb2, 0x0f, 0x0f, 0x6f,
-  0x0f, 0x9f, 0xff, 0x68, 0xbb, 0xb8, 0x47, 0x80,
-  0xae, 0x08, 0x42, 0x74, 0x3d, 0x9b, 0x1d, 0xb4,
-  0x24, 0xd0, 0xb3, 0xd0, 0xa1, 0x68, 0x93, 0xa9,
-  0x53, 0xff, 0x85, 0xc5, 0xd7, 0xa7, 0xf2, 0xfe,
-  0xfd, 0xfd, 0x30, 0xe9, 0xf9, 0xff, 0xf3, 0xed,
-  0x87, 0x4f, 0xa8, 0xf0, 0xab, 0xce, 0x81, 0x3d,
-  0x4f, 0x96, 0xcf, 0xfa, 0xca, 0x20, 0xfe, 0x07,
-  0x80, 0x74, 0xec, 0xc6, 0x8e, 0x96, 0x58, 0xf5,
-  0xc0, 0x79, 0x3f, 0x57, 0x1b, 0x7d, 0x69, 0x3a,
-  0x79, 0x7f, 0x74, 0x3a, 0x4b, 0x88, 0xee, 0xfb,
-  0xc5, 0xc9, 0xf5, 0x0b, 0xe7, 0xb4, 0xe1, 0x79,
-  0xd3, 0xcb, 0xa3, 0x77, 0x52, 0xa7, 0xcf, 0x70,
-  0x42, 0x13, 0xa3, 0xe7, 0x9f, 0xa1, 0x3c, 0x6c,
-  0x89, 0x3c, 0x70, 0x86, 0x2a, 0x6e, 0x04, 0x6e,
-  0x9a, 0x43, 0x5e, 0x7e, 0x1d, 0x01, 0x9f, 0x43,
-  0xa7, 0xfa, 0x8f, 0xe3, 0xed, 0x80, 0xa9, 0xd3,
-  0xdb, 0x6c, 0xad, 0x8e, 0x9f, 0xff, 0x2d, 0x95,
-  0x88, 0xb7, 0xc1, 0x4e, 0xe4, 0x34, 0x5f, 0x13,
-  0xf8, 0x3d, 0x7a, 0xae, 0x50, 0x74, 0xff, 0xfd,
-  0x97, 0xde, 0xf5, 0x6d, 0xef, 0x80, 0x7c, 0xac,
-  0xc2, 0xa6, 0xbe, 0x1d, 0x3e, 0x1f, 0x51, 0xcc,
-  0x34, 0xc2, 0x73, 0xd7, 0xd1, 0x78, 0xd3, 0x09,
-  0xcc, 0x05, 0x35, 0x02, 0x73, 0xfb, 0xfd, 0xae,
-  0xea, 0x20, 0x35, 0x02, 0x73, 0xfa, 0xb9, 0x6f,
-  0x57, 0x4a, 0x0d, 0x30, 0x9c, 0xd9, 0xb1, 0xa6,
-  0x13, 0x98, 0x21, 0x3c, 0xc2, 0x71, 0x89, 0xa6,
-  0x52, 0x69, 0xe2, 0xe6, 0x11, 0x55, 0x01, 0xb2,
-  0x10, 0x48, 0xe5, 0x72, 0xcc, 0x26, 0xe3, 0xe7,
-  0x97, 0xa9, 0x4f, 0xd8, 0x31, 0xe4, 0x45, 0x55,
-  0x42, 0x5e, 0x52, 0x9c, 0x2a, 0xb9, 0xbd, 0x8e,
-  0x50, 0x96, 0xcb, 0x77, 0x95, 0x6d, 0x3e, 0xdb,
-  0x07, 0xda, 0xce, 0x9f, 0x7f, 0x37, 0xe3, 0x47,
-  0x4f, 0xf5, 0xb9, 0x96, 0xf2, 0xd2, 0xf3, 0xa7,
-  0xed, 0xff, 0x7e, 0xa7, 0x50, 0x74, 0x78, 0xfb,
-  0x00, 0x73, 0x1f, 0x45, 0xbd, 0xe1, 0x2b, 0x0a,
-  0xba, 0x43, 0x92, 0xf1, 0xfc, 0xa5, 0xd0, 0xe0,
-  0x9f, 0xfc, 0xcb, 0xd7, 0xdf, 0xa5, 0xf7, 0xf5,
-  0x7c, 0x74, 0xff, 0xfe, 0xfe, 0x53, 0x95, 0xef,
-  0xdb, 0xcb, 0x7b, 0x69, 0xcc, 0x3a, 0x7e, 0xfe,
-  0x8c, 0xf5, 0x94, 0xe9, 0xff, 0xf7, 0x7e, 0xfd,
-  0xd6, 0xfa, 0xde, 0xa1, 0xcb, 0x1d, 0x38, 0x6b,
-  0x53, 0xc4, 0x07, 0x3f, 0xfd, 0xbc, 0x56, 0xcb,
-  0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x01, 0xb8, 0xd4,
-  0x40, 0x11, 0xcb, 0x77, 0xb8, 0xc4, 0xcd, 0xbd,
-  0x18, 0x9c, 0xff, 0xfe, 0xe7, 0xe5, 0x7c, 0x23,
-  0xe6, 0x6f, 0xbd, 0xb0, 0x37, 0x3a, 0x7f, 0xff,
-  0xb9, 0xf9, 0xf6, 0x9f, 0x94, 0xbf, 0x7a, 0x81,
-  0xc1, 0x08, 0x4a, 0x8b, 0x23, 0x2f, 0xec, 0x33,
-  0xf9, 0x70, 0x53, 0xb9, 0x0d, 0x10, 0x4c, 0xff,
-  0x2d, 0xf0, 0x53, 0xb9, 0x0d, 0x17, 0xcc, 0xfb,
-  0xcd, 0xbf, 0x95, 0xd8, 0xfe, 0x90, 0xea, 0x7f,
-  0xd4, 0x75, 0x3a, 0x99, 0x7f, 0xf3, 0x63, 0xa7,
-  0x04, 0x21, 0x2a, 0x7e, 0xbd, 0xb1, 0x38, 0x4a,
-  0x71, 0x79, 0x14, 0x22, 0x67, 0xec, 0x13, 0xff,
-  0x50, 0xc5, 0xa6, 0xbf, 0xca, 0x37, 0xbc, 0xe9,
-  0xff, 0xed, 0xf4, 0xff, 0x72, 0x5b, 0xc0, 0x02,
-  0x8b, 0xce, 0x9c, 0x10, 0x84, 0xa9, 0xfd, 0xbc,
-  0x0b, 0xfc, 0xa6, 0xe5, 0x38, 0xbc, 0x9f, 0xff,
-  0x9b, 0xbd, 0xc9, 0x6f, 0x6d, 0xb6, 0x07, 0x75,
-  0xeb, 0x94, 0x1d, 0x2e, 0xb2, 0x2a, 0xf4, 0x44,
-  0x87, 0xaa, 0x8b, 0xf4, 0x36, 0x84, 0x91, 0x89,
-  0x37, 0x8c, 0x6e, 0x7f, 0xd9, 0x75, 0x1a, 0xd9,
-  0x7f, 0x73, 0xc4, 0x11, 0x3f, 0x97, 0x05, 0x3b,
-  0x90, 0xd1, 0x04, 0x38, 0xf2, 0x67, 0xee, 0xb0,
-  0x8f, 0x82, 0x74, 0xfd, 0xab, 0xd8, 0x3d, 0xf7,
-  0x9d, 0x1f, 0x3d, 0xdd, 0x0a, 0xe0, 0x08, 0xcb,
-  0xfc, 0x2a, 0x27, 0xf9, 0x7f, 0x7d, 0xf9, 0x6e,
-  0xa4, 0xe9, 0xff, 0xee, 0x0d, 0xf2, 0xcb, 0xeb,
-  0xff, 0x2d, 0xe3, 0xa1, 0xe8, 0x88, 0xf9, 0xd4,
-  0xfe, 0xbe, 0xf6, 0x54, 0x3d, 0x49, 0xd3, 0xde,
-  0x6b, 0xc1, 0x3a, 0x7f, 0xfd, 0xa5, 0x1f, 0x5c,
-  0xb3, 0x96, 0xf9, 0x6d, 0x04, 0xe9, 0xf6, 0x5e,
-  0xbb, 0xeb, 0xb1, 0xfc, 0xef, 0x23, 0x9f, 0x92,
-  0xde, 0xd4, 0xf6, 0xb3, 0xa7, 0xe6, 0x2e, 0xae,
-  0xd9, 0x41, 0xd3, 0xff, 0xff, 0xde, 0xbf, 0x33,
-  0xbe, 0x07, 0xfa, 0xba, 0x32, 0xde, 0x5b, 0xdb,
-  0x4e, 0x61, 0xd1, 0xb2, 0x38, 0xfc, 0x65, 0xc6,
-  0x33, 0x87, 0x7d, 0x4e, 0x9f, 0xf7, 0x7d, 0x30,
-  0x53, 0xb9, 0x0d, 0x10, 0x8c, 0x29, 0xf1, 0x68,
-  0x3b, 0x3f, 0xf9, 0x72, 0x9d, 0xf7, 0xf7, 0xf4,
-  0x7e, 0x54, 0xe9, 0xff, 0xee, 0xea, 0x37, 0xe5,
-  0xb9, 0x8e, 0x08, 0x42, 0x74, 0xb3, 0x64, 0x4f,
-  0x34, 0x9b, 0x38, 0x21, 0x09, 0x53, 0xfd, 0x80,
-  0xe1, 0xc6, 0xd9, 0xb1, 0x4e, 0x2f, 0x26, 0x08,
-  0x4a, 0x9c, 0x10, 0x84, 0xa9, 0xfb, 0xa8, 0xda,
-  0xcb, 0x52, 0x9c, 0x5e, 0x47, 0xd1, 0x6c, 0x14,
-  0x7d, 0x43, 0x29, 0xf2, 0x7b, 0x6d, 0xec, 0x29,
-  0xc6, 0xce, 0x70, 0x42, 0x12, 0xa7, 0x55, 0x44,
-  0xa7, 0x17, 0x92, 0x07, 0x8f, 0xfe, 0xea, 0xd3,
-  0xf6, 0xdf, 0x57, 0xf2, 0x1d, 0x3f, 0xb7, 0x8e,
-  0xde, 0x6c, 0xbb, 0x1d, 0x3f, 0xaf, 0x6c, 0x6d,
-  0x97, 0xa9, 0xd0, 0x28, 0x98, 0xb1, 0x67, 0xce,
-  0x21, 0x51, 0xdf, 0x90, 0xc0, 0x9d, 0x4e, 0xab,
-  0x9b, 0xa9, 0xd3, 0xff, 0xb3, 0x57, 0xdf, 0x06,
-  0x22, 0xd9, 0x58, 0x74, 0xfc, 0x9e, 0xad, 0xbc,
-  0xd1, 0x53, 0xfb, 0xf9, 0x4b, 0xeb, 0xed, 0x67,
-  0x4f, 0x77, 0x0e, 0xb3, 0xa3, 0x71, 0xeb, 0xd0,
-  0x6d, 0x3c, 0xbc, 0xc6, 0xc5, 0x4e, 0x08, 0x42,
-  0x54, 0xff, 0xf6, 0xf5, 0x06, 0x67, 0xef, 0x6f,
-  0x2f, 0xe8, 0x29, 0xc5, 0xe4, 0xb1, 0x11, 0x3c,
-  0xc3, 0xe8, 0x54, 0xf9, 0x1e, 0x57, 0x4a, 0x57,
-  0xa1, 0x0b, 0x68, 0x61, 0xcf, 0xff, 0x99, 0x88,
-  0xbf, 0xeb, 0xd7, 0x6d, 0x38, 0x5e, 0x74, 0xf9,
-  0x6f, 0x56, 0xd8, 0x74, 0x29, 0xfe, 0x5d, 0x52,
-  0x7f, 0xfb, 0xcd, 0xb3, 0xfb, 0x7f, 0x83, 0x9f,
-  0xed, 0x67, 0x4f, 0xff, 0xf6, 0xd6, 0xf0, 0x71,
-  0xbf, 0xcc, 0xeb, 0xd7, 0x47, 0xe5, 0x37, 0x3a,
-  0x31, 0x18, 0x1c, 0xa7, 0x0a, 0xd8, 0xef, 0xd0,
-  0x9a, 0xf8, 0xe5, 0xf6, 0x87, 0xa6, 0x4b, 0x28,
-  0xf4, 0x6d, 0x4d, 0x42, 0xc0, 0x48, 0xd9, 0x0a,
-  0xfb, 0x46, 0x4e, 0x08, 0x49, 0x7e, 0x18, 0x15,
-  0x95, 0x3b, 0x79, 0x41, 0x5a, 0x43, 0x44, 0x30,
-  0xe1, 0x9c, 0xd9, 0x7e, 0x74, 0xff, 0xf6, 0x7d,
-  0xd7, 0xd7, 0xea, 0x6b, 0x6c, 0x07, 0x1d, 0x2a,
-  0x5e, 0x7d, 0xfb, 0x0e, 0xcf, 0xd6, 0x6b, 0xd6,
-  0xf3, 0x0e, 0x9f, 0xf7, 0xd6, 0xf6, 0xe0, 0x75,
-  0x35, 0x3a, 0x73, 0x5a, 0x09, 0xd3, 0xfe, 0xef,
-  0x0e, 0x52, 0xe0, 0x84, 0x27, 0x47, 0x1e, 0xdd,
-  0x47, 0x67, 0xff, 0xbe, 0xaf, 0xdd, 0xbe, 0xfe,
-  0xfe, 0x8f, 0xca, 0x9d, 0x18, 0x99, 0xf2, 0x17,
-  0xda, 0x13, 0x20, 0x21, 0x9f, 0xcb, 0xf7, 0xff,
-  0x30, 0x07, 0x4f, 0xe7, 0xe0, 0xd7, 0xeb, 0x41,
-  0xd3, 0xff, 0xca, 0xd9, 0x45, 0xdb, 0xef, 0xfc,
-  0xa3, 0xc2, 0x7b, 0xbd, 0xe7, 0xff, 0xb2, 0xeb,
-  0xf4, 0xcb, 0xdb, 0xc2, 0x04, 0x3a, 0x7d, 0xd5,
-  0xcf, 0xdc, 0xe9, 0xd7, 0xed, 0x59, 0xd3, 0xfa,
-  0xf6, 0xf3, 0x81, 0xde, 0x3a, 0x28, 0x4c, 0x8f,
-  0x65, 0xff, 0xa6, 0x5c, 0x9b, 0x41, 0xf9, 0xfd,
-  0xa0, 0x16, 0xde, 0xe7, 0x9d, 0x3f, 0xff, 0x7f,
-  0x2b, 0xa6, 0xec, 0xb7, 0x7f, 0x1a, 0x7a, 0xd2,
-  0x74, 0xff, 0xb2, 0xba, 0x60, 0xa7, 0x72, 0x1a,
-  0x20, 0x69, 0xf6, 0x5e, 0xdc, 0xfd, 0xc8, 0xa5,
-  0xfa, 0xf4, 0xff, 0xff, 0xfd, 0x97, 0xb7, 0x7f,
-  0x5e, 0xea, 0x8f, 0x75, 0xdb, 0x66, 0xdb, 0xb1,
-  0x9d, 0xfa, 0x5e, 0x78, 0x82, 0xe7, 0xfd, 0xdd,
-  0xad, 0x3b, 0x6d, 0xda, 0xc2, 0x78, 0x82, 0xe7,
-  0xfe, 0xb7, 0xad, 0xe5, 0xfd, 0xf7, 0x6b, 0x09,
-  0xe2, 0x0b, 0x9f, 0xcb, 0xef, 0xdf, 0x76, 0xb0,
-  0x9e, 0x20, 0xb9, 0xf9, 0x99, 0xb6, 0xed, 0x61,
-  0x3c, 0x41, 0x73, 0xff, 0xfd, 0xdf, 0xff, 0x99,
-  0xba, 0xa9, 0x6f, 0x0f, 0xb5, 0xd1, 0x81, 0x3c,
-  0x41, 0x73, 0x53, 0xbb, 0x64, 0xe8, 0x51, 0x40,
-  0x55, 0xb9, 0x13, 0xe7, 0xf1, 0x65, 0x52, 0xdf,
-  0x94, 0x7d, 0x3d, 0xc2, 0x0e, 0x3a, 0x7f, 0xeb,
-  0x7a, 0xde, 0x5f, 0xdf, 0x76, 0xb0, 0x9e, 0x20,
-  0xb9, 0xfe, 0x6a, 0xa9, 0xea, 0x37, 0x6b, 0x09,
-  0xe2, 0x0b, 0x9f, 0x5e, 0xaa, 0xcd, 0xc8, 0x8a,
-  0x2d, 0xea, 0xd3, 0xff, 0xb7, 0x25, 0xbc, 0x8b,
-  0x7a, 0xee, 0xd6, 0x13, 0xc4, 0x17, 0x3f, 0xff,
-  0xf7, 0xff, 0xe6, 0x6e, 0xd3, 0x37, 0x55, 0x2d,
-  0xe1, 0xf6, 0xba, 0x30, 0x27, 0x88, 0x2e, 0x31,
-  0x32, 0x6a, 0x50, 0xf9, 0x72, 0x7f, 0xad, 0xe1,
-  0xf6, 0xba, 0x30, 0x27, 0x88, 0x2e, 0x7f, 0xfb,
-  0xba, 0x97, 0xd6, 0xde, 0xdb, 0x65, 0x15, 0x2a,
-  0x7f, 0xd8, 0xf7, 0xe9, 0x51, 0xfd, 0x1a, 0x87,
-  0x88, 0x2e, 0x11, 0x1d, 0x02, 0x91, 0x55, 0x09,
-  0xff, 0x27, 0x86, 0xfc, 0x0a, 0xee, 0x09, 0xe2,
-  0x0b, 0x9f, 0xad, 0xeb, 0x5b, 0xc0, 0x34, 0x01,
-  0x73, 0xec, 0x06, 0xed, 0x61, 0x3c, 0x41, 0x73,
-  0x65, 0xd0, 0xfc, 0xec, 0x77, 0x14, 0xa3, 0xae,
-  0xb0, 0xbf, 0x9f, 0x99, 0x9b, 0x6e, 0xd6, 0x13,
-  0xc4, 0x17, 0x3f, 0xe4, 0xb7, 0x87, 0xda, 0xe8,
-  0xc0, 0x9e, 0x20, 0xb9, 0xb3, 0x77, 0x22, 0x32,
-  0xa7, 0xf3, 0xfb, 0x4f, 0x33, 0xbf, 0x4b, 0xcf,
-  0x10, 0x5c, 0xff, 0xb3, 0xcd, 0xb3, 0xf9, 0xb7,
-  0x3c, 0xf1, 0x05, 0xb0, 0xf0, 0xa3, 0x65, 0xdc,
-  0x70, 0x16, 0x7e, 0x3e, 0x7a, 0xc6, 0x31, 0x78,
-  0xc6, 0x74, 0x85, 0xa8, 0x5c, 0x67, 0xc0, 0xa8,
-  0x00, 0xa6, 0x88, 0x2d, 0xc8, 0x80, 0x9f, 0xf6,
-  0x3e, 0xdc, 0xf6, 0xf6, 0xfd, 0x28, 0x3a, 0x7f,
-  0x0f, 0xf3, 0x6b, 0x68, 0x13, 0xa7, 0xd4, 0xdf,
-  0x84, 0x07, 0x4f, 0xd9, 0x47, 0x59, 0x75, 0x67,
-  0x47, 0x91, 0x17, 0xc6, 0x9f, 0x27, 0x9d, 0xc3,
-  0x41, 0xd3, 0x01, 0x4e, 0x9e, 0xf2, 0xb3, 0x0e,
-  0x83, 0xa7, 0xee, 0xd7, 0x75, 0x10, 0x1d, 0x1b,
-  0x1b, 0x7f, 0x85, 0x4f, 0xff, 0xe5, 0xf6, 0xdf,
-  0x5d, 0x12, 0xf8, 0x9b, 0x2a, 0x6f, 0x61, 0xd3,
-  0x01, 0x4e, 0x99, 0x75, 0x9d, 0x3f, 0xd9, 0x7a,
-  0xab, 0x37, 0xe3, 0x47, 0x4f, 0xea, 0xe5, 0xbd,
-  0x5d, 0x28, 0x3a, 0x60, 0x84, 0xa9, 0xfe, 0xfe,
-  0x36, 0xe7, 0xd7, 0xdb, 0x1d, 0x08, 0x9f, 0xbf,
-  0x86, 0xc4, 0x55, 0x8a, 0xf6, 0x22, 0x03, 0x13,
-  0x76, 0x2b, 0xf1, 0x7a, 0x9d, 0x04, 0xd7, 0x78,
-  0xb4, 0xe0, 0x84, 0x25, 0x49, 0x85, 0x38, 0xbc,
-  0x9f, 0x73, 0x5d, 0xc2, 0x53, 0x91, 0xb3, 0xbe,
-  0x17, 0x53, 0xfa, 0x9b, 0xae, 0x5b, 0x28, 0x3a,
-  0x15, 0xb2, 0x07, 0xc8, 0xda, 0x35, 0xa0, 0xd2,
-  0x63, 0xe8, 0xd5, 0x45, 0x3a, 0xd0, 0xd8, 0xea,
-  0x48, 0xf7, 0xd1, 0xab, 0x0d, 0x1d, 0x25, 0x7f,
-  0xb6, 0x4b, 0x9e, 0xc4, 0x5b, 0x9d, 0x3d, 0x8c,
-  0xcb, 0x9d, 0x3d, 0xd4, 0x6f, 0x79, 0xd0, 0xa7,
-  0xc7, 0x48, 0xfb, 0x79, 0x04, 0xfd, 0xfd, 0x36,
-  0x67, 0x3c, 0xe9, 0xff, 0xea, 0x5f, 0xf5, 0xdc,
-  0xcf, 0xae, 0xbb, 0xfa, 0x83, 0xa7, 0xf5, 0x6e,
-  0xdb, 0x3f, 0x9b, 0x1d, 0x0a, 0x8b, 0xaf, 0x17,
-  0xf2, 0xb4, 0xee, 0xdd, 0xbc, 0xe9, 0xff, 0xef,
-  0xbf, 0x76, 0x6d, 0xea, 0xd3, 0x7d, 0x3a, 0xa7,
-  0x46, 0xe3, 0xf4, 0xc1, 0xf9, 0xfa, 0x86, 0x9e,
-  0xdc, 0x1a, 0x0e, 0x99, 0xf4, 0x1d, 0x3e, 0xb6,
-  0x79, 0xf5, 0x3a, 0x7f, 0xfa, 0xcb, 0xbd, 0xd7,
-  0xff, 0x02, 0xb5, 0x50, 0x15, 0x3f, 0x81, 0x82,
-  0x9d, 0xc8, 0x78, 0x81, 0x21, 0xe8, 0xb3, 0xd8,
-  0x9c, 0x54, 0x66, 0x6f, 0x79, 0xd3, 0xd7, 0xa3,
-  0xbe, 0x74, 0xf5, 0x35, 0xeb, 0x9d, 0x14, 0x1e,
-  0xee, 0x0c, 0xd8, 0x8a, 0x7f, 0x7f, 0x83, 0x5a,
-  0xa8, 0x0e, 0x9c, 0x10, 0x84, 0xf8, 0x7d, 0x4e,
-  0xef, 0xec, 0x5c, 0x3e, 0x9c, 0x6a, 0x63, 0x64,
-  0x4a, 0x01, 0x6e, 0x7f, 0xfd, 0x9f, 0xf6, 0xb7,
-  0x56, 0xf6, 0xd3, 0x9e, 0xf5, 0x3a, 0x28, 0x3f,
-  0xcd, 0x64, 0x91, 0xaa, 0x95, 0x77, 0xbc, 0xd3,
-  0x21, 0x95, 0xe8, 0x46, 0xf4, 0x67, 0xf3, 0xef,
-  0x5d, 0x6f, 0x52, 0xa7, 0x91, 0x6f, 0x52, 0xa6,
-  0x08, 0x4a, 0x87, 0x9e, 0xee, 0x13, 0x84, 0x82,
-  0x6c, 0x09, 0x4e, 0x35, 0xd3, 0xff, 0xec, 0xba,
-  0xa6, 0x67, 0xef, 0x6f, 0x2f, 0xe8, 0x3a, 0x00,
-  0x7f, 0x01, 0x25, 0x9f, 0xff, 0xca, 0xdb, 0xdf,
-  0x06, 0xeb, 0xd7, 0x12, 0xdd, 0xfb, 0xd4, 0xe9,
-  0xfc, 0xd5, 0x2f, 0xb6, 0x8a, 0x27, 0x4e, 0x7f,
-  0x09, 0xd3, 0xe7, 0xe5, 0xf3, 0x62, 0xa5, 0xe6,
-  0x8f, 0x06, 0xe3, 0x53, 0x01, 0x4e, 0x98, 0x0a,
-  0x74, 0xfd, 0xfd, 0x1f, 0x9f, 0x77, 0x8d, 0x50,
-  0x05, 0x67, 0xfe, 0xbd, 0xb1, 0x9b, 0xd4, 0x19,
-  0x4d, 0xce, 0x9f, 0xd4, 0xa7, 0x87, 0x7a, 0xec,
-  0x74, 0xf0, 0x19, 0xcf, 0xa9, 0xfd, 0xdd, 0x1a,
-  0x76, 0xa6, 0x52, 0x74, 0x29, 0xec, 0x71, 0xcc,
-  0xe0, 0x84, 0x25, 0x4f, 0xb3, 0x5f, 0xf4, 0xa9,
-  0x4e, 0x2f, 0x27, 0xd8, 0xe0, 0x84, 0x27, 0x42,
-  0x9f, 0x05, 0xce, 0x67, 0x83, 0xdf, 0x79, 0xd3,
-  0x25, 0x8e, 0x9c, 0x10, 0x84, 0xa9, 0xfb, 0xdd,
-  0xae, 0xde, 0xb9, 0x4e, 0x2f, 0x27, 0xd8, 0x0c,
-  0xc6, 0x8e, 0x95, 0x77, 0x22, 0x54, 0x4c, 0x7e,
-  0x7d, 0x3d, 0xef, 0xe8, 0xfd, 0x91, 0xdb, 0x90,
-  0xb6, 0x85, 0x5c, 0x52, 0x79, 0x16, 0x32, 0x6b,
-  0x76, 0x15, 0x3b, 0x46, 0x31, 0x58, 0x4e, 0x5e,
-  0x30, 0xe9, 0xf9, 0x58, 0x23, 0xd7, 0x3a, 0x7f,
-  0xfb, 0xcc, 0xa5, 0xf5, 0xdd, 0x9f, 0xfe, 0x78,
-  0x07, 0x45, 0x8f, 0xf6, 0xe5, 0x52, 0x73, 0x74,
-  0x84, 0x1c, 0x4a, 0xca, 0xa6, 0xa2, 0x31, 0x67,
-  0xca, 0x4d, 0xda, 0x54, 0x16, 0x56, 0xda, 0x7a,
-  0xe3, 0x71, 0x48, 0xec, 0xa9, 0x95, 0x4f, 0xe8,
-  0x4e, 0xb5, 0x3c, 0x44, 0x33, 0xa4, 0x8c, 0x94,
-  0x17, 0x69, 0xed, 0x2e, 0xa7, 0x69, 0x82, 0x57,
-  0xdf, 0xe7, 0x57, 0xeb, 0x59, 0x14, 0x5e, 0xb3,
-  0x9f, 0xd2, 0x33, 0x56, 0xd0, 0xec, 0x0c, 0x28,
-  0xb5, 0x25, 0x89, 0x6f, 0x9d, 0xb5, 0x6f, 0x8c,
-  0x06, 0x1d, 0x08, 0x5f, 0x07, 0xe2, 0x0f, 0x56,
-  0x7f, 0x3b, 0x05, 0x3b, 0x90, 0xd1, 0x71, 0xcf,
-  0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x2e, 0xb9, 0xff,
-  0x9d, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x51,
-  0x85, 0x84, 0x4a, 0x2b, 0xca, 0x36, 0x3b, 0xd6,
-  0x76, 0x87, 0x7e, 0x87, 0x86, 0xad, 0x03, 0xb1,
-  0x0c, 0x85, 0x53, 0x8b, 0x9d, 0xb7, 0x9d, 0xcf,
-  0xfe, 0x73, 0x39, 0xee, 0xc1, 0x4e, 0xe4, 0x34,
-  0x4b, 0x53, 0xe1, 0x4e, 0xe4, 0x34, 0x46, 0xf3,
-  0xfe, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x2f,
-  0xc9, 0xd8, 0x7e, 0xcc, 0x30, 0x9f, 0xce, 0xc1,
-  0x4e, 0xe4, 0x34, 0x55, 0x73, 0xfd, 0xaf, 0x3f,
-  0x94, 0xdf, 0x98, 0x74, 0xdb, 0x78, 0xe9, 0xfb,
-  0x05, 0x3b, 0x90, 0xd1, 0x20, 0x46, 0xe3, 0xcc,
-  0x70, 0xbc, 0xfa, 0xbd, 0xfe, 0xa4, 0xe8, 0x79,
-  0xe5, 0xd2, 0x49, 0x1a, 0xd1, 0xe9, 0xd0, 0xd1,
-  0x9f, 0xfb, 0xf9, 0x43, 0xb5, 0x17, 0xff, 0xcb,
-  0x9d, 0x0e, 0x3f, 0x01, 0x29, 0x9f, 0xce, 0xc1,
-  0x4e, 0xe4, 0x34, 0x59, 0x13, 0xf9, 0xd8, 0x29,
-  0xdc, 0x86, 0x8b, 0x5e, 0x7f, 0x3b, 0x05, 0x3b,
-  0x90, 0xd1, 0x72, 0x4f, 0x85, 0x3b, 0x90, 0xd1,
-  0x76, 0x4f, 0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43,
-  0x45, 0x1d, 0x27, 0x61, 0xfb, 0x30, 0xc2, 0x7c,
-  0x29, 0xdc, 0x86, 0x8a, 0x56, 0x7f, 0xff, 0xfa,
-  0xcb, 0x42, 0xdb, 0xcd, 0xbb, 0x6b, 0x79, 0xc9,
-  0x6f, 0x35, 0x65, 0xa3, 0x0e, 0x9f, 0x39, 0x9c,
-  0xf7, 0x62, 0x2c, 0x9a, 0x30, 0x8a, 0x17, 0x3b,
-  0xdf, 0x0c, 0x8a, 0x49, 0xfd, 0x1c, 0xfb, 0x08,
-  0x40, 0x77, 0x53, 0xbb, 0xc2, 0xc5, 0xb4, 0x36,
-  0x67, 0xf9, 0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x47,
-  0x13, 0xfd, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x2b,
-  0x59, 0x3b, 0x91, 0x05, 0x74, 0x19, 0xff, 0xce,
-  0x67, 0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x89, 0x6e,
-  0x6c, 0xa4, 0xe9, 0xfd, 0xb6, 0x31, 0x8b, 0xea,
-  0x9d, 0x14, 0x9e, 0x4f, 0x85, 0xa7, 0x5b, 0x67,
-  0x9d, 0x39, 0xec, 0x43, 0xa0, 0xd1, 0x0d, 0xcf,
-  0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0xc1,
-  0x38, 0x74, 0x01, 0x53, 0xfb, 0xf9, 0x7b, 0xa8,
-  0xd4, 0xe9, 0x39, 0x53, 0x05, 0xa0, 0x8f, 0x61,
-  0xd4, 0x1b, 0x60, 0xbd, 0xd1, 0xb7, 0x8e, 0x4e,
-  0x66, 0x82, 0x54, 0xff, 0xb9, 0xee, 0xc1, 0x4e,
-  0xe4, 0x34, 0x4c, 0x72, 0x77, 0x8f, 0x89, 0x83,
-  0x93, 0xf2, 0xd7, 0x75, 0xf2, 0xc7, 0x4f, 0xff,
-  0xff, 0x3e, 0xb6, 0xcd, 0x03, 0x5b, 0x62, 0x65,
-  0x77, 0x65, 0x2f, 0xaf, 0xbf, 0xe3, 0xa7, 0x93,
-  0xb9, 0x0d, 0x15, 0x8c, 0xff, 0xb5, 0x32, 0xff,
-  0xcd, 0x17, 0xf7, 0x3a, 0x35, 0xa6, 0x37, 0x49,
-  0x70, 0xc2, 0x06, 0xe5, 0x73, 0xff, 0x97, 0xf7,
-  0xd7, 0xa2, 0xff, 0x11, 0x44, 0xe9, 0xff, 0x66,
-  0xd6, 0xca, 0xd2, 0xf5, 0xb1, 0xd3, 0xff, 0xff,
-  0x7f, 0x4a, 0x31, 0x37, 0x7f, 0x46, 0xfd, 0xd9,
-  0x4b, 0xf3, 0x4f, 0x82, 0xa7, 0x4f, 0xed, 0x55,
-  0x43, 0x4f, 0x6e, 0x0d, 0x07, 0x4e, 0xb7, 0x9d,
-  0x89, 0xc5, 0xa2, 0x2d, 0x92, 0x6e, 0x7f, 0xa8,
-  0xfd, 0x36, 0x8d, 0x1d, 0x3e, 0xef, 0xd1, 0xa5,
-  0x4e, 0x8f, 0x9e, 0x0d, 0x46, 0x27, 0x94, 0x7b,
-  0xe7, 0x4f, 0x56, 0xaa, 0x03, 0xa2, 0xc7, 0x80,
-  0x11, 0xf9, 0xf2, 0xbc, 0x1a, 0x3c, 0xe9, 0xcb,
-  0xf7, 0x9d, 0x0d, 0x1e, 0x1d, 0xca, 0x27, 0xe5,
-  0x66, 0x7f, 0xda, 0xce, 0x95, 0x4e, 0x8f, 0x1b,
-  0xee, 0x2e, 0x98, 0x0a, 0x54, 0xc1, 0x09, 0x51,
-  0xe3, 0x56, 0x11, 0x59, 0xfd, 0xcf, 0xfe, 0x5e,
-  0xde, 0x29, 0xc6, 0x86, 0x7b, 0x6e, 0xa6, 0xa7,
-  0x4e, 0x5f, 0xb4, 0x74, 0xdf, 0x53, 0xa1, 0xa3,
-  0x62, 0x23, 0x93, 0xc2, 0x0c, 0x6f, 0x3a, 0x76,
-  0xf1, 0xd6, 0x74, 0x2a, 0x2d, 0xf1, 0x53, 0xc4,
-  0x36, 0x23, 0x9a, 0xd7, 0x3a, 0x70, 0x42, 0x12,
-  0xa7, 0xfe, 0xc4, 0xd9, 0x68, 0xdf, 0x96, 0xea,
-  0x4a, 0x71, 0x79, 0x3d, 0xe1, 0x6f, 0xd8, 0xe9,
-  0x09, 0xd3, 0xe6, 0x7a, 0xe0, 0xe3, 0xa2, 0x83,
-  0xdb, 0xd5, 0x92, 0xe8, 0x1f, 0x3f, 0x93, 0xd5,
-  0xfe, 0x36, 0xe3, 0xa6, 0xcb, 0x9d, 0x14, 0x9e,
-  0x45, 0x8c, 0xe7, 0xff, 0xaf, 0xea, 0xdb, 0x36,
-  0xfe, 0x36, 0xfe, 0x54, 0xe9, 0x39, 0x57, 0x27,
-  0x36, 0x62, 0xc6, 0x51, 0x61, 0x63, 0x65, 0xa1,
-  0xf3, 0xc7, 0x7f, 0x32, 0xac, 0x2c, 0x2e, 0xfb,
-  0xbc, 0x8e, 0x7c, 0x29, 0xdc, 0x86, 0x8a, 0xde,
-  0x7f, 0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x27,
-  0x09, 0x3b, 0x0f, 0xd9, 0x86, 0x13, 0xe1, 0x4e,
-  0xe4, 0x34, 0x5a, 0x33, 0xd8, 0xd7, 0xb5, 0x9d,
-  0x27, 0x61, 0xea, 0x58, 0xc2, 0x79, 0x3b, 0x90,
-  0xd1, 0x6d, 0x4f, 0xd6, 0x56, 0x2f, 0xb6, 0x3a,
-  0x67, 0x60, 0x9e, 0xc5, 0xca, 0xe7, 0xf3, 0xb0,
-  0x53, 0xb9, 0x0d, 0x17, 0x2c, 0xfe, 0x76, 0x0a,
-  0x77, 0x21, 0xa2, 0xed, 0x85, 0x66, 0xae, 0x50,
-  0x50, 0xf8, 0xe8, 0x36, 0x86, 0x7e, 0xb9, 0x59,
-  0xde, 0x9d, 0x3b, 0xd5, 0xc6, 0x41, 0x67, 0xbf,
-  0xbf, 0xd4, 0xb2, 0xe7, 0x73, 0xf9, 0xd8, 0x29,
-  0xdc, 0x86, 0x8a, 0x9e, 0x79, 0x3b, 0x90, 0xd1,
-  0x5c, 0xcf, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x2c,
-  0xe8, 0x13, 0xe6, 0xb1, 0x5c, 0xf8, 0x53, 0xb9,
-  0x0d, 0x12, 0x14, 0xff, 0x7a, 0x9a, 0xdf, 0xea,
-  0xca, 0x9d, 0x33, 0xdd, 0x87, 0xd4, 0x03, 0x09,
-  0xe6, 0xe9, 0x65, 0x61, 0xd3, 0xfb, 0x2d, 0x5a,
-  0xe0, 0xd0, 0x74, 0x9d, 0x89, 0x88, 0xf4, 0x22,
-  0xea, 0x5b, 0x72, 0x79, 0xff, 0xce, 0x67, 0x3d,
-  0xd8, 0x29, 0xdc, 0x86, 0x89, 0xf2, 0x11, 0x52,
-  0x5e, 0xae, 0x3b, 0x2b, 0x23, 0xcf, 0x85, 0x3b,
-  0x90, 0xd1, 0x59, 0x4f, 0xfb, 0x9e, 0xec, 0x14,
-  0xee, 0x43, 0x44, 0xdd, 0x37, 0x9d, 0x87, 0xec,
-  0xc3, 0x09, 0xf0, 0xa7, 0x72, 0x1a, 0x25, 0x69,
-  0xfe, 0xd7, 0x6f, 0x6e, 0xd1, 0x32, 0xa7, 0x4f,
-  0x9c, 0xce, 0x7b, 0xb0, 0xfb, 0x78, 0xc2, 0x7c,
-  0x29, 0xdc, 0x86, 0x89, 0x72, 0x7f, 0xbd, 0xcf,
-  0xbf, 0xd5, 0x95, 0x3a, 0x79, 0xb7, 0xbe, 0xa7,
-  0x4f, 0x9c, 0xce, 0x7b, 0xb1, 0x11, 0x76, 0x30,
-  0xe3, 0x89, 0xff, 0x9d, 0xcf, 0x76, 0x0a, 0x77,
-  0x21, 0xa2, 0x3b, 0x9f, 0xeb, 0xdb, 0x1e, 0xee,
-  0xfd, 0x4e, 0x9f, 0x9b, 0x9f, 0x54, 0xcf, 0x9d,
-  0x3f, 0x6a, 0x9f, 0xcb, 0x75, 0xce, 0x9f, 0x0a,
-  0x77, 0x21, 0xa2, 0xa1, 0x9f, 0x65, 0xaf, 0x94,
-  0x1d, 0x27, 0x6a, 0x88, 0xb7, 0x6e, 0x17, 0xe1,
-  0x8d, 0xcc, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0xaa,
-  0x27, 0xfd, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2,
-  0x6b, 0x93, 0xb0, 0xfd, 0x98, 0x61, 0x3f, 0x9d,
-  0x82, 0x9d, 0xc8, 0x68, 0xab, 0x27, 0xfe, 0x77,
-  0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x89, 0x12, 0x7c,
-  0x29, 0xdc, 0x86, 0x8b, 0x4a, 0x7f, 0xdc, 0xf7,
-  0x60, 0xa7, 0x72, 0x1a, 0x27, 0xd9, 0x3b, 0x0f,
-  0xd9, 0x86, 0x13, 0xff, 0x9c, 0xce, 0x7b, 0xb0,
-  0x53, 0xb9, 0x0d, 0x14, 0x24, 0xfa, 0xde, 0xa1,
-  0x44, 0xe9, 0xf0, 0xa7, 0x72, 0x1a, 0x28, 0xf9,
-  0xff, 0xfb, 0x36, 0xb2, 0xef, 0x75, 0xff, 0xc0,
-  0xad, 0x54, 0x05, 0x4f, 0x9c, 0xce, 0x7b, 0x95,
-  0x16, 0x98, 0x4f, 0xa8, 0x61, 0x0a, 0xbb, 0x5d,
-  0x44, 0x32, 0x1e, 0x97, 0x89, 0x9a, 0xe1, 0xde,
-  0x90, 0xc1, 0xa4, 0x9d, 0xa3, 0xbb, 0x43, 0x08,
-  0x04, 0xf7, 0x8c, 0x1a, 0x7f, 0x3b, 0x05, 0x3b,
-  0x90, 0xd1, 0x11, 0x4f, 0xd8, 0x29, 0xdc, 0x86,
-  0x88, 0xae, 0x7f, 0xb5, 0x6e, 0xc1, 0x4e, 0xe4,
-  0x34, 0x57, 0x10, 0xe3, 0xfa, 0xe3, 0x59, 0xec,
-  0xb7, 0x5c, 0xe9, 0xfd, 0x9e, 0x10, 0x03, 0x4a,
-  0x9d, 0x2d, 0x53, 0xe7, 0xa7, 0x52, 0x09, 0xff,
-  0xbb, 0xcf, 0xf7, 0xef, 0xa5, 0x87, 0x0e, 0x9f,
-  0x67, 0xb6, 0x1c, 0x3a, 0x75, 0xeb, 0xeb, 0x1f,
-  0x55, 0xd1, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0xa7,
-  0xa1, 0xb8, 0x8f, 0xb5, 0x84, 0xbe, 0x1a, 0x4f,
-  0xfe, 0xe7, 0xbb, 0x6f, 0xf0, 0x6b, 0x55, 0x01,
-  0xd0, 0xe4, 0x40, 0xec, 0x6f, 0x39, 0xdb, 0x61,
-  0xd3, 0xe5, 0x78, 0x34, 0x79, 0xd3, 0xc9, 0xdc,
-  0x86, 0x8a, 0xce, 0x1a, 0x3d, 0x31, 0x28, 0x9f,
-  0xa8, 0x62, 0xfd, 0xf5, 0x3a, 0x72, 0xd1, 0xe3,
-  0xa7, 0xd7, 0x06, 0xff, 0xbc, 0xe9, 0xf6, 0x35,
-  0x46, 0x80, 0x3a, 0x4e, 0xc4, 0x60, 0x09, 0x15,
-  0x8b, 0xb8, 0x73, 0x79, 0x54, 0xff, 0xce, 0xe7,
-  0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x22, 0xcf, 0xe7,
-  0x60, 0xa7, 0x72, 0x1a, 0x2c, 0x99, 0xfc, 0xec,
-  0x14, 0xee, 0x43, 0x45, 0xb1, 0x3b, 0x2b, 0x87,
-  0x4f, 0x85, 0x3b, 0x90, 0xd1, 0x6d, 0xc9, 0xcf,
-  0x3c, 0xac, 0x1a, 0x9f, 0xf3, 0x71, 0xb9, 0xaa,
-  0xd7, 0xb6, 0x7d, 0x40, 0x74, 0xfc, 0xbf, 0x7e,
-  0xda, 0x30, 0xe9, 0xf0, 0xa7, 0x72, 0x1a, 0x2f,
-  0x09, 0xeb, 0xea, 0x65, 0x8e, 0x9f, 0xf9, 0x77,
-  0xb2, 0x97, 0xdf, 0x3f, 0x7a, 0x9d, 0x3e, 0xcf,
-  0x81, 0xbd, 0x4e, 0x9f, 0x2e, 0xfd, 0x3a, 0xa7,
-  0x4e, 0xba, 0x80, 0xe9, 0x3b, 0x55, 0xe4, 0xe1,
-  0x28, 0x4d, 0xc2, 0xfa, 0x4c, 0x2c, 0x48, 0x04,
-  0x7f, 0x94, 0xdc, 0xa6, 0x77, 0xb2, 0x93, 0xa7,
-  0xc2, 0x9d, 0xc8, 0x68, 0xbd, 0x27, 0xfd, 0xfe,
-  0xbb, 0xd7, 0x5d, 0xfd, 0x41, 0xd3, 0xec, 0x65,
-  0xbb, 0x63, 0xa4, 0xed, 0x91, 0x69, 0x83, 0x9b,
-  0xcc, 0x1b, 0xd0, 0x61, 0x59, 0x0f, 0x94, 0x42,
-  0xd7, 0x23, 0xf0, 0x42, 0x4f, 0x46, 0x5e, 0x29,
-  0xec, 0x4c, 0x01, 0xdf, 0xe1, 0x0b, 0xa4, 0x75,
-  0x61, 0x8c, 0xda, 0x7b, 0x2d, 0xd7, 0x3a, 0x7f,
-  0x67, 0x84, 0x00, 0xd2, 0xa7, 0x4b, 0x54, 0xf9,
-  0xe9, 0xd4, 0x82, 0x7c, 0x29, 0xdc, 0x86, 0x88,
-  0x8e, 0x7f, 0xfa, 0xda, 0x56, 0xb8, 0xcf, 0xe3,
-  0x6d, 0xca, 0xdd, 0x4e, 0x9f, 0xf3, 0xd6, 0x81,
-  0xcb, 0xdf, 0xd7, 0x3a, 0x7f, 0xff, 0x96, 0xdd,
-  0xeb, 0xad, 0xbf, 0x97, 0xb7, 0xad, 0x9e, 0x09,
-  0xd3, 0x50, 0xc2, 0xa6, 0x08, 0x4a, 0x9f, 0xf9,
-  0xee, 0x4b, 0x79, 0xab, 0x2d, 0x0e, 0x01, 0xad,
-  0x08, 0xbc, 0xfe, 0xcd, 0x5f, 0xf2, 0xdd, 0x73,
-  0xa7, 0xff, 0xe4, 0x70, 0xf7, 0xfd, 0x77, 0x0a,
-  0xdf, 0xfc, 0x03, 0xa1, 0xb8, 0xa9, 0xc7, 0x0b,
-  0x50, 0xc2, 0x95, 0xa1, 0x3e, 0xe8, 0x49, 0x5d,
-  0x75, 0xb1, 0xac, 0xf8, 0x53, 0xb9, 0x0d, 0x11,
-  0x74, 0xfa, 0xe0, 0xdf, 0xf7, 0x96, 0xcf, 0x69,
-  0x3b, 0x0f, 0x9f, 0x8c, 0x21, 0xc9, 0x84, 0x3e,
-  0x1c, 0x53, 0xff, 0x33, 0x9e, 0xec, 0x14, 0xee,
-  0x43, 0x44, 0xcd, 0x3a, 0x95, 0xa9, 0xd3, 0x93,
-  0xcc, 0x3a, 0x76, 0xaa, 0xd4, 0xd5, 0x47, 0x4f,
-  0x93, 0xad, 0xe6, 0x8e, 0x9f, 0xf9, 0xbf, 0xd7,
-  0xf2, 0x7b, 0x6b, 0xe2, 0x1d, 0x3f, 0xff, 0xda,
-  0x77, 0xd3, 0xf9, 0xb5, 0xb4, 0xdd, 0x65, 0x78,
-  0xad, 0x07, 0x46, 0x22, 0xc6, 0xc8, 0xf3, 0xff,
-  0xed, 0xbd, 0xfa, 0x32, 0xbe, 0xeb, 0x38, 0x21,
-  0x09, 0x53, 0xc9, 0xdc, 0x86, 0x8b, 0x3e, 0x7f,
-  0xfb, 0xc3, 0x6e, 0xdd, 0x8d, 0xbf, 0x95, 0xcf,
-  0x9d, 0x38, 0x21, 0x09, 0x53, 0xfe, 0xe7, 0xd7,
-  0xf8, 0x9b, 0x60, 0x94, 0xe2, 0xf2, 0x7f, 0x96,
-  0xde, 0xdb, 0xfd, 0xcd, 0x1d, 0x3f, 0xde, 0xfe,
-  0xdb, 0xf6, 0xd2, 0xf5, 0x3a, 0x11, 0x3b, 0x31,
-  0x58, 0xb1, 0x58, 0x1b, 0x6e, 0x96, 0xd8, 0xe6,
-  0x7f, 0xff, 0xfe, 0xcc, 0x05, 0x73, 0x3f, 0xaf,
-  0x78, 0xfd, 0x72, 0xce, 0xaf, 0xf2, 0x86, 0x63,
-  0x0e, 0x9d, 0x55, 0xa0, 0xe9, 0xda, 0x99, 0x63,
-  0xa1, 0xe8, 0xc4, 0xac, 0x22, 0xae, 0x39, 0x3d,
-  0x48, 0x34, 0x43, 0xa7, 0xd6, 0xfa, 0xe0, 0x99,
-  0x3f, 0xef, 0x0b, 0xf0, 0x68, 0xd3, 0xb6, 0x34,
-  0x41, 0xae, 0x34, 0xb3, 0xee, 0x4f, 0x31, 0x4e,
-  0x9f, 0x9f, 0x6f, 0xf5, 0x37, 0x3a, 0x58, 0x87,
-  0xa7, 0xf2, 0x59, 0xff, 0xff, 0x70, 0x6f, 0x96,
-  0xba, 0xe7, 0xe9, 0xbe, 0x0f, 0xa8, 0xe6, 0x1d,
-  0x0f, 0x4d, 0x03, 0x21, 0x5f, 0xf2, 0x69, 0xf8,
-  0x73, 0x6a, 0xd9, 0x4e, 0x9f, 0xff, 0xda, 0x7f,
-  0xb5, 0xee, 0xdf, 0xfe, 0xbd, 0x7d, 0x4d, 0xbc,
-  0x13, 0xa7, 0xff, 0xfa, 0xb5, 0x51, 0xba, 0xb9,
-  0x99, 0x7a, 0xef, 0xaf, 0x3f, 0x0e, 0x9e, 0xb6,
-  0x79, 0xb1, 0xd1, 0xe4, 0x44, 0xd9, 0x9a, 0x66,
-  0x6a, 0x86, 0x8b, 0xf2, 0x7f, 0xe7, 0xdf, 0x47,
-  0xbd, 0x97, 0xba, 0xb0, 0xe9, 0xff, 0xbd, 0x9f,
-  0xcc, 0xae, 0xe7, 0xd5, 0x87, 0x45, 0x28, 0x8b,
-  0xaa, 0x34, 0xf7, 0xfe, 0xa8, 0x74, 0x2a, 0x63,
-  0x5b, 0x11, 0xe4, 0x2c, 0xf8, 0x92, 0x7f, 0xff,
-  0xe6, 0xf5, 0xb7, 0x98, 0xe6, 0x9f, 0xc3, 0xbe,
-  0xde, 0xa6, 0xa9, 0xea, 0x0e, 0x9f, 0x69, 0x95,
-  0xf7, 0xce, 0x9e, 0xdf, 0xa7, 0x54, 0xe9, 0xff,
-  0x5e, 0xa0, 0xf5, 0x34, 0xbf, 0x2e, 0x74, 0x29,
-  0xf2, 0xe1, 0x24, 0xcd, 0x68, 0x74, 0x98, 0x74,
-  0x52, 0x6a, 0x1b, 0xb1, 0x89, 0xff, 0xff, 0x5b,
-  0xd4, 0xdf, 0x29, 0xb8, 0x8a, 0xdc, 0x1b, 0xfe,
-  0xfb, 0x61, 0xd3, 0x82, 0x10, 0x95, 0x3d, 0xb6,
-  0xdd, 0xf2, 0x9c, 0x5e, 0x4f, 0xfb, 0xac, 0x9e,
-  0xed, 0xd5, 0xeb, 0x1d, 0x0a, 0x99, 0x12, 0x13,
-  0xfa, 0x11, 0x76, 0x32, 0x9f, 0xfb, 0x3f, 0x4d,
-  0xf0, 0x7d, 0x47, 0x30, 0xe9, 0xf6, 0x5d, 0xec,
-  0xb1, 0xd0, 0xa7, 0xd7, 0x54, 0x49, 0x81, 0x63,
-  0xa7, 0xea, 0x1a, 0x7b, 0x70, 0x68, 0x3a, 0x7f,
-  0x6b, 0xb6, 0x5e, 0xde, 0xb9, 0xd3, 0x78, 0x4e,
-  0x8d, 0x54, 0x7f, 0xde, 0x34, 0xb1, 0xac, 0xff,
-  0xed, 0xb6, 0x5d, 0x85, 0x6f, 0xe4, 0xf6, 0xc7,
-  0x49, 0xcd, 0xd1, 0x99, 0xd5, 0xaa, 0xc3, 0x8a,
-  0x37, 0x41, 0x5e, 0xd0, 0xd8, 0xc8, 0xf5, 0x69,
-  0x8c, 0x73, 0xc6, 0xad, 0x47, 0x10, 0x26, 0xac,
-  0x2c, 0xb4, 0xa0, 0xde, 0x41, 0x03, 0xd7, 0xe1,
-  0x1b, 0x58, 0xda, 0xaf, 0x0a, 0xc0, 0x90, 0xea,
-  0x42, 0x53, 0x79, 0xac, 0x39, 0x9d, 0x25, 0x6a,
-  0x69, 0xb4, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14,
-  0xee, 0x43, 0x44, 0xd9, 0x3f, 0x9d, 0x82, 0x9d,
-  0xc8, 0x68, 0xab, 0x67, 0xf3, 0xdf, 0xa5, 0xfe,
-  0xaf, 0x3a, 0x7b, 0x2d, 0xd7, 0x3a, 0x5a, 0xa6,
-  0x1e, 0xa7, 0xcd, 0x27, 0xc2, 0x9d, 0xc8, 0x68,
-  0xad, 0x27, 0xff, 0x91, 0x47, 0x01, 0xcc, 0xe7,
-  0xaf, 0x90, 0xe9, 0xff, 0xe7, 0xd7, 0x3e, 0xac,
-  0xec, 0xbd, 0xd5, 0x87, 0x4d, 0x7b, 0xaa, 0x25,
-  0xf9, 0x2a, 0x7f, 0x2b, 0x6d, 0xf7, 0xfa, 0x80,
-  0xe9, 0xfa, 0x8c, 0xb7, 0xb1, 0x87, 0x4f, 0xf6,
-  0x37, 0xfd, 0x43, 0x4b, 0xea, 0x74, 0xfe, 0x7e,
-  0x5f, 0xbe, 0x0d, 0x0e, 0x93, 0x9b, 0x89, 0xf9,
-  0x61, 0x67, 0xa1, 0x8f, 0x62, 0xde, 0x36, 0xf9,
-  0x6d, 0xcf, 0x27, 0xf3, 0xb0, 0x53, 0xb9, 0x0d,
-  0x16, 0x04, 0xf8, 0x53, 0xb9, 0x0d, 0x13, 0xac,
-  0xff, 0xfe, 0xb2, 0xd1, 0xb6, 0x31, 0xd5, 0xae,
-  0x5b, 0xd5, 0xd2, 0x83, 0xa7, 0xce, 0x67, 0x3d,
-  0xd8, 0x89, 0x56, 0x8c, 0x27, 0xc2, 0x9d, 0xc8,
-  0x68, 0xb6, 0x67, 0xfc, 0x05, 0xab, 0xad, 0xe4,
-  0xe1, 0x3a, 0x4e, 0xc3, 0xec, 0xe3, 0x09, 0xe4,
-  0xee, 0x43, 0x45, 0xcd, 0x26, 0x1d, 0x33, 0xb0,
-  0x4d, 0xd8, 0x4a, 0xe7, 0xf3, 0xb0, 0x53, 0xb9,
-  0x0d, 0x17, 0x7c, 0xf3, 0xb5, 0xec, 0x03, 0xa1,
-  0x5b, 0x49, 0x8c, 0xa7, 0x5d, 0xa1, 0x85, 0x2a,
-  0x5e, 0x95, 0x02, 0x2e, 0x4c, 0x86, 0x80, 0x21,
-  0x59, 0x56, 0x1b, 0x95, 0xef, 0x3b, 0x9f, 0xf7,
-  0xf9, 0xcb, 0x5a, 0xb3, 0x9e, 0x74, 0xfe, 0xfd,
-  0x18, 0xdf, 0x75, 0xd6, 0x74, 0xf8, 0x53, 0xb9,
-  0x0d, 0x12, 0xbc, 0xf6, 0x9c, 0x2f, 0x3a, 0x7f,
-  0xff, 0x7a, 0xfc, 0xce, 0xf8, 0x2c, 0x1e, 0xfd,
-  0x09, 0xea, 0x0e, 0x95, 0xb6, 0x44, 0x1f, 0x10,
-  0xce, 0xe7, 0xb9, 0x53, 0x14, 0xc3, 0x8a, 0xc2,
-  0xce, 0x75, 0xd7, 0x62, 0xa7, 0xff, 0x5b, 0xbd,
-  0x75, 0x7f, 0x86, 0x8d, 0x00, 0x54, 0xfe, 0xe4,
-  0x76, 0xc2, 0xdd, 0xb9, 0x4f, 0x9e, 0xa3, 0x92,
-  0x72, 0x2a, 0x4b, 0x64, 0x6a, 0x2d, 0xa1, 0x59,
-  0x3f, 0xf9, 0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90,
-  0xd1, 0x30, 0xcf, 0xff, 0xd8, 0xed, 0xe3, 0xc0,
-  0x76, 0xbb, 0xbc, 0x2b, 0x57, 0x9d, 0x3f, 0xf6,
-  0xa9, 0x94, 0xbf, 0x4e, 0xbf, 0xd5, 0xe7, 0x4f,
-  0xf7, 0xd7, 0xa8, 0xbe, 0xbe, 0x13, 0xa7, 0xe6,
-  0x2e, 0x7e, 0xfa, 0x87, 0x4f, 0x97, 0x3f, 0x7d,
-  0x43, 0xa7, 0xeb, 0x7a, 0xf5, 0xea, 0x77, 0x1e,
-  0xc3, 0x0b, 0xe7, 0xff, 0xfd, 0xfc, 0x0b, 0x7d,
-  0xf2, 0xdb, 0xbf, 0x94, 0x7b, 0x3f, 0x4b, 0xea,
-  0x74, 0xfc, 0xdb, 0x7d, 0xfe, 0xa0, 0x3a, 0x7f,
-  0xf2, 0xdc, 0x0a, 0xfc, 0xa6, 0xf4, 0x68, 0x13,
-  0xa1, 0x4f, 0xf7, 0xc6, 0x33, 0xf5, 0x7d, 0xad,
-  0x9d, 0x73, 0xa7, 0xff, 0xfc, 0x38, 0xd9, 0x7f,
-  0x7d, 0xdb, 0xfe, 0xb6, 0xef, 0x5d, 0x6f, 0x53,
-  0xa5, 0x94, 0xa2, 0x7c, 0x4b, 0xe7, 0xbe, 0xa0,
-  0xde, 0x74, 0xf7, 0x6f, 0xdb, 0x0e, 0x93, 0x9b,
-  0x8a, 0xd0, 0x76, 0x4a, 0x48, 0x48, 0xb4, 0x91,
-  0x68, 0x78, 0x7e, 0x18, 0x17, 0x28, 0xd0, 0x8e,
-  0x7c, 0x29, 0xdc, 0x86, 0x8a, 0xba, 0x7f, 0x9e,
-  0xec, 0x14, 0xee, 0x43, 0x44, 0x79, 0x27, 0x61,
-  0xf8, 0xf1, 0x84, 0xfe, 0x76, 0x0a, 0x77, 0x21,
-  0xa2, 0xc1, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
-  0x59, 0x53, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b,
-  0x4e, 0x79, 0x3b, 0x90, 0xd1, 0x6e, 0x4f, 0xfc,
-  0xb8, 0x39, 0xfd, 0xd6, 0xca, 0x42, 0x74, 0x09,
-  0xf7, 0xd4, 0xae, 0x7f, 0xdc, 0xf7, 0x60, 0xa7,
-  0x72, 0x1a, 0x28, 0x79, 0xfb, 0xed, 0xcc, 0x15,
-  0xa9, 0xd3, 0xff, 0xf6, 0x6d, 0x65, 0xde, 0xeb,
-  0xff, 0x81, 0x5a, 0xa8, 0x0a, 0x93, 0xb1, 0x1e,
-  0x6c, 0x21, 0xd1, 0x1b, 0x50, 0xbe, 0x7f, 0x3b,
-  0x05, 0x3b, 0x90, 0xd1, 0x79, 0xc2, 0xaf, 0xf7,
-  0x3d, 0x13, 0x65, 0x2c, 0x97, 0x3f, 0x4c, 0x3f,
-  0xc4, 0x99, 0x87, 0x76, 0x3b, 0xfc, 0x73, 0xad,
-  0x91, 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x14,
-  0xb4, 0xfe, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xc2,
-  0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x59, 0x73,
-  0xce, 0xd7, 0xaa, 0xf9, 0xba, 0x9d, 0x39, 0xdb,
-  0xd8, 0x74, 0xf2, 0x39, 0x6a, 0x87, 0xa5, 0xa1,
-  0xa4, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14, 0xee,
-  0x43, 0x45, 0x19, 0x3f, 0x9c, 0xad, 0x94, 0x54,
-  0x07, 0x43, 0xd3, 0xbf, 0x13, 0xb6, 0x1d, 0xf4,
-  0x23, 0x6a, 0x71, 0x75, 0x29, 0xff, 0x9d, 0xcf,
-  0x76, 0x0a, 0x77, 0x21, 0xa2, 0x39, 0x9f, 0xfc,
-  0xe6, 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x9c,
-  0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x16, 0x64,
-  0xfe, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xdd, 0x9f,
-  0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68,
-  0xa4, 0x27, 0xfe, 0x77, 0x3d, 0xd8, 0x29, 0xdc,
-  0x86, 0x89, 0x4a, 0x28, 0x4e, 0xc9, 0xa4, 0xc6,
-  0x29, 0x7c, 0xee, 0xe7, 0x6d, 0xea, 0x53, 0xfe,
-  0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x3b, 0x4f,
-  0xff, 0xbd, 0xb6, 0x8c, 0x56, 0xfe, 0xdb, 0xeb,
-  0xfc, 0x43, 0xa4, 0xe6, 0x22, 0x7f, 0x91, 0xa7,
-  0xfe, 0xe6, 0x5b, 0x13, 0xac, 0xbb, 0xde, 0x74,
-  0xff, 0xdf, 0xcb, 0x75, 0x19, 0x5f, 0xf5, 0x27,
-  0x4d, 0xa8, 0xed, 0x91, 0x0f, 0x54, 0x38, 0x62,
-  0x38, 0xb5, 0x21, 0x5f, 0x3e, 0x14, 0xee, 0x43,
-  0x44, 0x59, 0x3f, 0xee, 0x7b, 0xb0, 0x53, 0xb9,
-  0x0d, 0x12, 0xec, 0xff, 0xfd, 0x9b, 0x59, 0x77,
-  0xba, 0xff, 0xe0, 0x56, 0xaa, 0x02, 0xa4, 0xec,
-  0x46, 0x9b, 0x0c, 0x35, 0x11, 0xa7, 0xff, 0x39,
-  0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x26, 0x29,
-  0xfc, 0xec, 0x14, 0xee, 0x43, 0x45, 0x53, 0x3f,
-  0xf9, 0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1,
-  0x3a, 0x4f, 0xef, 0x70, 0xab, 0xf9, 0xb1, 0xd3,
-  0xe6, 0x95, 0xa5, 0xa9, 0xd3, 0xf0, 0x73, 0xcd,
-  0xb3, 0xe7, 0x4f, 0x7a, 0xca, 0xef, 0x1e, 0xb5,
-  0x4a, 0x27, 0xfe, 0xd2, 0xb7, 0x5a, 0x5d, 0xa3,
-  0x5e, 0x61, 0xd0, 0xc4, 0x41, 0x58, 0xe6, 0x7f,
-  0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x27, 0x79,
-  0xf5, 0xf4, 0xe6, 0x78, 0xa9, 0x3b, 0x64, 0xe6,
-  0xf2, 0x30, 0xa6, 0x11, 0xf2, 0x34, 0xff, 0xe7,
-  0x33, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x45, 0x0b,
-  0x3f, 0xf9, 0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90,
-  0xd1, 0x49, 0x4f, 0xff, 0xec, 0xab, 0xb7, 0xe3,
-  0x56, 0xe6, 0x5e, 0xcb, 0x7d, 0x18, 0x74, 0x50,
-  0xb8, 0x06, 0xf3, 0x84, 0x52, 0x13, 0xb6, 0x47,
-  0xda, 0x04, 0x9d, 0x14, 0xb5, 0x14, 0xa7, 0xf3,
-  0xb0, 0x53, 0xb9, 0x0d, 0x11, 0x24, 0xff, 0xe7,
-  0x33, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0xbd,
-  0x3e, 0x14, 0xee, 0x43, 0x45, 0x2f, 0x3f, 0x97,
-  0x66, 0xff, 0x31, 0x6a, 0x74, 0x9d, 0x87, 0xcd,
-  0x73, 0x09, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
-  0x39, 0x3f, 0xef, 0x0f, 0x56, 0xd9, 0x9f, 0x43,
-  0xa7, 0xfd, 0x96, 0x51, 0xc7, 0x04, 0x21, 0x2a,
-  0x6f, 0x04, 0xe9, 0xa8, 0x76, 0xc8, 0x8d, 0xd4,
-  0x3b, 0x6f, 0x3c, 0x9f, 0x0a, 0x77, 0x21, 0xa2,
-  0xbc, 0x9f, 0xff, 0xb3, 0x6b, 0x2e, 0xf7, 0x5f,
-  0xfc, 0x0a, 0xd5, 0x40, 0x54, 0x9d, 0x88, 0x8d,
-  0xd4, 0x30, 0x9f, 0xf9, 0xdc, 0xf7, 0x60, 0xa7,
-  0x72, 0x1a, 0x24, 0x79, 0xde, 0x02, 0x9d, 0x39,
-  0x31, 0x85, 0x38, 0xbb, 0x9f, 0x0a, 0x77, 0x21,
-  0xa2, 0x48, 0x9e, 0x77, 0x3d, 0xca, 0x7b, 0x38,
-  0x53, 0x3f, 0xf3, 0xb9, 0xee, 0xc1, 0x4e, 0xe4,
-  0x34, 0x49, 0x53, 0xe1, 0x4e, 0xe4, 0x34, 0x5e,
-  0x33, 0xf6, 0x9f, 0xa7, 0xa9, 0xa9, 0xd3, 0xea,
-  0xd6, 0xf8, 0x87, 0x4f, 0xf3, 0xdd, 0x82, 0x9d,
-  0xc8, 0x68, 0x93, 0x64, 0xec, 0x46, 0x3d, 0x26,
-  0x02, 0x61, 0xc4, 0xd0, 0xab, 0xa5, 0x34, 0x1d,
-  0xbe, 0x17, 0x1b, 0x13, 0xfa, 0x19, 0x0d, 0x43,
-  0x45, 0x85, 0x76, 0x86, 0x05, 0xcd, 0xf4, 0x8c,
-  0x4e, 0x16, 0x36, 0x9d, 0x1a, 0x23, 0xae, 0x7c,
-  0x79, 0x3b, 0x47, 0xb5, 0x96, 0xe4, 0x47, 0x5c,
-  0xa5, 0x64, 0xaf, 0xb3, 0x69, 0x9e, 0x7b, 0xf4,
-  0xe6, 0x26, 0xae, 0x3b, 0x06, 0xa9, 0xa9, 0xe3,
-  0x48, 0xf0, 0x66, 0x22, 0x86, 0x2d, 0x3b, 0x51,
-  0xd4, 0xe7, 0x80, 0x4b, 0x0e, 0x6e, 0xe1, 0x63,
-  0xf9, 0xe4, 0x8a, 0xd2, 0x4c, 0xef, 0x5c, 0x90,
-  0x69, 0x4a, 0xef, 0x6d, 0x29, 0x80, 0x32, 0x83,
-  0x75, 0x23, 0xde, 0xdf, 0x3a, 0x02, 0xdf, 0x3b,
-  0x4d, 0x00,
+  0x9e, 0x15, 0x3c, 0xaa, 0x0e, 0xde, 0xa5, 0xe8,
+  0x47, 0xb0, 0xe2, 0xe7, 0x73, 0xf9, 0xd8, 0x29,
+  0xdc, 0x86, 0x88, 0x7a, 0x7c, 0x29, 0xdc, 0x86,
+  0x88, 0x9a, 0x6b, 0xb0, 0xe9, 0xff, 0xd9, 0x6d,
+  0xf4, 0x55, 0x7d, 0x4d, 0xd5, 0x87, 0x45, 0x27,
+  0xc7, 0x61, 0x69, 0xeb, 0xeb, 0xdb, 0xcd, 0x10,
+  0xbc, 0x9d, 0x88, 0xe7, 0xac, 0x24, 0xf5, 0x23,
+  0x9e, 0xbd, 0xbd, 0x73, 0xa7, 0xff, 0x79, 0xa7,
+  0xe5, 0x2f, 0xd0, 0xce, 0xef, 0x9d, 0x37, 0x37,
+  0x9d, 0x2d, 0xd3, 0x11, 0x0f, 0x62, 0x2e, 0x4d,
+  0x9f, 0x5b, 0xaf, 0xcf, 0x3a, 0x7b, 0xd5, 0xf0,
+  0x0e, 0x9c, 0x10, 0x84, 0xa9, 0xf7, 0x7e, 0xf6,
+  0xc2, 0x9c, 0x5e, 0x4f, 0xba, 0xed, 0x65, 0xce,
+  0x8d, 0x91, 0x34, 0x03, 0xef, 0x9a, 0xcf, 0xfc,
+  0x0f, 0x35, 0xa2, 0xcb, 0xe1, 0xd7, 0x76, 0x74,
+  0xff, 0xbd, 0xa5, 0x7e, 0xb5, 0x5f, 0x30, 0xe9,
+  0xfb, 0x1b, 0x6a, 0xfc, 0xa9, 0xd3, 0xd9, 0xb6,
+  0x50, 0x74, 0x62, 0x79, 0xbe, 0x86, 0x03, 0x46,
+  0x36, 0x4c, 0xf9, 0xfd, 0xcb, 0xe7, 0xec, 0x0a,
+  0xe6, 0xde, 0x3a, 0x7f, 0xff, 0xf7, 0xff, 0x4a,
+  0xe9, 0xfe, 0x6d, 0x6f, 0x35, 0xa2, 0xb9, 0x4b,
+  0xc7, 0x02, 0x74, 0xfb, 0xd7, 0xd5, 0x68, 0x3a,
+  0x7f, 0x52, 0xfa, 0xe9, 0xd5, 0x69, 0x3a, 0x7f,
+  0x70, 0x75, 0x69, 0x6f, 0xc7, 0x47, 0x8f, 0xaf,
+  0xe7, 0x10, 0xa9, 0x9a, 0xe3, 0xf8, 0xc2, 0x52,
+  0x6d, 0x5e, 0x74, 0xee, 0xbd, 0x4e, 0x9b, 0x5a,
+  0x0e, 0x9e, 0x5f, 0xdd, 0xa7, 0x9b, 0x31, 0x1b,
+  0x9f, 0xff, 0x6a, 0xb7, 0xd1, 0xfd, 0x5b, 0xf4,
+  0x65, 0xf7, 0x32, 0xe7, 0x4f, 0xfd, 0x65, 0xd3,
+  0xa2, 0xff, 0xeb, 0xad, 0xce, 0x9f, 0xda, 0x29,
+  0x7f, 0xad, 0xab, 0x0e, 0x80, 0x1f, 0xff, 0xd1,
+  0xe7, 0xfc, 0x2d, 0x68, 0xaa, 0xfa, 0x8e, 0xb9,
+  0xd0, 0xa7, 0xc7, 0xa9, 0x14, 0xff, 0xff, 0xf6,
+  0xbf, 0xa8, 0xfd, 0x5a, 0xd1, 0xbe, 0xfe, 0x7e,
+  0x53, 0x7c, 0x6d, 0xfc, 0xa9, 0xd2, 0x53, 0xa7,
+  0xf3, 0xf8, 0x7d, 0x55, 0xa4, 0xe9, 0xff, 0xff,
+  0xfd, 0xe0, 0x57, 0xf9, 0xd4, 0xe8, 0xda, 0xda,
+  0xe8, 0xfe, 0x52, 0xfc, 0xd6, 0x8f, 0xe7, 0x52,
+  0x74, 0xee, 0xe4, 0x34, 0x53, 0x11, 0x88, 0xbf,
+  0x48, 0x4c, 0xcf, 0xfb, 0x3f, 0x4b, 0xeb, 0x75,
+  0x16, 0x8e, 0x9f, 0x53, 0xfc, 0x6d, 0x87, 0x47,
+  0x8f, 0xa3, 0x8f, 0xe7, 0xfb, 0x99, 0xb5, 0x96,
+  0x8c, 0x09, 0xd3, 0xff, 0xfb, 0xf8, 0x97, 0xba,
+  0xde, 0xad, 0x7f, 0x03, 0xa1, 0x5b, 0xa9, 0xd3,
+  0xfe, 0x45, 0x65, 0xb2, 0xb9, 0xef, 0x9d, 0x0a,
+  0x8a, 0x4b, 0x34, 0x4f, 0x85, 0x5b, 0x28, 0x9d,
+  0x3f, 0x77, 0xf4, 0x6c, 0xbf, 0x3a, 0x30, 0xfd,
+  0xfc, 0x45, 0xa9, 0x34, 0x50, 0xbb, 0x3f, 0xb2,
+  0x56, 0x93, 0x84, 0x8d, 0x0e, 0x92, 0x2f, 0x42,
+  0x19, 0xa0, 0xf1, 0x87, 0x8b, 0x21, 0x1d, 0xf2,
+  0x1b, 0xc6, 0xa9, 0x3f, 0xed, 0x23, 0xc1, 0xd1,
+  0xdb, 0x75, 0x07, 0x4f, 0x67, 0xf4, 0xee, 0xce,
+  0x9f, 0xff, 0xff, 0x5b, 0xd7, 0xb6, 0x0a, 0xb6,
+  0xd0, 0xcd, 0x5b, 0xf4, 0x65, 0x2f, 0xcd, 0x7e,
+  0x0a, 0x9d, 0x2b, 0xf9, 0x16, 0xd5, 0x27, 0x9f,
+  0xff, 0x66, 0x5b, 0xc9, 0x6c, 0xd1, 0x5d, 0x6c,
+  0xbb, 0xb3, 0xa7, 0xff, 0xaf, 0x6c, 0x06, 0x86,
+  0x2e, 0x5f, 0x6c, 0xf9, 0xd3, 0xfd, 0x4e, 0x86,
+  0x2e, 0x7e, 0xfb, 0x87, 0x4a, 0xb8, 0x88, 0xfe,
+  0x51, 0x97, 0xbe, 0x98, 0x85, 0xe1, 0xd3, 0x3e,
+  0x7a, 0xd2, 0xfa, 0x9d, 0x3f, 0xff, 0xff, 0xec,
+  0xfe, 0x9d, 0x1e, 0xb6, 0xae, 0x6b, 0xd7, 0x56,
+  0x7f, 0xb4, 0xdb, 0xce, 0xcb, 0x52, 0x05, 0xd8,
+  0xa9, 0xff, 0xff, 0x93, 0xc1, 0xdb, 0x51, 0xd1,
+  0xaa, 0xd1, 0x54, 0xb6, 0xb6, 0xa7, 0x82, 0x74,
+  0xda, 0xd1, 0x4a, 0x68, 0xde, 0x28, 0xac, 0x29,
+  0x61, 0x55, 0x79, 0xda, 0x33, 0x9f, 0xc6, 0xeb,
+  0x3f, 0xf9, 0x89, 0xa2, 0xdc, 0xfc, 0x67, 0x7c,
+  0x07, 0x4f, 0xff, 0xbd, 0xfb, 0xdb, 0x1b, 0xee,
+  0xd6, 0x6e, 0xfb, 0xe0, 0x3a, 0x7f, 0xe5, 0xfd,
+  0x1f, 0xc6, 0xd5, 0xd5, 0x69, 0x3a, 0x2a, 0x8a,
+  0x5d, 0x57, 0x67, 0xb2, 0xf8, 0xdd, 0x9d, 0x3b,
+  0x73, 0x2c, 0x74, 0xd9, 0xb1, 0xd1, 0x42, 0x6d,
+  0x8f, 0x87, 0x7d, 0x49, 0x2e, 0x4a, 0xd8, 0x7a,
+  0x7e, 0xd9, 0x7f, 0x6e, 0x79, 0xd3, 0x97, 0x65,
+  0x3a, 0x7f, 0x34, 0xfc, 0xbd, 0x79, 0xad, 0x07,
+  0x90, 0xc2, 0xd9, 0xf9, 0xbe, 0xdd, 0xbb, 0x50,
+  0x1d, 0x3f, 0x85, 0xaf, 0xe5, 0xba, 0xe7, 0x46,
+  0x1f, 0x2f, 0x8c, 0xe7, 0xe5, 0x06, 0x5f, 0x7d,
+  0x07, 0x43, 0xcf, 0x43, 0xe4, 0x33, 0xff, 0xfe,
+  0xbf, 0xf8, 0x15, 0xa3, 0x3d, 0xfb, 0xff, 0x1b,
+  0x68, 0xa8, 0x7e, 0x74, 0xff, 0xbd, 0x8d, 0x68,
+  0xaa, 0xdb, 0xb7, 0x67, 0x4f, 0xee, 0xa6, 0xb6,
+  0xce, 0x13, 0xa3, 0x63, 0xf5, 0xba, 0x24, 0x98,
+  0x74, 0xef, 0xe6, 0xc7, 0x42, 0x9a, 0xca, 0x44,
+  0x27, 0xea, 0x6b, 0x99, 0xfd, 0x27, 0x4f, 0x33,
+  0x7a, 0x80, 0xe8, 0xc3, 0xd2, 0xf1, 0x7c, 0x2a,
+  0x79, 0x59, 0x0e, 0x7f, 0x27, 0x8b, 0x9c, 0xfe,
+  0xbf, 0xa8, 0xcb, 0x6b, 0x73, 0xa7, 0xb2, 0x95,
+  0x68, 0xe9, 0xfa, 0xdc, 0xf6, 0x0f, 0x8e, 0x9f,
+  0x78, 0x03, 0x94, 0x9d, 0x1a, 0x51, 0x55, 0xe3,
+  0x50, 0x11, 0x6a, 0x59, 0x3f, 0xff, 0x0b, 0xed,
+  0x8d, 0x59, 0x7f, 0xa7, 0xf9, 0x7b, 0x6a, 0x74,
+  0xff, 0xfe, 0xf6, 0x52, 0xfa, 0xde, 0xca, 0xc5,
+  0xf6, 0xda, 0x15, 0xba, 0x9d, 0x3f, 0xff, 0xfe,
+  0xd7, 0xfa, 0x03, 0xd4, 0xbc, 0x78, 0x1a, 0x2b,
+  0xaa, 0xd3, 0x6c, 0xf7, 0xf3, 0x49, 0xd3, 0xff,
+  0xed, 0x44, 0x72, 0xf5, 0xb7, 0xb3, 0x45, 0x80,
+  0xa7, 0x46, 0x23, 0x8a, 0xd0, 0x8c, 0x9f, 0xfe,
+  0x7b, 0x7d, 0xb1, 0x7e, 0xd7, 0xf2, 0xf5, 0xe3,
+  0xa7, 0xff, 0xdb, 0x63, 0x34, 0x37, 0xdd, 0x6a,
+  0xd3, 0xf8, 0x68, 0x3a, 0x7f, 0xb3, 0xf4, 0x68,
+  0x07, 0x73, 0x47, 0x4f, 0xfa, 0xba, 0xff, 0x45,
+  0x75, 0xdc, 0xd4, 0x4e, 0x9f, 0xfd, 0x46, 0x8a,
+  0xdb, 0x5d, 0x17, 0xad, 0x54, 0x4e, 0x9f, 0xff,
+  0xf6, 0x53, 0x5f, 0x60, 0x74, 0x5b, 0x2f, 0x5c,
+  0xa3, 0x46, 0x7b, 0x63, 0xa3, 0x11, 0x85, 0xe5,
+  0x08, 0xa1, 0x5c, 0x3a, 0x46, 0x99, 0x49, 0x3f,
+  0x94, 0x98, 0xb9, 0x53, 0xbb, 0xc6, 0x13, 0x3f,
+  0xee, 0x1b, 0x65, 0xd7, 0xfe, 0x01, 0xd3, 0xfd,
+  0x81, 0xa5, 0xf5, 0xd1, 0x7f, 0x1d, 0x3f, 0xff,
+  0xe5, 0x45, 0x66, 0x86, 0xad, 0xef, 0xed, 0xa3,
+  0x7a, 0x7f, 0x2d, 0x87, 0x42, 0x23, 0xab, 0xe7,
+  0x8d, 0xe7, 0x93, 0xde, 0xbf, 0x94, 0xe9, 0xff,
+  0xff, 0xfa, 0xea, 0xcf, 0xfb, 0x4d, 0xb9, 0xad,
+  0x1f, 0xd5, 0xbf, 0x46, 0x52, 0xfc, 0xd7, 0xe0,
+  0xa9, 0xd0, 0xf4, 0x5c, 0x78, 0x86, 0x15, 0x79,
+  0x3f, 0x25, 0xf2, 0xfa, 0x35, 0xde, 0x87, 0x54,
+  0xf5, 0xeb, 0xc0, 0x3a, 0x7f, 0xeb, 0x7b, 0x47,
+  0x87, 0x5a, 0x38, 0x50, 0xe9, 0xef, 0x5b, 0xa8,
+  0x3a, 0x7e, 0xbf, 0x0f, 0xe9, 0xf1, 0xd1, 0x88,
+  0xb6, 0xd2, 0x42, 0x88, 0xd7, 0x22, 0x9e, 0xdf,
+  0xaf, 0x54, 0xe9, 0xff, 0xfb, 0xc3, 0xa3, 0x3d,
+  0x9f, 0xd3, 0x6f, 0x63, 0x31, 0x0e, 0x9f, 0xff,
+  0xef, 0x50, 0x2a, 0xca, 0xea, 0xba, 0x14, 0x57,
+  0x6b, 0x2b, 0x0e, 0x8c, 0x46, 0x20, 0xae, 0x4f,
+  0xff, 0xfe, 0x11, 0xf5, 0x1a, 0x2d, 0x97, 0xfa,
+  0xb5, 0x6c, 0xa1, 0x69, 0xbe, 0xa8, 0x74, 0xff,
+  0xff, 0xcb, 0xa6, 0xcb, 0xa3, 0xf9, 0xae, 0x9d,
+  0x14, 0xbe, 0xbe, 0xfe, 0xf5, 0xa0, 0xe9, 0xf5,
+  0x35, 0xf6, 0x7c, 0xe8, 0xc4, 0x53, 0xea, 0xff,
+  0x1e, 0x4d, 0x1a, 0xd1, 0x91, 0xcf, 0xfc, 0xfa,
+  0xfb, 0x4d, 0x97, 0xd4, 0x2e, 0x93, 0xa7, 0xfb,
+  0xfa, 0xb5, 0xfc, 0xb7, 0x5c, 0xe9, 0xfe, 0xda,
+  0xca, 0x1d, 0xad, 0xcc, 0x3a, 0x7f, 0xff, 0xb8,
+  0x6d, 0x97, 0xf6, 0x7e, 0x8a, 0xae, 0x7f, 0x6b,
+  0x29, 0xd3, 0xd7, 0xd1, 0x40, 0x9d, 0x14, 0xa2,
+  0x27, 0x99, 0x67, 0xe6, 0xa9, 0x7e, 0xab, 0x73,
+  0xa7, 0xfa, 0xdc, 0xcf, 0xe5, 0xba, 0xe7, 0x42,
+  0x9f, 0x3d, 0x4c, 0x27, 0xec, 0xb8, 0x8e, 0x3c,
+  0xe9, 0xfb, 0xf9, 0x6f, 0xe2, 0x1d, 0x3d, 0xfc,
+  0xae, 0x86, 0x8f, 0x56, 0xe5, 0x51, 0xb2, 0xe0,
+  0x9a, 0x46, 0xcf, 0x49, 0x57, 0x92, 0x44, 0xea,
+  0xd0, 0xc3, 0xbc, 0x22, 0x9b, 0x3b, 0x4f, 0xfd,
+  0xff, 0xe6, 0x81, 0xcb, 0x7f, 0x1a, 0x3a, 0x15,
+  0x77, 0x1b, 0x27, 0x3e, 0xfa, 0x10, 0xd3, 0xef,
+  0xab, 0x3b, 0x63, 0xa7, 0xf6, 0x35, 0x6c, 0xba,
+  0xec, 0x74, 0xff, 0xff, 0xf5, 0xb2, 0xf5, 0xe6,
+  0xb4, 0x7f, 0x29, 0x7e, 0x6b, 0x47, 0xf3, 0x6b,
+  0x79, 0xa3, 0xa6, 0xd7, 0x49, 0xd0, 0x28, 0x9e,
+  0xbc, 0x21, 0x67, 0xec, 0xa3, 0xf9, 0x4d, 0x4e,
+  0x9f, 0xfc, 0x34, 0xbe, 0xb8, 0xca, 0x56, 0xd6,
+  0x53, 0xa5, 0x53, 0xa3, 0x53, 0xda, 0xde, 0x95,
+  0x3f, 0x95, 0x9f, 0xcb, 0x75, 0xce, 0x9f, 0xff,
+  0xf5, 0xfe, 0xa0, 0xa5, 0xf5, 0xd5, 0x6f, 0xfc,
+  0xdb, 0xd8, 0x2d, 0x1d, 0x1e, 0x54, 0xd8, 0xd1,
+  0x3f, 0x43, 0x47, 0xe4, 0xf5, 0x84, 0x46, 0xa4,
+  0xbb, 0xcc, 0x67, 0xcf, 0xf0, 0xe5, 0x27, 0x4f,
+  0xb2, 0xb4, 0x60, 0x4e, 0x8a, 0x4f, 0x3a, 0xc4,
+  0xf3, 0xff, 0xef, 0x51, 0x89, 0xb5, 0xbd, 0x9a,
+  0x74, 0x69, 0xd5, 0x4e, 0x9e, 0x6f, 0xbe, 0x58,
+  0xe9, 0xff, 0xff, 0x9b, 0xe9, 0x7f, 0x53, 0xa3,
+  0xfa, 0xb7, 0xe8, 0xca, 0x5f, 0x9a, 0xfc, 0x15,
+  0x3a, 0x28, 0x45, 0x36, 0x12, 0x4f, 0xff, 0xff,
+  0x96, 0x9a, 0xea, 0xb4, 0xe8, 0xb6, 0x6d, 0xa3,
+  0xf9, 0xae, 0x9d, 0x15, 0x00, 0x3d, 0x73, 0xa7,
+  0xcb, 0xfa, 0x7a, 0x83, 0xa7, 0xff, 0xff, 0xff,
+  0x63, 0x31, 0x16, 0xca, 0xcb, 0xe5, 0x6a, 0xa2,
+  0x2b, 0xfc, 0xa3, 0x35, 0xae, 0xad, 0x7d, 0x58,
+  0x74, 0xff, 0x03, 0x36, 0xfe, 0x5b, 0xae, 0x74,
+  0xfe, 0xa3, 0x55, 0xbb, 0x3d, 0x73, 0xa7, 0xfc,
+  0xba, 0x5b, 0xf5, 0xcf, 0xb5, 0xbd, 0x87, 0x46,
+  0x1f, 0xe5, 0x26, 0xb3, 0xff, 0xd9, 0x7d, 0xb3,
+  0x01, 0x5d, 0x03, 0x5d, 0xaa, 0x74, 0xf5, 0x1e,
+  0xfd, 0xce, 0x85, 0x57, 0xe1, 0x84, 0x7e, 0x8c,
+  0x0c, 0x48, 0xd9, 0x09, 0x1b, 0x14, 0x74, 0x28,
+  0xff, 0x0b, 0x4a, 0x91, 0x6a, 0xa5, 0x3b, 0x6d,
+  0x0d, 0x1d, 0x3f, 0xfd, 0x4b, 0xfe, 0xba, 0x19,
+  0xf5, 0xd3, 0x7f, 0x50, 0x74, 0x61, 0xfb, 0x78,
+  0x82, 0x7e, 0xa1, 0xa7, 0xb7, 0x06, 0x83, 0xa7,
+  0xcc, 0xf6, 0xd9, 0xb1, 0xd2, 0x68, 0xe9, 0x95,
+  0x87, 0x4a, 0xe7, 0x40, 0x9a, 0x5e, 0x15, 0x8d,
+  0x8f, 0x56, 0xc6, 0xd3, 0xd7, 0xaf, 0x52, 0x74,
+  0xcd, 0x71, 0xd3, 0xfa, 0xde, 0x1a, 0x5f, 0xf5,
+  0x3a, 0x37, 0x52, 0x68, 0x0a, 0x69, 0x8f, 0xde,
+  0x23, 0x61, 0x16, 0xa2, 0xd3, 0xfa, 0xbe, 0xa4,
+  0x3d, 0xf0, 0x1d, 0x3f, 0xfe, 0x51, 0x54, 0xc6,
+  0x2a, 0x3f, 0xd5, 0xd5, 0x87, 0x43, 0x48, 0x86,
+  0xdc, 0x34, 0x9d, 0xfe, 0x61, 0xd3, 0x01, 0x4e,
+  0x8f, 0x1b, 0x0f, 0x8d, 0xc9, 0xcd, 0xc7, 0x5a,
+  0x34, 0xb2, 0x81, 0xa8, 0x5d, 0xda, 0x36, 0x1c,
+  0x9d, 0xd2, 0xd3, 0x0b, 0xa4, 0x97, 0xd7, 0x4c,
+  0x75, 0x3e, 0x84, 0xdb, 0x51, 0x81, 0x8c, 0x7d,
+  0x8c, 0x87, 0x55, 0xa7, 0xa3, 0xfa, 0x30, 0x5f,
+  0xcf, 0x01, 0xd6, 0x55, 0x4d, 0xe7, 0x2c, 0x5b,
+  0x46, 0x2b, 0xb9, 0x1b, 0x0e, 0xf8, 0x71, 0xb7,
+  0xab, 0xcf, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x29,
+  0xd9, 0xf0, 0xa7, 0x72, 0x1a, 0x2a, 0x39, 0xff,
+  0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x9a, 0x24,
+  0xec, 0x3f, 0x66, 0x18, 0x4f, 0xe7, 0x60, 0xa7,
+  0x72, 0x1a, 0x2a, 0xf9, 0xf0, 0xa7, 0x72, 0x1a,
+  0x2b, 0x69, 0xfe, 0x7b, 0xb0, 0x53, 0xb9, 0x0d,
+  0x12, 0x0c, 0x9d, 0x87, 0xe3, 0xc6, 0x13, 0xff,
+  0x3b, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x87,
+  0x3e, 0x14, 0xee, 0x43, 0x45, 0x89, 0x3e, 0xc1,
+  0x5f, 0xe9, 0x3a, 0x7f, 0x59, 0x77, 0xee, 0x60,
+  0xa9, 0xd3, 0xff, 0x2e, 0x57, 0x3f, 0xb7, 0x80,
+  0xbf, 0x3a, 0x77, 0xd6, 0x83, 0xa4, 0xff, 0x9e,
+  0xfe, 0xa8, 0x73, 0xb7, 0x3c, 0x03, 0xa7, 0x0a,
+  0xbc, 0xe9, 0xfd, 0x82, 0xf0, 0x66, 0x34, 0x74,
+  0xfb, 0x9f, 0xbe, 0xca, 0x74, 0xfd, 0x5a, 0x8f,
+  0x83, 0xbb, 0x3a, 0x15, 0x11, 0x5e, 0x31, 0xe2,
+  0x89, 0xff, 0xe7, 0xab, 0x15, 0xfb, 0x7d, 0x6d,
+  0xd8, 0x27, 0x4f, 0xe4, 0xfe, 0x36, 0xfe, 0x54,
+  0xe8, 0xa5, 0x10, 0x16, 0x4d, 0x9f, 0xc0, 0x5c,
+  0xbf, 0xbe, 0x12, 0xa3, 0x15, 0x6d, 0xe9, 0x30,
+  0x42, 0x7a, 0x61, 0x29, 0xe2, 0x91, 0x1f, 0xb4,
+  0x29, 0x3a, 0x15, 0xc0, 0x24, 0x9f, 0xfa, 0xde,
+  0x5b, 0xdb, 0xb4, 0xe7, 0xc0, 0x74, 0xff, 0xf6,
+  0x52, 0xfb, 0xeb, 0x43, 0xad, 0xcc, 0xf5, 0x4e,
+  0x9a, 0xce, 0xc4, 0x4c, 0x7d, 0x16, 0x1c, 0x9a,
+  0xa2, 0xc6, 0x4d, 0x3f, 0x9d, 0x82, 0x9d, 0xc8,
+  0x68, 0xb3, 0x67, 0xff, 0x39, 0x9c, 0xf7, 0x60,
+  0xa7, 0x72, 0x1a, 0x28, 0x09, 0xfd, 0xfc, 0xb8,
+  0x37, 0xfd, 0xa3, 0xa6, 0xd1, 0x53, 0xa7, 0x93,
+  0xb9, 0x0d, 0x16, 0xfc, 0xfd, 0xbe, 0xfc, 0x9c,
+  0x27, 0x40, 0x9e, 0xb8, 0x0a, 0xe7, 0xd7, 0x7d,
+  0x77, 0xd4, 0xe9, 0xfc, 0xad, 0xb7, 0xdf, 0xea,
+  0x03, 0xa7, 0xbb, 0xdf, 0xb9, 0xd3, 0xfb, 0x5a,
+  0x6a, 0xa9, 0x8c, 0x3a, 0x7a, 0xda, 0x76, 0x61,
+  0xd3, 0x63, 0xce, 0x8c, 0x37, 0x5f, 0x25, 0x93,
+  0x95, 0x3d, 0x47, 0x9b, 0x63, 0x78, 0x90, 0xd8,
+  0xa8, 0x06, 0xdf, 0x21, 0xbb, 0x6c, 0xff, 0xb9,
+  0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x52, 0x93, 0xfc,
+  0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x24, 0xe9, 0x39,
+  0x88, 0x87, 0xe4, 0x68, 0x57, 0x74, 0xf3, 0x44,
+  0x64, 0x5b, 0x5a, 0xdd, 0xcc, 0x8e, 0xa1, 0x21,
+  0x63, 0xe2, 0x7d, 0xdc, 0x2b, 0x1a, 0x26, 0x64,
+  0xe3, 0xdd, 0x8a, 0x40, 0x77, 0x59, 0x44, 0xcd,
+  0xa1, 0xf9, 0x3e, 0x14, 0xee, 0x43, 0x44, 0x3f,
+  0x3f, 0xee, 0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x12,
+  0x9c, 0x9d, 0x87, 0xec, 0xc3, 0x09, 0xfc, 0xec,
+  0x14, 0xee, 0x43, 0x44, 0x4f, 0x3f, 0x9d, 0x82,
+  0x9d, 0xc8, 0x68, 0x8c, 0x67, 0xff, 0x39, 0x9c,
+  0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x27, 0x98, 0x54,
+  0x77, 0xd0, 0x4e, 0xf3, 0xbb, 0x1d, 0xcf, 0x85,
+  0x3b, 0x90, 0xd1, 0x10, 0x4f, 0xfb, 0x9e, 0xec,
+  0x14, 0xee, 0x43, 0x44, 0xa9, 0x27, 0x61, 0xfb,
+  0x30, 0xc2, 0x7f, 0x3b, 0x05, 0x3b, 0x90, 0xd1,
+  0x14, 0x4f, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x23,
+  0x29, 0xff, 0xce, 0x67, 0x3d, 0xd8, 0x29, 0xdc,
+  0x86, 0x89, 0x96, 0x7f, 0x3b, 0x05, 0x3b, 0x90,
+  0xd1, 0x52, 0x4f, 0xe7, 0x60, 0xa7, 0x72, 0x1a,
+  0x2b, 0xa9, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
+  0x8b, 0x3f, 0xf3, 0x39, 0xee, 0xc1, 0x4e, 0xe4,
+  0x34, 0x4f, 0x53, 0xfc, 0x17, 0x72, 0xfb, 0x73,
+  0xcd, 0xe7, 0x43, 0x91, 0x14, 0xa9, 0x93, 0xf6,
+  0xeb, 0xb2, 0xfe, 0xd6, 0xa7, 0x4f, 0x0b, 0x2f,
+  0x49, 0xd3, 0x93, 0x2c, 0x54, 0xff, 0xfd, 0x6f,
+  0xf6, 0x9f, 0x0a, 0xbd, 0xf9, 0x50, 0x01, 0x4e,
+  0x9f, 0xff, 0x87, 0xcd, 0xfc, 0xc7, 0x28, 0x8f,
+  0x9b, 0xd3, 0x5a, 0x0e, 0x9f, 0x27, 0xad, 0xbd,
+  0x87, 0x4f, 0xfe, 0xea, 0xff, 0x00, 0xeb, 0x79,
+  0x38, 0x4e, 0x9f, 0x5e, 0xca, 0xc4, 0x3a, 0x7f,
+  0xf7, 0xf4, 0x2a, 0xfd, 0x59, 0xa3, 0x45, 0xb7,
+  0x0e, 0x9b, 0xa9, 0x3a, 0x7f, 0x75, 0x7a, 0xda,
+  0xfe, 0x83, 0xa3, 0xe7, 0x95, 0xa8, 0xb4, 0x79,
+  0x50, 0x80, 0xad, 0xb1, 0x82, 0xc5, 0x3f, 0x47,
+  0xb9, 0x33, 0x7c, 0x27, 0x27, 0x7f, 0xae, 0x6a,
+  0x85, 0xa7, 0x7f, 0xd5, 0x3a, 0x41, 0xdd, 0x0f,
+  0x11, 0x4a, 0x27, 0x85, 0xb7, 0x30, 0xe8, 0xc3,
+  0xce, 0xf1, 0x64, 0xff, 0xbd, 0x6e, 0xba, 0xb5,
+  0x5f, 0x30, 0xe9, 0xf7, 0xf4, 0xfb, 0x2a, 0x74,
+  0xff, 0xd8, 0x1e, 0x06, 0x25, 0xb8, 0x15, 0x3a,
+  0x3c, 0x7d, 0x5f, 0x29, 0x9e, 0xfe, 0xda, 0x34,
+  0x9d, 0x3f, 0x65, 0x43, 0xdf, 0xa0, 0xe8, 0xe3,
+  0xd4, 0xf9, 0x3c, 0xfb, 0x5d, 0x35, 0xd9, 0x4e,
+  0x8c, 0x46, 0x17, 0x9d, 0xac, 0x43, 0x3f, 0xff,
+  0xfa, 0xcb, 0xe1, 0x15, 0xdf, 0x7f, 0x7f, 0x57,
+  0xe5, 0x76, 0xd7, 0x85, 0xe7, 0x4f, 0xa8, 0xd8,
+  0x7c, 0x13, 0xa7, 0xed, 0xb8, 0x41, 0xb9, 0x87,
+  0x4f, 0xfb, 0xfe, 0x7d, 0xed, 0x83, 0xea, 0x9d,
+  0x3f, 0xee, 0xc0, 0x2f, 0xfb, 0x6c, 0xd2, 0x74,
+  0x3c, 0xff, 0x00, 0x7d, 0x3f, 0xf9, 0x72, 0x9b,
+  0xd9, 0x6f, 0xf5, 0x05, 0x4e, 0x9d, 0x5b, 0x30,
+  0xe8, 0xb9, 0xf2, 0xea, 0x93, 0x3f, 0x6b, 0x5b,
+  0xd7, 0x2e, 0x74, 0xe0, 0x84, 0x25, 0x4f, 0xfe,
+  0xbf, 0xaf, 0x5b, 0x7b, 0x73, 0x78, 0xab, 0xca,
+  0x71, 0x79, 0x1e, 0x45, 0x46, 0xa9, 0x50, 0xf5,
+  0x58, 0x98, 0xf5, 0xe2, 0x91, 0x85, 0x5f, 0xe1,
+  0x0f, 0x78, 0x65, 0xcd, 0xa7, 0x0e, 0x9f, 0x06,
+  0xeb, 0x48, 0x4e, 0x9f, 0xcb, 0xc3, 0x60, 0xf6,
+  0xc5, 0x4c, 0x10, 0x95, 0x1b, 0x1e, 0x38, 0x4c,
+  0x67, 0xab, 0x7f, 0x6e, 0xca, 0x71, 0xa3, 0x98,
+  0x35, 0x3a, 0x58, 0x74, 0xa9, 0xc3, 0x4b, 0x71,
+  0x69, 0xff, 0xab, 0x5d, 0xbe, 0xbb, 0x59, 0x6f,
+  0x53, 0xa1, 0x4f, 0xb7, 0x52, 0x79, 0xff, 0x5f,
+  0xc3, 0xc0, 0x6f, 0xbe, 0x58, 0xe8, 0x79, 0xf1,
+  0x78, 0x8a, 0x7d, 0x94, 0x67, 0x84, 0xe9, 0xfa,
+  0xea, 0x3b, 0x67, 0xce, 0x9f, 0xdb, 0x59, 0x7e,
+  0x1e, 0xa4, 0xe9, 0xff, 0xbd, 0xb5, 0x95, 0x14,
+  0x1d, 0xf0, 0x1d, 0x3f, 0xff, 0xef, 0x33, 0xbf,
+  0x4b, 0xdc, 0x1c, 0xf3, 0x6c, 0xfe, 0x6d, 0xcf,
+  0x3c, 0x5e, 0xb0, 0xa9, 0x8f, 0xf1, 0x65, 0x4d,
+  0x35, 0x43, 0x9f, 0xfe, 0xcb, 0xd7, 0x1a, 0xb2,
+  0xb6, 0xcb, 0x59, 0x4e, 0x9f, 0xff, 0xff, 0x7b,
+  0x29, 0xaf, 0xb0, 0x3a, 0x32, 0x97, 0xd7, 0xd7,
+  0xaf, 0xa9, 0xdb, 0x6d, 0x68, 0x3a, 0x3e, 0x8d,
+  0xeb, 0xa8, 0x4d, 0xe0, 0x9d, 0x36, 0xf0, 0x1d,
+  0x0d, 0x1a, 0xe0, 0x0b, 0x4e, 0x7f, 0x6c, 0x74,
+  0xc1, 0x09, 0xd1, 0xe3, 0xd4, 0xa9, 0x10, 0x47,
+  0x27, 0x5f, 0x78, 0x0a, 0x71, 0xaf, 0x9f, 0xff,
+  0xfd, 0x75, 0xda, 0xda, 0xf6, 0x96, 0x76, 0xd9,
+  0x9f, 0xd3, 0x5a, 0xe7, 0xc0, 0x74, 0x52, 0x8a,
+  0xbf, 0x17, 0x4f, 0xf6, 0x5e, 0xca, 0x37, 0xc4,
+  0x3a, 0x72, 0x8b, 0x47, 0x46, 0x27, 0xe7, 0xd1,
+  0xbf, 0xfc, 0x93, 0x70, 0xd6, 0x7d, 0xfc, 0xbf,
+  0x37, 0x9d, 0x3f, 0xf6, 0x08, 0xe3, 0x56, 0xca,
+  0xf7, 0xce, 0x9f, 0xdf, 0x51, 0xd5, 0x2c, 0xa7,
+  0x4f, 0xbd, 0xa6, 0xdc, 0xf3, 0xa7, 0xef, 0x2b,
+  0x28, 0xc0, 0x9d, 0x30, 0x42, 0x74, 0x21, 0xf6,
+  0x09, 0x48, 0x4b, 0x67, 0xfb, 0x1a, 0xe6, 0xba,
+  0x97, 0xd4, 0xa7, 0x1a, 0xd9, 0xff, 0xd9, 0xf0,
+  0x65, 0xbd, 0x4d, 0x6d, 0xad, 0x4e, 0x9f, 0xbf,
+  0xc0, 0xdb, 0x3e, 0x74, 0xfc, 0xcf, 0x6e, 0x60,
+  0xe9, 0x3a, 0x70, 0x42, 0x12, 0xa7, 0xfe, 0x51,
+  0xfe, 0xbd, 0xbf, 0x1a, 0x56, 0x1c, 0xe2, 0xf2,
+  0x37, 0x6a, 0x8b, 0x9a, 0x86, 0x55, 0x52, 0xae,
+  0x99, 0xa9, 0x68, 0x53, 0x67, 0x70, 0xd0, 0x79,
+  0x04, 0xa7, 0x9f, 0x94, 0xbc, 0xf2, 0x09, 0x4e,
+  0xaf, 0xb6, 0x3c, 0x82, 0x53, 0x04, 0x27, 0x90,
+  0x4a, 0x11, 0x14, 0x8d, 0x14, 0x5c, 0xbc, 0x25,
+  0x53, 0x75, 0xcb, 0x20, 0x91, 0xc6, 0xf6, 0x7e,
+  0xcb, 0x66, 0x7f, 0x49, 0xd3, 0xbb, 0xe0, 0xf9,
+  0xf0, 0x5c, 0xce, 0x7b, 0x73, 0x3a, 0xc7, 0x4b,
+  0x37, 0x67, 0xac, 0x03, 0x39, 0xfc, 0xd3, 0xf5,
+  0xa2, 0xfe, 0xa0, 0xa9, 0xfd, 0xe7, 0xeb, 0xd5,
+  0xb7, 0x8e, 0x93, 0xca, 0x9d, 0xc3, 0x41, 0x50,
+  0x54, 0x29, 0xb5, 0x41, 0x06, 0x0d, 0xcf, 0x7d,
+  0x40, 0x85, 0x38, 0xd6, 0x42, 0xa3, 0x17, 0x21,
+  0x2b, 0x3d, 0xaf, 0x0b, 0xce, 0x93, 0x0e, 0x9b,
+  0x1f, 0xb1, 0xb1, 0x68, 0x86, 0x7c, 0x1c, 0x6b,
+  0xcc, 0x3a, 0x7e, 0x45, 0x69, 0xea, 0x02, 0xa5,
+  0xe3, 0xa7, 0xfa, 0x8d, 0x5f, 0xb5, 0xb5, 0xef,
+  0x9d, 0x3f, 0x79, 0x59, 0x46, 0x04, 0xe9, 0xf6,
+  0x50, 0xcc, 0x61, 0xd3, 0xab, 0xe1, 0x3a, 0x3e,
+  0x78, 0x57, 0x27, 0x9f, 0xbf, 0xc0, 0x06, 0xb5,
+  0x3a, 0x7e, 0xf6, 0x9d, 0xea, 0xc7, 0x6c, 0x98,
+  0x66, 0x08, 0x09, 0xed, 0x5b, 0xee, 0x45, 0x18,
+  0x9e, 0x8f, 0x8a, 0x3f, 0x19, 0xc4, 0xf7, 0xf2,
+  0x8d, 0x4e, 0x87, 0xab, 0xd7, 0xc2, 0xbb, 0x43,
+  0xf7, 0xea, 0xf5, 0x8f, 0xfe, 0xe6, 0xd3, 0xff,
+  0xea, 0x04, 0x73, 0x6e, 0x65, 0xba, 0xff, 0x56,
+  0x8e, 0x9c, 0x10, 0x84, 0xa9, 0x9e, 0xa5, 0x38,
+  0xbc, 0x85, 0x44, 0xa8, 0xb8, 0xcf, 0xd4, 0x34,
+  0xf6, 0xe0, 0xd0, 0x74, 0xf5, 0xba, 0x90, 0x9d,
+  0x3e, 0xa0, 0x7c, 0xac, 0x3a, 0x7f, 0xf9, 0x77,
+  0xdf, 0xea, 0x0e, 0xb8, 0x37, 0xfd, 0xe7, 0x46,
+  0xea, 0x46, 0x87, 0x8d, 0x38, 0x8a, 0xe4, 0xf3,
+  0x9f, 0xef, 0x9d, 0x3f, 0x5d, 0x5a, 0xfe, 0xb5,
+  0x3a, 0x1e, 0x79, 0x77, 0x1c, 0x9d, 0xae, 0xad,
+  0xd9, 0xd3, 0x73, 0x9b, 0xa3, 0x74, 0x31, 0xba,
+  0xc6, 0xdb, 0xaf, 0xc8, 0x96, 0x51, 0x55, 0x10,
+  0xff, 0x79, 0x0e, 0xd1, 0xb5, 0xe4, 0xaf, 0x3d,
+  0x2c, 0xc8, 0x2f, 0xe8, 0x49, 0x35, 0x19, 0x50,
+  0x91, 0x32, 0x34, 0x5b, 0x4b, 0x0e, 0xe4, 0x5f,
+  0x94, 0xd6, 0x53, 0x7d, 0xe7, 0x74, 0xb5, 0x87,
+  0xc6, 0xe4, 0x3c, 0x77, 0xc2, 0x35, 0xbc, 0x8a,
+  0x7f, 0xf3, 0x99, 0xcf, 0x76, 0x0a, 0x77, 0x21,
+  0xa2, 0x8a, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
+  0x5d, 0x13, 0xff, 0x3b, 0x9e, 0xec, 0x14, 0xee,
+  0x43, 0x44, 0x97, 0x3f, 0x9d, 0x82, 0x9d, 0xc8,
+  0x68, 0xbc, 0xa1, 0x5b, 0xf2, 0xba, 0x09, 0xde,
+  0x77, 0x87, 0x68, 0xa4, 0xd1, 0xdb, 0x0e, 0xed,
+  0x0c, 0x5f, 0xd7, 0x47, 0x55, 0x8e, 0xce, 0xea,
+  0x5a, 0x9d, 0xb6, 0x4c, 0x9f, 0xfc, 0xe6, 0x73,
+  0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x96, 0x67, 0x93,
+  0xb9, 0x0d, 0x11, 0x9c, 0xfd, 0xe5, 0x65, 0x18,
+  0x13, 0xa6, 0xfb, 0xce, 0x93, 0x0e, 0x9f, 0x78,
+  0x6d, 0xce, 0x13, 0xd3, 0x61, 0x6e, 0xf1, 0x69,
+  0xfb, 0x9f, 0xe1, 0xe1, 0x3a, 0x75, 0x56, 0x93,
+  0xa0, 0x53, 0x10, 0x63, 0xf7, 0xd3, 0x2e, 0x55,
+  0x3f, 0xf5, 0xfc, 0x3c, 0x0d, 0x14, 0xbd, 0x58,
+  0x74, 0xfb, 0xea, 0xfa, 0xf1, 0xd1, 0xe3, 0xec,
+  0x6c, 0x8d, 0x3f, 0xff, 0x7b, 0x6d, 0x6f, 0x5a,
+  0x5e, 0xbf, 0x05, 0x74, 0x6b, 0xf3, 0xa7, 0xfe,
+  0xc6, 0x5f, 0xc1, 0xaa, 0xdb, 0xb7, 0x67, 0x4f,
+  0xfa, 0xcb, 0xeb, 0x79, 0x7e, 0xd6, 0xa7, 0x49,
+  0xd8, 0x9d, 0xbb, 0x50, 0xa9, 0xe2, 0x4f, 0xb1,
+  0xd5, 0x1e, 0x7f, 0xf3, 0x99, 0xcf, 0x76, 0x0a,
+  0x77, 0x21, 0xa2, 0x69, 0x9f, 0xfc, 0xe6, 0x73,
+  0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x9c, 0x67, 0xff,
+  0x39, 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x28,
+  0x19, 0xf0, 0xa7, 0x72, 0x1a, 0x2e, 0x09, 0x97,
+  0xc7, 0x4f, 0xef, 0xbd, 0x7d, 0xb6, 0x30, 0xe9,
+  0x3b, 0x0f, 0xe2, 0xc6, 0x1a, 0x8a, 0xcf, 0xef,
+  0x3b, 0x7a, 0x83, 0x02, 0x74, 0xff, 0x3d, 0xd8,
+  0x29, 0xdc, 0x86, 0x89, 0x26, 0x4e, 0xb1, 0xfa,
+  0xf1, 0xa4, 0x50, 0xbb, 0x5a, 0xf9, 0x63, 0x28,
+  0xaa, 0xd2, 0x90, 0x14, 0xab, 0x0c, 0xab, 0xc2,
+  0xaa, 0x7f, 0xda, 0x79, 0xd8, 0x29, 0xdc, 0x86,
+  0x8b, 0x52, 0x7f, 0xdc, 0xf7, 0x60, 0xa7, 0x72,
+  0x1a, 0x25, 0x58, 0x3a, 0x4e, 0xd2, 0x89, 0x86,
+  0x24, 0x37, 0xa3, 0x4f, 0xe7, 0x60, 0xa7, 0x72,
+  0x1a, 0x22, 0x99, 0xfc, 0xec, 0x14, 0xee, 0x43,
+  0x44, 0x69, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68,
+  0xa7, 0xe7, 0xff, 0x39, 0x9c, 0xf7, 0x60, 0xa7,
+  0x72, 0x1a, 0x26, 0xa9, 0xfc, 0xec, 0x14, 0xee,
+  0x43, 0x45, 0x77, 0x3c, 0x9d, 0xc8, 0x68, 0xaf,
+  0xa7, 0x04, 0x21, 0x2a, 0x5f, 0x29, 0xc5, 0xe4,
+  0x09, 0xf3, 0x31, 0x1e, 0x73, 0xd6, 0x93, 0xa7,
+  0xfd, 0x96, 0x0f, 0x5e, 0xab, 0x94, 0x1d, 0x2b,
+  0x9d, 0x3f, 0xde, 0x1c, 0xa3, 0xcf, 0xcd, 0x8e,
+  0x81, 0x3c, 0x9e, 0x10, 0x93, 0xb1, 0x1c, 0x6d,
+  0x10, 0xfc, 0x72, 0xb0, 0x86, 0x9f, 0xfc, 0xe6,
+  0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x9e, 0xe7,
+  0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x17, 0x0c, 0xff,
+  0xce, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x27,
+  0xc2, 0xab, 0xe3, 0xa0, 0xed, 0xe7, 0x7a, 0x4e,
+  0xd0, 0xed, 0xa5, 0x21, 0x8e, 0x12, 0xc9, 0x15,
+  0x52, 0x6c, 0x77, 0x3f, 0x9d, 0x82, 0x9d, 0xc8,
+  0x68, 0x8a, 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d,
+  0x14, 0xcc, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14,
+  0xee, 0x43, 0x44, 0xcf, 0x3f, 0xf9, 0xcc, 0xe7,
+  0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x46, 0xc5, 0x09,
+  0x8d, 0x6c, 0x77, 0xa4, 0xee, 0xea, 0x53, 0xff,
+  0x3b, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x75,
+  0x3f, 0x7b, 0x3f, 0xb6, 0x50, 0x74, 0xf8, 0x53,
+  0xb9, 0x0d, 0x14, 0xd4, 0xff, 0xcf, 0xb7, 0xbf,
+  0x45, 0x75, 0x51, 0x68, 0xe9, 0xfb, 0xca, 0xca,
+  0x30, 0x27, 0x4f, 0xff, 0x65, 0xed, 0x8f, 0x1e,
+  0xfd, 0xed, 0xcf, 0x3a, 0x65, 0x01, 0xd3, 0xfd,
+  0x5e, 0xa5, 0x53, 0xc8, 0xe1, 0x44, 0x7f, 0xcb,
+  0x77, 0xa6, 0xc9, 0xdb, 0x27, 0x25, 0x85, 0xd4,
+  0x98, 0x5e, 0x1a, 0xd3, 0xe1, 0x4e, 0xe4, 0x34,
+  0x55, 0x53, 0xfe, 0xe7, 0xbb, 0x05, 0x3b, 0x90,
+  0xd1, 0x36, 0xc9, 0xd8, 0x7e, 0xcc, 0x30, 0x9f,
+  0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x57, 0xf3, 0xf9,
+  0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x1a, 0x7c, 0x29,
+  0xdc, 0x86, 0x8b, 0x56, 0x7f, 0xdc, 0xf7, 0x60,
+  0xa7, 0x72, 0x1a, 0x28, 0x29, 0x3b, 0x0f, 0xd9,
+  0x86, 0x13, 0xe1, 0x4e, 0xe4, 0x34, 0x5c, 0x53,
+  0xcd, 0xed, 0xfe, 0x43, 0xa7, 0xf2, 0xb3, 0x9b,
+  0x28, 0xb7, 0x9d, 0x27, 0x62, 0x23, 0x38, 0xc2,
+  0xe4, 0xf3, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b,
+  0xa6, 0x7f, 0xff, 0x2d, 0xbf, 0xaf, 0x6e, 0xf1,
+  0xf6, 0xcd, 0x39, 0xb3, 0x5a, 0x9d, 0x3f, 0xe7,
+  0xe0, 0x8f, 0x3e, 0x8c, 0x09, 0xd3, 0xbf, 0xce,
+  0x14, 0x52, 0xdd, 0xa6, 0x7f, 0xc2, 0xb4, 0xdb,
+  0xab, 0x75, 0x09, 0xd3, 0xf6, 0xe9, 0xfc, 0xb7,
+  0x5c, 0xe9, 0xf8, 0x1c, 0xd3, 0xfd, 0x73, 0xa7,
+  0xff, 0xfd, 0xa5, 0x76, 0xb6, 0x53, 0x7f, 0xf5,
+  0x81, 0xd5, 0xaf, 0x0a, 0x1d, 0x3c, 0x9d, 0xc8,
+  0x68, 0x93, 0x27, 0xf8, 0x72, 0x9b, 0xdf, 0x9f,
+  0x53, 0xa0, 0x4f, 0x8d, 0x85, 0x73, 0xf6, 0xc0,
+  0xdd, 0x2a, 0x0d, 0xc3, 0xa7, 0xff, 0x5b, 0xd7,
+  0xa5, 0x3c, 0x35, 0x69, 0x78, 0xe9, 0xf6, 0x5f,
+  0xcc, 0xe3, 0xa7, 0xff, 0xdc, 0x82, 0xb6, 0xfe,
+  0x5f, 0x1c, 0x10, 0x84, 0xa8, 0x79, 0xfc, 0x5c,
+  0x9a, 0x7f, 0xf6, 0xbf, 0xeb, 0xa8, 0xd6, 0xcb,
+  0xfb, 0x9d, 0x38, 0x21, 0x09, 0x53, 0xf0, 0xf5,
+  0x0c, 0xf5, 0x4a, 0x71, 0x79, 0x3e, 0xc6, 0x0e,
+  0x6e, 0xce, 0x9f, 0x7a, 0xf4, 0x60, 0x4e, 0x9f,
+  0xe5, 0x4b, 0x7f, 0x5b, 0xad, 0x4e, 0x81, 0x3e,
+  0x06, 0x14, 0x4f, 0xf6, 0x70, 0x34, 0x66, 0xdc,
+  0xf3, 0xa7, 0xff, 0x75, 0x16, 0xf2, 0xff, 0x1a,
+  0xf0, 0xf8, 0xe8, 0xc4, 0x52, 0x5c, 0x84, 0x27,
+  0x33, 0xef, 0xe5, 0xba, 0xe7, 0x4f, 0xf9, 0xeb,
+  0xfa, 0x37, 0x8f, 0xf5, 0x79, 0xd1, 0xbb, 0x3e,
+  0x86, 0x89, 0xa7, 0xaf, 0x46, 0x6c, 0x74, 0xff,
+  0x7b, 0x4e, 0xf1, 0x03, 0x3d, 0x53, 0xa1, 0xa3,
+  0xe0, 0xdc, 0x23, 0x9c, 0x10, 0x84, 0xe9, 0xff,
+  0xf6, 0x32, 0xff, 0x50, 0x66, 0xd5, 0xc6, 0x2a,
+  0x14, 0xe2, 0xf2, 0x31, 0x32, 0xbf, 0x42, 0x1e,
+  0xc8, 0x53, 0xf5, 0x97, 0x42, 0x7a, 0x83, 0xa7,
+  0xe1, 0xe1, 0xfa, 0xbc, 0xe8, 0xd8, 0xf6, 0x44,
+  0xbe, 0x67, 0xb9, 0xb8, 0xbd, 0x56, 0xa6, 0x2f,
+  0x2e, 0xc8, 0x68, 0x69, 0x21, 0x43, 0x7a, 0x61,
+  0x84, 0xd1, 0x17, 0x32, 0xfc, 0xf2, 0xb1, 0x96,
+  0xde, 0x3c, 0x2d, 0xf0, 0x8e, 0x9f, 0x63, 0x07,
+  0x37, 0x67, 0x4f, 0xfd, 0x96, 0xfa, 0xd1, 0xbe,
+  0xd6, 0xed, 0xd9, 0xd3, 0xf7, 0x23, 0x82, 0x10,
+  0x9d, 0x27, 0x23, 0x22, 0x70, 0x4c, 0xfa, 0x7b,
+  0xa3, 0xf0, 0xe2, 0xa9, 0x4b, 0x64, 0xa8, 0x7b,
+  0x3a, 0x07, 0x68, 0xf7, 0xa9, 0x86, 0x00, 0x93,
+  0xb0, 0xec, 0x10, 0xb1, 0xac, 0x2c, 0xee, 0x69,
+  0xad, 0x25, 0xf2, 0x7f, 0x3b, 0x05, 0x3b, 0x90,
+  0xd1, 0x1a, 0xcf, 0x85, 0x3b, 0x90, 0xd1, 0x52,
+  0xcd, 0xc8, 0x68, 0x86, 0xa4, 0xec, 0x3d, 0x1e,
+  0x30, 0x9f, 0xf9, 0xdc, 0xf7, 0x60, 0xa7, 0x72,
+  0x1a, 0x23, 0xe9, 0xfc, 0xec, 0x14, 0xee, 0x43,
+  0x45, 0x8f, 0x3f, 0x6e, 0x9f, 0xcb, 0x75, 0xce,
+  0x9f, 0xef, 0xf0, 0x2b, 0xd7, 0xbf, 0x1d, 0x3c,
+  0x06, 0x78, 0x4e, 0x9f, 0xff, 0xe5, 0x1f, 0xe6,
+  0xd9, 0x6b, 0x79, 0x2d, 0xeb, 0xd7, 0xa9, 0x3a,
+  0x3c, 0x88, 0x7b, 0x10, 0xce, 0xee, 0x43, 0x45,
+  0xa1, 0x3f, 0xee, 0x0b, 0x7a, 0x70, 0xd1, 0x81,
+  0x3a, 0x42, 0x87, 0xca, 0x24, 0xd3, 0xf3, 0x6d,
+  0xf7, 0xfa, 0x80, 0xe9, 0xf2, 0xdf, 0x2c, 0xa7,
+  0x4f, 0xff, 0x65, 0xeb, 0x8d, 0x59, 0x5b, 0x65,
+  0xac, 0xa7, 0x45, 0x07, 0xeb, 0xf2, 0x58, 0x54,
+  0x64, 0xe4, 0x29, 0xa7, 0xfe, 0xca, 0xfb, 0x5f,
+  0xbc, 0x57, 0x36, 0x3a, 0x7d, 0x7b, 0x77, 0xf4,
+  0x9d, 0x3f, 0xdf, 0xd6, 0x8d, 0xad, 0x9f, 0x53,
+  0xa6, 0xfe, 0x61, 0xf2, 0x21, 0x4c, 0xfe, 0xcb,
+  0x35, 0xeb, 0x79, 0x87, 0x4f, 0xe7, 0xe0, 0xd7,
+  0xeb, 0x41, 0xd3, 0xdb, 0x65, 0xb8, 0xe9, 0xfe,
+  0xcc, 0x0e, 0x22, 0x60, 0x4e, 0x8c, 0x45, 0xdd,
+  0x26, 0x9c, 0x65, 0x52, 0x19, 0xec, 0xb7, 0x5c,
+  0xe9, 0xfd, 0xa7, 0xdf, 0xd5, 0xf9, 0x53, 0xa4,
+  0xe6, 0xe2, 0xe5, 0x5a, 0x98, 0xed, 0x0b, 0xec,
+  0x84, 0x45, 0xa1, 0xdd, 0xf2, 0x6a, 0xc2, 0xa2,
+  0xf0, 0xe6, 0xdc, 0x3c, 0xde, 0x41, 0x3f, 0x37,
+  0xfb, 0x6f, 0xab, 0x47, 0x4f, 0x65, 0xba, 0xe7,
+  0x4b, 0x74, 0xc3, 0xd2, 0xf9, 0x94, 0xf8, 0x53,
+  0xb9, 0x0d, 0x16, 0xb4, 0xff, 0xb9, 0xee, 0xc1,
+  0x4e, 0xe4, 0x34, 0x50, 0x72, 0x73, 0x71, 0x14,
+  0x58, 0x58, 0xc3, 0x09, 0xff, 0xce, 0x67, 0x3d,
+  0xd8, 0x29, 0xdc, 0x86, 0x8a, 0x2e, 0x7f, 0x3b,
+  0x05, 0x3b, 0x90, 0xd1, 0x75, 0x43, 0xd9, 0x0a,
+  0x69, 0x08, 0xcf, 0x13, 0x31, 0x32, 0xd3, 0x9c,
+  0xc0, 0x8e, 0xa6, 0xa7, 0x37, 0x52, 0x9f, 0x0a,
+  0x77, 0x21, 0xa2, 0x21, 0x9d, 0x6c, 0xd8, 0xe9,
+  0x3b, 0x0f, 0x32, 0x93, 0x09, 0xfc, 0xec, 0x14,
+  0xee, 0x43, 0x44, 0x6d, 0x3f, 0x9d, 0x82, 0x9d,
+  0xc8, 0x68, 0xa6, 0xe7, 0xf3, 0xb0, 0x53, 0xb9,
+  0x0d, 0x15, 0x04, 0xfe, 0x76, 0x0a, 0x77, 0x21,
+  0xa2, 0xa6, 0x9f, 0x0a, 0x77, 0x21, 0xa2, 0xb0,
+  0x9f, 0x78, 0x3b, 0x6a, 0x27, 0x4f, 0xf3, 0xdd,
+  0x82, 0x9d, 0xc8, 0x68, 0x8f, 0xe7, 0x62, 0xd0,
+  0x74, 0x9d, 0x88, 0xb5, 0x43, 0x0e, 0x29, 0xfa,
+  0x0c, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14, 0xee,
+  0x43, 0x44, 0xdf, 0x3f, 0xf3, 0x39, 0xee, 0xc1,
+  0x4e, 0xe4, 0x34, 0x4f, 0xd3, 0xf3, 0x75, 0xdd,
+  0x5b, 0xa6, 0xe6, 0x52, 0x74, 0xff, 0xf2, 0xaa,
+  0xaa, 0xaa, 0xaa, 0xad, 0x35, 0x3a, 0x7c, 0x3e,
+  0xa3, 0x98, 0x54, 0xc1, 0x09, 0x51, 0x86, 0xf4,
+  0x24, 0xf2, 0xd4, 0xa7, 0x1a, 0x08, 0x54, 0x63,
+  0xd6, 0x14, 0xd3, 0xf0, 0xf2, 0x5b, 0xc2, 0x74,
+  0xf5, 0x0c, 0xf3, 0xce, 0x9f, 0x57, 0xfa, 0xf3,
+  0xce, 0x9f, 0xd6, 0x56, 0x38, 0x00, 0x53, 0xa4,
+  0x2a, 0x7f, 0xb8, 0x47, 0xe2, 0x89, 0xff, 0x2d,
+  0x3b, 0x6f, 0x5d, 0xdd, 0xb5, 0xa9, 0xd3, 0x81,
+  0x5c, 0x3a, 0x7f, 0xed, 0x96, 0xfd, 0x5c, 0xb5,
+  0xbc, 0xc3, 0xa7, 0x5f, 0xcd, 0x1d, 0x0a, 0x7c,
+  0x35, 0x44, 0x85, 0x4f, 0x93, 0xc4, 0xe3, 0x0a,
+  0x76, 0x19, 0x7d, 0x1e, 0xef, 0x93, 0xdc, 0xd6,
+  0xf6, 0x1d, 0x37, 0x7c, 0xe8, 0x13, 0x72, 0xc2,
+  0x49, 0xc1, 0x08, 0x4e, 0x9e, 0xa3, 0xfe, 0x52,
+  0x9c, 0x5e, 0x4f, 0x53, 0x7f, 0x21, 0xd0, 0xa8,
+  0x8f, 0xb1, 0xe6, 0xa6, 0x33, 0xff, 0x51, 0xa8,
+  0x33, 0xfa, 0xb4, 0xb7, 0xe3, 0xa7, 0x96, 0xf5,
+  0x43, 0x44, 0x1d, 0x3f, 0x75, 0x97, 0x77, 0xab,
+  0xce, 0x81, 0x45, 0x2d, 0xd1, 0xdb, 0x16, 0xcc,
+  0x3b, 0x1d, 0x30, 0x42, 0x74, 0x3c, 0xd6, 0x04,
+  0x5a, 0x7a, 0xab, 0xe6, 0xc5, 0x38, 0xd0, 0xcf,
+  0xab, 0xbf, 0x60, 0x54, 0xe8, 0xf1, 0xef, 0x6f,
+  0x33, 0x9c, 0x10, 0x84, 0xa8, 0x29, 0xc5, 0xe4,
+  0xf7, 0x83, 0xe6, 0x8a, 0x84, 0x37, 0x9e, 0x19,
+  0x8f, 0x26, 0xf1, 0x68, 0x6e, 0x7d, 0xf2, 0x77,
+  0xfd, 0x53, 0xa7, 0xb6, 0xef, 0x80, 0xe9, 0xff,
+  0x97, 0xe0, 0xfa, 0xd2, 0xd2, 0xfc, 0x07, 0x47,
+  0x91, 0x06, 0x01, 0xca, 0x91, 0x4f, 0x97, 0x06,
+  0xde, 0x3a, 0x7b, 0x6c, 0x66, 0xec, 0xe8, 0x68,
+  0xf2, 0xdb, 0x12, 0xcf, 0xd7, 0xc6, 0xbe, 0xac,
+  0x3c, 0x40, 0x53, 0xee, 0xfe, 0xd6, 0x53, 0x44,
+  0x04, 0xe3, 0x75, 0x3f, 0xca, 0x34, 0x68, 0xc6,
+  0xbc, 0xc3, 0xa7, 0xca, 0x0f, 0x53, 0x53, 0xa7,
+  0xf0, 0xb5, 0x5f, 0x7e, 0xfe, 0x3a, 0x7a, 0x90,
+  0x0a, 0x95, 0x30, 0x42, 0x54, 0x29, 0xb7, 0x09,
+  0x0c, 0xfd, 0xc2, 0xf7, 0xff, 0xc5, 0x38, 0xd0,
+  0x42, 0xaa, 0x48, 0xc7, 0xbf, 0x2f, 0xd9, 0x13,
+  0xe7, 0x77, 0x28, 0xd6, 0x11, 0x73, 0xed, 0x6f,
+  0xaf, 0x6f, 0x34, 0x40, 0xf3, 0xfe, 0xb6, 0xb4,
+  0x2e, 0x85, 0xba, 0xec, 0x74, 0xee, 0x1a, 0x0e,
+  0x98, 0x21, 0x3a, 0x7f, 0x0f, 0xb1, 0xb6, 0xf7,
+  0xb9, 0x0d, 0x88, 0x46, 0xe3, 0x64, 0x5f, 0x8b,
+  0x9c, 0xff, 0xdf, 0xcd, 0x36, 0xe7, 0xef, 0xea,
+  0x54, 0xe8, 0x53, 0xea, 0xc2, 0x39, 0xff, 0xd8,
+  0xc6, 0x73, 0xf0, 0x53, 0xb9, 0x0d, 0x10, 0xc4,
+  0x58, 0xfc, 0x7e, 0x41, 0x3f, 0x60, 0xa7, 0x72,
+  0x1a, 0x20, 0xa9, 0xeb, 0xd5, 0x40, 0x54, 0xee,
+  0x1a, 0x0a, 0x9e, 0xd7, 0xfd, 0xa4, 0xa9, 0xfd,
+  0xea, 0x32, 0xf5, 0x50, 0x15, 0x05, 0x4f, 0xd8,
+  0x8b, 0x65, 0x61, 0x53, 0x04, 0x25, 0x4f, 0xdf,
+  0x5f, 0xd1, 0xe1, 0x2a, 0x31, 0x30, 0xa4, 0x21,
+  0x60, 0xdd, 0x89, 0x00, 0x67, 0xf0, 0xa0, 0x95,
+  0x6f, 0x16, 0x9b, 0xc2, 0x53, 0x8f, 0xca, 0x5c,
+  0xf4, 0xf5, 0xed, 0x1d, 0x8c, 0xff, 0x95, 0xfd,
+  0xfc, 0xa8, 0xad, 0x4e, 0x9f, 0xeb, 0xd9, 0x5b,
+  0x6c, 0xa0, 0x53, 0xa7, 0xf9, 0x69, 0x7e, 0xe2,
+  0xa6, 0x30, 0xe8, 0x53, 0xf4, 0xb1, 0xd4, 0xff,
+  0xfc, 0xd7, 0x73, 0xfa, 0xda, 0x32, 0x8d, 0x6f,
+  0xaf, 0x6f, 0x34, 0x5f, 0x73, 0xef, 0x5f, 0xf8,
+  0xf3, 0xa7, 0xfd, 0xff, 0x3e, 0xf6, 0xc1, 0xf5,
+  0x4e, 0x9f, 0xd7, 0x06, 0xff, 0xbe, 0xd8, 0x78,
+  0x80, 0x67, 0x70, 0xbc, 0xf1, 0x00, 0xc6, 0x1f,
+  0x4e, 0xa8, 0x53, 0x73, 0xcf, 0x10, 0x0c, 0xf7,
+  0x7e, 0x97, 0x9e, 0x20, 0x19, 0xfd, 0xe4, 0xb6,
+  0x00, 0x0a, 0x78, 0x80, 0x67, 0x7b, 0xfb, 0x1e,
+  0x20, 0x18, 0xd9, 0x17, 0x2c, 0x22, 0xb1, 0x7b,
+  0x63, 0xe9, 0xc2, 0xb7, 0x3c, 0x40, 0x30, 0x78,
+  0x80, 0x66, 0x56, 0x1e, 0x20, 0x18, 0xd8, 0xdc,
+  0xf8, 0x5e, 0x7b, 0xcc, 0xd9, 0x4f, 0x10, 0x0c,
+  0xeb, 0xf2, 0x1e, 0x20, 0x19, 0xff, 0x7f, 0x9e,
+  0xeb, 0x79, 0x38, 0x4f, 0x10, 0x0c, 0xdd, 0xb1,
+  0xe2, 0x01, 0x9f, 0xdf, 0xe0, 0xd6, 0xaa, 0x03,
+  0xc4, 0x03, 0x3e, 0xf6, 0x9e, 0xf8, 0x0f, 0x10,
+  0x0c, 0xde, 0xa9, 0xe2, 0x01, 0x81, 0x3d, 0x9b,
+  0x9b, 0x4f, 0xaf, 0xf5, 0xa5, 0xe6, 0x88, 0x06,
+  0x60, 0x29, 0xe2, 0x01, 0x71, 0xb5, 0x9f, 0x79,
+  0x59, 0xdb, 0x1e, 0x20, 0x19, 0xed, 0x7b, 0xe8,
+  0x78, 0x80, 0x67, 0x28, 0xa1, 0xe2, 0x01, 0x9f,
+  0xf6, 0x53, 0x5d, 0x97, 0x3e, 0x0a, 0x9e, 0x20,
+  0x19, 0xf6, 0xbc, 0xf7, 0xa9, 0xe2, 0x01, 0x8c,
+  0x44, 0x05, 0x93, 0x26, 0x10, 0x1e, 0x20, 0x18,
+  0x7a, 0xa8, 0xfd, 0x88, 0xf2, 0x13, 0x1e, 0x56,
+  0xb1, 0x90, 0x0d, 0x2a, 0x5d, 0x78, 0x53, 0x6a,
+  0x45, 0x3e, 0xcb, 0xd7, 0xa9, 0x3c, 0x40, 0x33,
+  0xfb, 0x65, 0x46, 0x85, 0x6e, 0x78, 0x80, 0x76,
+  0x36, 0x93, 0x85, 0x42, 0x78, 0x80, 0x61, 0x0f,
+  0xdc, 0x54, 0x27, 0xbd, 0xf7, 0xd4, 0xf1, 0x00,
+  0xcf, 0xdc, 0xd3, 0xf2, 0x97, 0x9e, 0x20, 0x18,
+  0xc4, 0x45, 0x00, 0x83, 0x52, 0xf9, 0xfe, 0xb2,
+  0xd5, 0xd5, 0xd4, 0x40, 0x78, 0x80, 0x65, 0xe3,
+  0xc4, 0x03, 0x37, 0x51, 0xb1, 0xf1, 0xd9, 0x1a,
+  0x61, 0x01, 0xe2, 0x01, 0x9f, 0x75, 0xeb, 0xea,
+  0x4f, 0x10, 0x0c, 0xfd, 0xef, 0xea, 0xfc, 0xa9,
+  0xe2, 0x01, 0x85, 0x44, 0x97, 0xc8, 0xae, 0x6b,
+  0x1b, 0x32, 0x03, 0xb2, 0x1b, 0x6d, 0x20, 0x0b,
+  0x05, 0x88, 0xb8, 0xbc, 0x04, 0xf5, 0x95, 0xb1,
+  0x78, 0xf0, 0x37, 0x21, 0x27, 0xbe, 0x18, 0x33,
+  0xbb, 0x90, 0xd1, 0x00, 0xb9, 0x17, 0x93, 0xda,
+  0x77, 0x5b, 0x66, 0x1d, 0x30, 0x14, 0xa9, 0x69,
+  0x2a, 0x75, 0x96, 0x83, 0xa6, 0x08, 0x4a, 0x8f,
+  0x1e, 0xce, 0xec, 0x55, 0xa1, 0x20, 0x8e, 0x4e,
+  0x67, 0xaa, 0x53, 0x8f, 0x06, 0x7a, 0xf5, 0x6f,
+  0xd4, 0xe8, 0xa1, 0x95, 0xd2, 0xf2, 0x74, 0xa4,
+  0xb8, 0xf8, 0xe0, 0x10, 0xc6, 0xde, 0x5b, 0x3f,
+  0x0b, 0x4f, 0x51, 0xa0, 0xe9, 0xff, 0x3e, 0xba,
+  0x3f, 0x8c, 0x51, 0xd2, 0x74, 0xff, 0xc3, 0x6e,
+  0xc7, 0xa8, 0x83, 0x7b, 0x0e, 0x9f, 0xb7, 0x84,
+  0x7d, 0x96, 0x2a, 0x79, 0xab, 0x73, 0x47, 0x4f,
+  0xb1, 0xa7, 0xad, 0x27, 0x4f, 0x67, 0xd5, 0xe5,
+  0x40, 0x9f, 0x5f, 0xc8, 0xdb, 0xca, 0x21, 0x53,
+  0x7b, 0xc2, 0xdf, 0x20, 0xd9, 0x0f, 0xa1, 0x33,
+  0x3d, 0xef, 0xde, 0xa7, 0x4e, 0xd5, 0xbb, 0xa9,
+  0xd3, 0xff, 0x01, 0x98, 0x96, 0xf6, 0xd6, 0xd7,
+  0x49, 0xd3, 0xff, 0x5e, 0xb9, 0xb2, 0xd3, 0x5c,
+  0xa6, 0xe7, 0x4f, 0xe7, 0xe5, 0x77, 0xd6, 0xf8,
+  0x74, 0x2a, 0x39, 0x3c, 0x45, 0xc9, 0x1a, 0xa3,
+  0x4f, 0xb9, 0xb6, 0xdb, 0x29, 0xd3, 0x56, 0xa7,
+  0x4e, 0x08, 0x42, 0x74, 0xc0, 0xe2, 0x9c, 0x5e,
+  0x40, 0x9e, 0xb5, 0x4c, 0xa7, 0x70, 0x30, 0xa8,
+  0x7a, 0x2e, 0xd9, 0x08, 0x0d, 0xc2, 0x19, 0xfd,
+  0x7f, 0xe5, 0x20, 0xde, 0xf3, 0xa7, 0xfb, 0xf8,
+  0xdb, 0x1c, 0x10, 0x84, 0xa9, 0xcc, 0xeb, 0x9d,
+  0x16, 0x3d, 0x56, 0xc7, 0x50, 0xa8, 0xe7, 0xf1,
+  0xc7, 0x42, 0x2e, 0x7f, 0xf6, 0x6d, 0xcc, 0xca,
+  0x5f, 0x80, 0xcd, 0x8e, 0x9a, 0xdc, 0x74, 0xcd,
+  0x54, 0xe9, 0xf6, 0x36, 0xf7, 0xf6, 0xc3, 0x59,
+  0xbc, 0x56, 0x34, 0x22, 0xe1, 0xce, 0xd3, 0xdb,
+  0x65, 0xb8, 0xe9, 0xff, 0x97, 0x3e, 0xfb, 0x67,
+  0xfe, 0xa1, 0x3a, 0x5e, 0x14, 0x44, 0x7c, 0x96,
+  0xe4, 0x31, 0x43, 0x6d, 0xc0, 0xf8, 0xf4, 0xb6,
+  0x8f, 0xe7, 0x49, 0x7a, 0x42, 0xbf, 0xc4, 0x23,
+  0x4b, 0x57, 0xb4, 0x7c, 0xc0, 0x4d, 0xfc, 0x60,
+  0xd7, 0x8f, 0x79, 0xb4, 0x6e, 0x73, 0xfd, 0x83,
+  0xf5, 0xbb, 0xf2, 0xc7, 0x4f, 0xdf, 0x06, 0x6d,
+  0xcf, 0x3a, 0x7d, 0xbd, 0xa7, 0xae, 0xec, 0xa8,
+  0x54, 0x48, 0xe1, 0xb6, 0xf2, 0xd9, 0xff, 0xc3,
+  0xa7, 0xfa, 0xf6, 0xfc, 0xaf, 0x97, 0xe7, 0x4b,
+  0x79, 0xa2, 0x05, 0x95, 0xcd, 0x40, 0xa4, 0xbd,
+  0x73, 0x78, 0x11, 0xf9, 0xff, 0x7b, 0x72, 0xde,
+  0xde, 0xe0, 0x01, 0x4a, 0x9f, 0xfd, 0x7a, 0xf5,
+  0x3a, 0x18, 0xb9, 0xfb, 0xee, 0x1d, 0x0a, 0x89,
+  0x3f, 0x22, 0x4e, 0xa3, 0xef, 0x3a, 0x15, 0x38,
+  0x26, 0x42, 0x26, 0xd0, 0xba, 0xd4, 0x8a, 0x7f,
+  0x3d, 0xac, 0xff, 0x5b, 0x0e, 0x9f, 0xfc, 0x29,
+  0xfc, 0x6d, 0xfc, 0x51, 0x5a, 0x9d, 0x3f, 0xb9,
+  0xab, 0x63, 0x32, 0xa7, 0x46, 0x1f, 0xcb, 0x64,
+  0x79, 0xfb, 0xda, 0x6f, 0x98, 0xc3, 0xa7, 0xd9,
+  0xb7, 0x86, 0xa7, 0x4f, 0xff, 0x56, 0xf4, 0xa7,
+  0xad, 0xa1, 0xbf, 0x2d, 0xe6, 0x1d, 0x25, 0xa0,
+  0xff, 0x42, 0x4f, 0x1e, 0x47, 0xb5, 0x88, 0xef,
+  0x0a, 0xb9, 0xdb, 0x70, 0x9d, 0x3e, 0x07, 0x7f,
+  0x1b, 0xce, 0x85, 0x3c, 0x4d, 0x46, 0xe7, 0x95,
+  0x94, 0xb4, 0x74, 0x2a, 0xa5, 0xf7, 0xc7, 0x43,
+  0x57, 0x9b, 0x91, 0x4f, 0x03, 0xa9, 0xa9, 0xd3,
+  0x04, 0x27, 0x45, 0x4d, 0xc0, 0x48, 0xa7, 0xea,
+  0xfa, 0xdd, 0x96, 0x29, 0xc6, 0x86, 0x70, 0x42,
+  0x12, 0xa7, 0x9f, 0x7c, 0x42, 0x9c, 0x5e, 0x4f,
+  0xb3, 0x6f, 0x02, 0xa7, 0x4b, 0x84, 0xf5, 0xfe,
+  0x5f, 0x3f, 0x7e, 0x9a, 0xb5, 0x97, 0x3a, 0x7f,
+  0xfb, 0xf7, 0x6b, 0x07, 0x39, 0x8b, 0x6f, 0x6c,
+  0x74, 0xfa, 0x8d, 0xdf, 0xb2, 0x93, 0xa7, 0xde,
+  0xaa, 0xd0, 0xc3, 0xe5, 0xfb, 0x3e, 0x5e, 0x10,
+  0x6a, 0x7c, 0xbf, 0x66, 0xe7, 0x9f, 0x2f, 0xd9,
+  0xed, 0x5f, 0x95, 0x3e, 0x5f, 0xb1, 0xb1, 0xe8,
+  0xfc, 0x8a, 0x7c, 0xb9, 0x5c, 0xf9, 0xf2, 0xfd,
+  0x83, 0xe5, 0xfb, 0x37, 0x5c, 0xf9, 0x7e, 0xb0,
+  0xb7, 0x93, 0xfe, 0x7f, 0x5a, 0xa4, 0xcf, 0x66,
+  0xe7, 0x80, 0x7c, 0xbf, 0x60, 0xf9, 0x7e, 0xcc,
+  0x05, 0x3e, 0x5f, 0xb3, 0xfd, 0x80, 0xe1, 0xc6,
+  0xd9, 0xb1, 0xf2, 0xfd, 0x9f, 0xb2, 0xde, 0xae,
+  0xb4, 0x1f, 0x2f, 0xd8, 0x02, 0x28, 0xfe, 0x45,
+  0x54, 0x59, 0xe1, 0xa1, 0x6e, 0x7c, 0xbf, 0x60,
+  0xf9, 0x7e, 0xe1, 0xae, 0x98, 0x21, 0x3e, 0x5f,
+  0xb0, 0xf5, 0x62, 0x3b, 0x1a, 0xe4, 0x21, 0x29,
+  0x84, 0xe8, 0x94, 0xb0, 0xc6, 0xb0, 0xba, 0xba,
+  0xf0, 0x49, 0xa7, 0xb1, 0xeb, 0xa4, 0xb9, 0x7e,
+  0xdc, 0x88, 0xf9, 0xff, 0x62, 0x6d, 0x82, 0x1e,
+  0xb3, 0x47, 0x4c, 0xfa, 0x0a, 0x8a, 0x11, 0x2d,
+  0x4a, 0x17, 0xcf, 0x60, 0x57, 0x25, 0x7a, 0x71,
+  0x8e, 0x7f, 0xfe, 0xa5, 0xe2, 0xad, 0xb9, 0xa5,
+  0xda, 0xca, 0xce, 0x68, 0xe8, 0x55, 0xdc, 0x3c,
+  0x26, 0xf1, 0x7f, 0x4e, 0x72, 0x6a, 0x59, 0x3f,
+  0xed, 0x2b, 0x4f, 0xd6, 0xd6, 0xd5, 0x0e, 0x9f,
+  0xbf, 0xda, 0x6d, 0xcf, 0x3a, 0x70, 0x42, 0x12,
+  0xa7, 0x6f, 0x50, 0x14, 0xe2, 0xf2, 0x7f, 0xdf,
+  0xe7, 0xef, 0x1c, 0x6d, 0xc2, 0x74, 0xff, 0x7f,
+  0x81, 0xa1, 0xea, 0x0a, 0x4e, 0x8d, 0x93, 0x31,
+  0x62, 0x08, 0x12, 0xbe, 0x59, 0x73, 0xf9, 0xff,
+  0x7f, 0xfe, 0xd5, 0xbb, 0xae, 0xe2, 0xdc, 0xe9,
+  0xc1, 0x08, 0x4b, 0x10, 0x82, 0x7c, 0x29, 0xdc,
+  0x85, 0x88, 0x40, 0xe3, 0x55, 0x38, 0x21, 0x09,
+  0x62, 0x0f, 0x41, 0x62, 0x0f, 0x38, 0xd5, 0x4c,
+  0xac, 0xc4, 0x49, 0xa3, 0x5c, 0xfa, 0xeb, 0x75,
+  0x61, 0xd3, 0xdf, 0xf2, 0xe9, 0x3a, 0x76, 0xf5,
+  0x01, 0xd1, 0x41, 0xe0, 0x30, 0x8e, 0x7c, 0x8b,
+  0x65, 0x61, 0x53, 0xef, 0xf7, 0xff, 0x85, 0x4d,
+  0x88, 0x54, 0xc1, 0x09, 0x51, 0x87, 0xeb, 0x52,
+  0x5b, 0x93, 0x04, 0x52, 0x7f, 0x7f, 0x7a, 0x82,
+  0xd8, 0xde, 0x53, 0x8d, 0xdc, 0x2a, 0x70, 0x1e,
+  0x66, 0xe8, 0x69, 0xcf, 0xfe, 0xb2, 0x82, 0xb9,
+  0x9b, 0x77, 0xfb, 0x49, 0xd3, 0xfa, 0xbb, 0xd9,
+  0x50, 0xf5, 0x27, 0x42, 0xab, 0xb1, 0xc4, 0xcf,
+  0x46, 0x0a, 0x31, 0xd6, 0x71, 0xa5, 0x52, 0xa7,
+  0x04, 0x21, 0x2a, 0x7c, 0xf0, 0x77, 0xf6, 0x29,
+  0xc5, 0xe4, 0xff, 0xf7, 0xe9, 0xd1, 0x48, 0x17,
+  0xe9, 0xd4, 0x7f, 0x8e, 0x9f, 0xfe, 0xc5, 0x76,
+  0xdf, 0x5d, 0x53, 0x34, 0xf8, 0x4e, 0x9e, 0x6f,
+  0xb0, 0x1b, 0x1d, 0x0f, 0x3f, 0x7e, 0x50, 0x9f,
+  0xfc, 0xfc, 0x10, 0x33, 0xd5, 0xdf, 0x55, 0xc3,
+  0xa7, 0xbd, 0xb6, 0x30, 0xe8, 0x54, 0xe3, 0x9e,
+  0x6f, 0xd0, 0xca, 0xf9, 0x0e, 0xa9, 0x53, 0xf6,
+  0xee, 0xbe, 0xfd, 0x2f, 0x3a, 0x7f, 0xdc, 0x3b,
+  0x9e, 0xb6, 0x75, 0x20, 0x3a, 0x7f, 0xd5, 0xaa,
+  0x8d, 0xd5, 0xdb, 0x78, 0xe9, 0xff, 0x7f, 0x9a,
+  0xb7, 0x08, 0xfb, 0x63, 0xa3, 0x11, 0xde, 0x86,
+  0x7e, 0x40, 0x61, 0xf4, 0xf3, 0xf7, 0xe3, 0x47,
+  0x4f, 0x87, 0x6c, 0xcf, 0x9d, 0x3f, 0xf6, 0xef,
+  0xd9, 0x65, 0x6d, 0x5b, 0x2d, 0x27, 0x47, 0x1f,
+  0x85, 0x49, 0xa7, 0xff, 0xb2, 0xf5, 0xc6, 0xac,
+  0xad, 0xb2, 0xd6, 0x53, 0xa7, 0xf5, 0xdb, 0xab,
+  0x5f, 0x6e, 0x94, 0x6a, 0x74, 0x6c, 0x8b, 0x4f,
+  0x90, 0xdd, 0x42, 0x7f, 0xfb, 0xd5, 0xcd, 0xaf,
+  0x5f, 0x69, 0xb7, 0x7f, 0xc7, 0x4f, 0xff, 0xef,
+  0xdf, 0x2d, 0xe5, 0xbf, 0x80, 0xaf, 0x70, 0x42,
+  0x12, 0xa7, 0xb6, 0xcc, 0xd2, 0x54, 0xe7, 0xff,
+  0x53, 0x44, 0x33, 0x38, 0x21, 0x09, 0x53, 0xb3,
+  0xe8, 0x53, 0x8b, 0xc9, 0xff, 0x65, 0x19, 0xb7,
+  0x3f, 0xeb, 0x41, 0xd0, 0x03, 0xe8, 0xf9, 0x4c,
+  0xfe, 0x7f, 0xf2, 0xf7, 0xd6, 0x83, 0xa1, 0x53,
+  0x89, 0xa1, 0x86, 0x92, 0x31, 0x85, 0x77, 0x11,
+  0x4f, 0x7a, 0xfe, 0x53, 0xa7, 0xf6, 0xb8, 0x20,
+  0x07, 0xbe, 0x74, 0xff, 0xf9, 0x5f, 0xed, 0xad,
+  0xbe, 0xb8, 0x29, 0xdc, 0x86, 0x88, 0x32, 0x2c,
+  0x89, 0x4b, 0x99, 0xcf, 0xaa, 0x3e, 0x0e, 0xec,
+  0xe9, 0xfd, 0xb9, 0x95, 0xdc, 0xc1, 0x53, 0xa1,
+  0xe9, 0x9c, 0xfa, 0x16, 0xb5, 0x23, 0xb9, 0x5c,
+  0xff, 0xf2, 0xfe, 0x8d, 0x0d, 0x7b, 0xf9, 0xb6,
+  0x7f, 0x49, 0xd3, 0x94, 0x5a, 0x3a, 0x15, 0x77,
+  0x33, 0x63, 0xbc, 0x8d, 0x21, 0x0c, 0x7d, 0x1e,
+  0xe7, 0x47, 0x11, 0xaa, 0x1e, 0xe2, 0xb4, 0xff,
+  0xf2, 0x2d, 0x6a, 0xac, 0xcb, 0xfa, 0xb6, 0xe3,
+  0xa7, 0xf7, 0xfe, 0xaf, 0x62, 0xf8, 0xe9, 0xfd,
+  0x7f, 0x36, 0xf5, 0xde, 0xa5, 0x49, 0x87, 0x4f,
+  0xd9, 0xfd, 0x22, 0xae, 0xf1, 0xe2, 0xef, 0x35,
+  0x8c, 0x4c, 0x2f, 0xc9, 0xb5, 0x77, 0x9e, 0x1d,
+  0x69, 0x79, 0xd3, 0xfb, 0xef, 0xfe, 0x31, 0x50,
+  0xe9, 0xcc, 0xdb, 0x0e, 0x85, 0x3f, 0x0c, 0x23,
+  0xe3, 0x19, 0xd7, 0xf5, 0x07, 0x4f, 0xfb, 0x5b,
+  0xd7, 0x78, 0x81, 0x9e, 0xa9, 0xd3, 0xff, 0x2f,
+  0xfa, 0xca, 0x07, 0x0d, 0x6a, 0x54, 0x6c, 0x88,
+  0x46, 0x21, 0x4f, 0xad, 0xef, 0x53, 0x53, 0xa0,
+  0xa9, 0xfa, 0xbb, 0xd4, 0x55, 0x85, 0x41, 0x50,
+  0x54, 0x15, 0x05, 0x43, 0xcf, 0x7f, 0xc1, 0x40,
+  0x2d, 0xd4, 0x2b, 0x70, 0x29, 0xbc, 0x2a, 0x6b,
+  0x61, 0x53, 0xf7, 0x75, 0xda, 0x56, 0x15, 0xa0,
+  0xb5, 0x93, 0x76, 0x54, 0x15, 0x05, 0x43, 0xcb,
+  0x4f, 0x05, 0x41, 0x50, 0x54, 0x15, 0x05, 0x41,
+  0x50, 0x54, 0x50, 0x6f, 0x36, 0x0a, 0xf0, 0x50,
+  0x02, 0xaa, 0x14, 0xd8, 0x2a, 0x0a, 0x82, 0xa1,
+  0xe5, 0xa5, 0x42, 0xa0, 0xa8, 0x2a, 0x0a, 0x82,
+  0xa1, 0xe6, 0xa0, 0x01, 0x57, 0x0a, 0x6f, 0x0a,
+  0x82, 0xa0, 0xa8, 0x2a, 0x0a, 0x8a, 0x0d, 0x46,
+  0x90, 0xa1, 0x0a, 0xb0, 0x54, 0xb4, 0x95, 0x05,
+  0x41, 0x50, 0x54, 0x15, 0x1b, 0x1a, 0x8a, 0x42,
+  0x80, 0x15, 0xa8, 0x54, 0x15, 0x05, 0x41, 0x53,
+  0xeb, 0x28, 0x2b, 0x85, 0x41, 0x50, 0xf3, 0xce,
+  0x40, 0xab, 0x05, 0x70, 0x50, 0x09, 0xa4, 0x85,
+  0x41, 0x50, 0x54, 0x15, 0x05, 0x43, 0xcd, 0x45,
+  0x21, 0x5e, 0x0a, 0x6c, 0x15, 0x05, 0x41, 0x50,
+  0x54, 0x15, 0x0f, 0x35, 0x1b, 0x05, 0x58, 0x2b,
+  0xe1, 0x52, 0xb1, 0x50, 0x54, 0x15, 0x27, 0x95,
+  0x05, 0x52, 0x58, 0x41, 0x50, 0x54, 0x15, 0x05,
+  0x45, 0x07, 0xcc, 0xf0, 0xad, 0x23, 0x48, 0x34,
+  0xd0, 0x50, 0x02, 0xae, 0x15, 0x2c, 0x2a, 0x0a,
+  0x82, 0xa4, 0xf2, 0xa0, 0xaa, 0x4b, 0x08, 0x2a,
+  0x0a, 0x85, 0x3d, 0x27, 0x85, 0x78, 0x68, 0x46,
+  0x98, 0x15, 0x05, 0x41, 0x50, 0x54, 0x15, 0x05,
+  0x42, 0x9b, 0x2a, 0x42, 0x84, 0x29, 0x81, 0x5f,
+  0x0a, 0x82, 0xa0, 0xa8, 0x2a, 0x04, 0xbe, 0xa8,
+  0x55, 0xc2, 0xa0, 0xa8, 0x2a, 0x0a, 0x86, 0x17,
+  0xdf, 0x0a, 0xb8, 0x54, 0x98, 0x54, 0x15, 0x05,
+  0x40, 0x0b, 0x4d, 0x42, 0xa0, 0xa8, 0x2a, 0x0a,
+  0x82, 0xa1, 0x4d, 0x43, 0x41, 0x56, 0x0a, 0xd4,
+  0x2a, 0x15, 0x7e, 0xb6, 0x87, 0x27, 0x9e, 0xec,
+  0x53, 0x8b, 0x88, 0xdb, 0x4a, 0x47, 0x99, 0xb7,
+  0x67, 0xad, 0x1d, 0x0c, 0x23, 0x18, 0x8f, 0x63,
+  0x7e, 0x66, 0x01, 0xe7, 0xdd, 0xaa, 0xcd, 0x76,
+  0x1d, 0x5e, 0x5b, 0x32, 0x85, 0x2b, 0x70, 0xb7,
+  0x79, 0x23, 0x7a, 0x4c, 0xf9, 0xff, 0x5c, 0xa9,
+  0x4e, 0x4d, 0x5e, 0x77, 0x95, 0x85, 0x4f, 0x79,
+  0x38, 0x4e, 0x9d, 0xed, 0xb0, 0xe9, 0xcb, 0xbd,
+  0xd4, 0xa2, 0x3c, 0x4e, 0x6c, 0x37, 0x71, 0xf9,
+  0xfd, 0x6f, 0x07, 0x61, 0x5a, 0x0e, 0x8a, 0x51,
+  0x08, 0xd2, 0x84, 0xc0, 0x53, 0xa7, 0xe1, 0xef,
+  0xef, 0x50, 0x1d, 0x37, 0x09, 0xd2, 0xf1, 0xc8,
+  0x5a, 0x49, 0x0e, 0x93, 0x0e, 0x9d, 0x9b, 0x8e,
+  0xf2, 0x24, 0xc4, 0x56, 0xc8, 0x3c, 0x3d, 0xbc,
+  0x3e, 0x7f, 0xfd, 0xaa, 0xe8, 0xe1, 0x1e, 0x02,
+  0xb8, 0x21, 0x09, 0xd0, 0xf6, 0x6c, 0xde, 0xd0,
+  0xa0, 0x42, 0xcf, 0x42, 0x85, 0xa2, 0x4e, 0xa5,
+  0x4f, 0xfe, 0x17, 0x17, 0x5e, 0x9f, 0xcb, 0xfb,
+  0xf7, 0xf5, 0xc3, 0xa7, 0xe7, 0xff, 0xcf, 0xb6,
+  0x1d, 0x3e, 0xa3, 0xc2, 0xaf, 0x3a, 0x04, 0xf5,
+  0x3e, 0x5b, 0x3f, 0xeb, 0x28, 0x83, 0xf8, 0x1e,
+  0x01, 0xd3, 0xb3, 0x1a, 0x3a, 0x59, 0x63, 0xd7,
+  0x01, 0xe4, 0xf3, 0x17, 0x28, 0x3a, 0x7d, 0x8d,
+  0xbe, 0xb4, 0x9d, 0x1e, 0x3c, 0xaa, 0x90, 0xcf,
+  0x2f, 0xee, 0x87, 0x49, 0x71, 0x32, 0xbf, 0xbc,
+  0x5d, 0xc7, 0x70, 0x8a, 0x7b, 0x5e, 0x17, 0x9d,
+  0x3c, 0xba, 0xb7, 0x75, 0x2a, 0x7c, 0xf7, 0x04,
+  0x21, 0x3a, 0x3e, 0x79, 0xfa, 0x93, 0xc6, 0xc8,
+  0x93, 0xc7, 0x08, 0x62, 0xaa, 0xc0, 0x47, 0x63,
+  0xac, 0x36, 0x27, 0xe1, 0xd4, 0x19, 0xf4, 0x3a,
+  0x7f, 0xa8, 0xfe, 0x3e, 0xd8, 0x0a, 0x9d, 0x3d,
+  0xb6, 0xca, 0xd8, 0xe9, 0xff, 0xf2, 0xd9, 0x58,
+  0x8b, 0x7c, 0x14, 0xee, 0x43, 0x45, 0xf1, 0x3f,
+  0x83, 0xd7, 0xaa, 0xe5, 0x07, 0x4f, 0xff, 0xd9,
+  0x7d, 0xef, 0x56, 0xde, 0xf8, 0x07, 0xca, 0xcc,
+  0x2a, 0x6b, 0xe1, 0xd3, 0xe1, 0xf5, 0x1c, 0xc3,
+  0x4c, 0x27, 0x3d, 0x7d, 0x57, 0x8d, 0x30, 0x9c,
+  0xc0, 0x53, 0x50, 0x27, 0x3f, 0xbf, 0xda, 0x6e,
+  0xa2, 0x03, 0x50, 0x27, 0x3f, 0xab, 0x96, 0xf5,
+  0x75, 0xa0, 0xd3, 0x09, 0xcd, 0x9b, 0x1a, 0x61,
+  0x39, 0x82, 0x13, 0xcc, 0x27, 0x18, 0x9a, 0x65,
+  0x26, 0x9e, 0x2e, 0x61, 0x15, 0x50, 0x1b, 0x21,
+  0x04, 0x8e, 0x57, 0x2c, 0xc2, 0x67, 0x1f, 0x3c,
+  0xbd, 0x4a, 0x7e, 0xe1, 0x8f, 0x22, 0x2a, 0xaa,
+  0x16, 0xf2, 0x95, 0x21, 0x55, 0xce, 0x6c, 0x72,
+  0x84, 0xb6, 0x5b, 0xbc, 0xab, 0x79, 0xf6, 0xd8,
+  0x3e, 0xd2, 0x74, 0xfb, 0xf9, 0xbf, 0x1a, 0x3a,
+  0x7f, 0xad, 0xcc, 0xb7, 0x96, 0x97, 0x9d, 0x3f,
+  0x6f, 0xfb, 0xf7, 0x3a, 0x83, 0xa3, 0xc7, 0xd8,
+  0x03, 0x98, 0xfa, 0x2d, 0xef, 0x09, 0x58, 0x55,
+  0xd2, 0x2c, 0x97, 0x91, 0xe5, 0x2e, 0x87, 0x04,
+  0xff, 0xe6, 0x5e, 0xbe, 0xfd, 0x2f, 0xbf, 0xab,
+  0xe3, 0xa7, 0xff, 0xf7, 0xf2, 0x9c, 0xaf, 0x7e,
+  0xde, 0x5b, 0xdb, 0x5e, 0x61, 0xd3, 0xf7, 0xf5,
+  0x67, 0xac, 0xa7, 0x4f, 0xff, 0xbb, 0xf7, 0xee,
+  0xb7, 0xd6, 0xf5, 0x0e, 0x58, 0xe9, 0xc3, 0x5a,
+  0x9e, 0x20, 0x39, 0xff, 0xed, 0xe2, 0xb6, 0x5d,
+  0x18, 0x29, 0xdc, 0x86, 0x88, 0x0d, 0xc6, 0xa2,
+  0x00, 0x8e, 0x5b, 0xbd, 0xc6, 0x26, 0x6d, 0xe8,
+  0xc4, 0xe7, 0xff, 0xf7, 0x3f, 0x2b, 0xe1, 0x1f,
+  0x33, 0x7d, 0xed, 0x81, 0xb9, 0xd3, 0xff, 0xfd,
+  0xcf, 0xcf, 0xb4, 0xfc, 0xa5, 0xfb, 0xd4, 0x0e,
+  0x08, 0x42, 0x54, 0x59, 0x19, 0x7f, 0x61, 0x9f,
+  0xcb, 0x82, 0x9d, 0xc8, 0x68, 0x82, 0x67, 0xf9,
+  0x6f, 0x82, 0x9d, 0xc8, 0x68, 0xbe, 0x67, 0xde,
+  0x6d, 0xfc, 0xae, 0xc7, 0xf4, 0x87, 0x53, 0xfe,
+  0xa3, 0xa9, 0xdc, 0xcb, 0xff, 0x9b, 0x1d, 0x38,
+  0x21, 0x09, 0x53, 0xf5, 0xed, 0x89, 0xc2, 0x53,
+  0x8b, 0xc8, 0xa1, 0x13, 0x3f, 0x60, 0x9f, 0xfa,
+  0x86, 0x2d, 0x35, 0xfe, 0x51, 0xbd, 0xe7, 0x4f,
+  0xff, 0x6f, 0xa7, 0xfa, 0x12, 0xde, 0x00, 0x14,
+  0x5e, 0x74, 0xe0, 0x84, 0x25, 0x4f, 0xed, 0xe0,
+  0x5f, 0xe5, 0x37, 0x29, 0xc5, 0xe4, 0xff, 0xfc,
+  0xdd, 0xe8, 0x4b, 0x7b, 0x6d, 0xb0, 0x3a, 0x2f,
+  0x5c, 0xa0, 0xe9, 0x75, 0x91, 0x57, 0xaa, 0x24,
+  0x3d, 0x54, 0x5f, 0xa1, 0xb4, 0x24, 0x8c, 0x49,
+  0xbc, 0x63, 0x73, 0xeb, 0x65, 0xda, 0x79, 0xd3,
+  0xfe, 0xcb, 0xa8, 0xd6, 0xcb, 0xfb, 0x9e, 0x20,
+  0x89, 0xfc, 0xb8, 0x29, 0xdc, 0x86, 0x88, 0x21,
+  0xc7, 0x93, 0x3f, 0x75, 0x84, 0x7c, 0x13, 0xa7,
+  0xed, 0xde, 0xc1, 0xef, 0xbc, 0xe8, 0xf9, 0xee,
+  0xea, 0x57, 0x16, 0x4c, 0xf0, 0x0e, 0x3f, 0x85,
+  0x44, 0xff, 0x2f, 0xef, 0xbf, 0x2d, 0xd4, 0x9d,
+  0x3f, 0xfd, 0xc1, 0xbe, 0x59, 0x7d, 0x7f, 0xe5,
+  0xbc, 0x74, 0x3d, 0x11, 0x1f, 0x3a, 0x9f, 0xd7,
+  0xde, 0xca, 0x87, 0xa9, 0x3a, 0x7b, 0xcd, 0x78,
+  0x27, 0x4f, 0xff, 0xb5, 0xa3, 0xeb, 0x96, 0x72,
+  0xdf, 0x2d, 0xa8, 0x9d, 0x3e, 0xcb, 0xd7, 0x7d,
+  0x76, 0x3f, 0x9d, 0xe4, 0x73, 0xf2, 0x5b, 0xdb,
+  0x9e, 0xd2, 0x74, 0xfc, 0xc5, 0xdd, 0xdb, 0x28,
+  0x3a, 0x7f, 0xff, 0xfb, 0xd7, 0xe6, 0x77, 0xc0,
+  0xff, 0x57, 0x56, 0x5b, 0xcb, 0x7b, 0x6b, 0xcc,
+  0x3a, 0x36, 0x47, 0x1f, 0x8c, 0xb8, 0xc6, 0x70,
+  0xef, 0xa9, 0xd3, 0xfe, 0xef, 0xa6, 0x0a, 0x77,
+  0x21, 0xa2, 0x11, 0x85, 0x3e, 0x2d, 0x47, 0x67,
+  0xff, 0x2e, 0x53, 0xbe, 0xfe, 0xfe, 0xaf, 0xca,
+  0x9d, 0x3f, 0xfd, 0xdd, 0x46, 0xfc, 0xb7, 0x31,
+  0xc1, 0x08, 0x4e, 0x96, 0x6c, 0x89, 0xe6, 0x93,
+  0x67, 0x04, 0x21, 0x2a, 0x7f, 0xb0, 0x1c, 0x38,
+  0xdb, 0x36, 0x29, 0xc5, 0xe4, 0xc1, 0x09, 0x53,
+  0x82, 0x10, 0x95, 0x3f, 0x75, 0x1b, 0x59, 0x6a,
+  0x53, 0x8b, 0xc8, 0xfa, 0x2d, 0x82, 0x8f, 0xb8,
+  0x65, 0x3e, 0x4f, 0x6d, 0xbd, 0x85, 0x38, 0xd9,
+  0xce, 0x08, 0x42, 0x54, 0xea, 0xa8, 0x94, 0xe2,
+  0xf2, 0x40, 0xf1, 0xff, 0xdd, 0x5a, 0x7e, 0xdb,
+  0xea, 0xfe, 0x43, 0xa7, 0xf6, 0xf1, 0xdb, 0xcd,
+  0x97, 0x63, 0xa7, 0xf5, 0xed, 0x8d, 0xb2, 0xf5,
+  0x3a, 0x05, 0x13, 0x16, 0x2c, 0xf9, 0xc4, 0x2a,
+  0x3b, 0xf2, 0x18, 0x13, 0xa9, 0xdd, 0x73, 0x75,
+  0x3a, 0x7f, 0xf6, 0x6e, 0xfb, 0xe0, 0xc4, 0x5b,
+  0x2b, 0x0e, 0x9f, 0x93, 0xd5, 0xb7, 0x9a, 0x2a,
+  0x7f, 0x7f, 0x29, 0x7d, 0x7d, 0xa4, 0xe9, 0xee,
+  0xe1, 0xd2, 0x74, 0x68, 0x3d, 0x7a, 0x0d, 0xa7,
+  0x97, 0x98, 0xd8, 0xa9, 0xc1, 0x08, 0x4a, 0x9f,
+  0xfe, 0xde, 0xa0, 0xcc, 0xfd, 0xed, 0xe5, 0xfd,
+  0x05, 0x38, 0xbc, 0x96, 0x22, 0x27, 0x98, 0x7d,
+  0x0a, 0x9f, 0x23, 0xca, 0xe9, 0x4a, 0xf4, 0x21,
+  0x6d, 0x0c, 0x39, 0xff, 0xf3, 0x31, 0x17, 0xfd,
+  0x7a, 0xed, 0xaf, 0x0b, 0xce, 0x9f, 0x2d, 0xea,
+  0xdb, 0x0e, 0x85, 0x3f, 0xcb, 0xaa, 0x4f, 0xff,
+  0x79, 0xb6, 0x7f, 0x6f, 0xf0, 0x73, 0xfd, 0xa4,
+  0xe9, 0xff, 0xfe, 0xda, 0xde, 0x0e, 0x37, 0xf9,
+  0x9d, 0x7a, 0xea, 0xfc, 0xa6, 0xe7, 0x46, 0x23,
+  0x03, 0x94, 0xe1, 0x5b, 0x21, 0x5a, 0x13, 0x5f,
+  0x1c, 0xbe, 0xd0, 0xf4, 0xc9, 0x65, 0x1e, 0x8e,
+  0x49, 0xa8, 0x5f, 0x09, 0x1b, 0x21, 0x5f, 0x68,
+  0xc9, 0xc1, 0x09, 0x2f, 0xc3, 0x02, 0xb2, 0xa7,
+  0x6f, 0x28, 0x2b, 0x58, 0x68, 0x86, 0x1c, 0x33,
+  0x9b, 0x2f, 0xce, 0x9f, 0xfe, 0xcf, 0xba, 0xfa,
+  0x7d, 0x4d, 0x6d, 0x80, 0xe3, 0xa5, 0x4b, 0xcf,
+  0xbf, 0x61, 0xd9, 0xfa, 0xcd, 0x7a, 0xde, 0x61,
+  0xd3, 0xfe, 0xfa, 0xde, 0xdc, 0x0e, 0xa6, 0xa7,
+  0x4e, 0x6b, 0x51, 0x3a, 0x7f, 0xdd, 0xe1, 0xca,
+  0x5c, 0x10, 0x84, 0xe8, 0xe3, 0xdb, 0xa8, 0xec,
+  0xff, 0xf7, 0xd5, 0xfa, 0x37, 0xdf, 0xdf, 0xd5,
+  0xf9, 0x53, 0xa3, 0x13, 0x3e, 0x42, 0xfb, 0x42,
+  0x64, 0x04, 0x33, 0xf9, 0x7e, 0xff, 0xe6, 0x00,
+  0xe9, 0xfc, 0xfc, 0x1a, 0xfd, 0x68, 0x3a, 0x7f,
+  0xf9, 0x5b, 0x28, 0xbb, 0x7d, 0xff, 0x94, 0x78,
+  0x4f, 0x77, 0xbc, 0xff, 0xf6, 0x5d, 0x7e, 0x99,
+  0x7b, 0x78, 0x40, 0x87, 0x4f, 0xba, 0xb9, 0xfb,
+  0x9d, 0x3a, 0xfd, 0xbb, 0x3a, 0x7f, 0x5e, 0xde,
+  0x70, 0x3b, 0xc7, 0x45, 0x09, 0x91, 0xec, 0xbf,
+  0xf4, 0xcb, 0x93, 0x6a, 0x3f, 0x3f, 0xb5, 0x02,
+  0xdb, 0xdc, 0xf3, 0xa7, 0xff, 0xef, 0xe5, 0x75,
+  0xd1, 0x96, 0xef, 0xe3, 0x4f, 0x5a, 0x4e, 0x9f,
+  0xf6, 0x57, 0x5c, 0x14, 0xee, 0x43, 0x44, 0x0d,
+  0x3e, 0xcb, 0xdb, 0x9f, 0xa1, 0x14, 0xbf, 0x5e,
+  0x9f, 0xff, 0xff, 0xb2, 0xf6, 0xef, 0xe9, 0xd1,
+  0x51, 0xee, 0xbb, 0x6c, 0xdb, 0x46, 0x33, 0xbf,
+  0x4b, 0xcf, 0x10, 0x5c, 0xff, 0xbb, 0xb4, 0xa7,
+  0x6d, 0xa3, 0x48, 0x4f, 0x10, 0x5c, 0xff, 0xd6,
+  0xf5, 0xbc, 0xbf, 0xbe, 0x8d, 0x21, 0x3c, 0x41,
+  0x73, 0xf9, 0x7d, 0xfb, 0xe8, 0xd2, 0x13, 0xc4,
+  0x17, 0x3f, 0x33, 0x36, 0xd1, 0xa4, 0x27, 0x88,
+  0x2e, 0x7f, 0xff, 0xbb, 0xff, 0xf3, 0x34, 0x55,
+  0x2d, 0xe1, 0xf6, 0x9a, 0x30, 0x27, 0x88, 0x2e,
+  0x6a, 0x74, 0x6c, 0x9d, 0x0a, 0x28, 0x0a, 0xb7,
+  0x22, 0x7c, 0xfe, 0x2c, 0xaa, 0x5b, 0xf2, 0x8f,
+  0xa7, 0xb8, 0x41, 0xc7, 0x4f, 0xfd, 0x6f, 0x5b,
+  0xcb, 0xfb, 0xe8, 0xd2, 0x13, 0xc4, 0x17, 0x3f,
+  0xcd, 0x55, 0x3d, 0x46, 0x8d, 0x21, 0x3c, 0x41,
+  0x73, 0xeb, 0xd5, 0x59, 0xa1, 0x11, 0x45, 0xbd,
+  0x5a, 0x7f, 0xf6, 0x84, 0xb7, 0x91, 0x6f, 0x5d,
+  0x1a, 0x42, 0x78, 0x82, 0xe7, 0xff, 0xfe, 0xff,
+  0xfc, 0xcd, 0x1a, 0xe6, 0x8a, 0xa5, 0xbc, 0x3e,
+  0xd3, 0x46, 0x04, 0xf1, 0x05, 0xc6, 0x26, 0x4d,
+  0x4a, 0x1f, 0x2e, 0x4f, 0xf5, 0xbc, 0x3e, 0xd3,
+  0x46, 0x04, 0xf1, 0x05, 0xcf, 0xff, 0x77, 0x52,
+  0xfa, 0xdb, 0xdb, 0x6c, 0xa2, 0xa5, 0x4f, 0xfb,
+  0x1e, 0xfd, 0x6a, 0x3f, 0xa3, 0x70, 0xf1, 0x05,
+  0xc2, 0x23, 0xa0, 0x52, 0x2a, 0xa1, 0x3f, 0xe4,
+  0xf0, 0xdf, 0x81, 0x5d, 0x01, 0x3c, 0x41, 0x73,
+  0xf5, 0xbd, 0x6b, 0x78, 0x06, 0x80, 0x2e, 0x7d,
+  0x80, 0xd1, 0xa4, 0x27, 0x88, 0x2e, 0x6c, 0xba,
+  0x1f, 0x9d, 0x8e, 0xe2, 0x94, 0x75, 0xd6, 0x17,
+  0xf3, 0xf3, 0x33, 0x6d, 0x1a, 0x42, 0x78, 0x82,
+  0xe7, 0xfc, 0x96, 0xf0, 0xfb, 0x4d, 0x18, 0x13,
+  0xc4, 0x17, 0x36, 0x68, 0xe4, 0x46, 0x54, 0xfe,
+  0x7f, 0x6b, 0xe6, 0x77, 0xe9, 0x79, 0xe2, 0x0b,
+  0x9f, 0xf6, 0x79, 0xb6, 0x7f, 0x36, 0xe7, 0x9e,
+  0x20, 0xb6, 0x1e, 0x14, 0x6c, 0xbb, 0x8e, 0x02,
+  0xcf, 0xc7, 0xcf, 0x58, 0xc6, 0x2f, 0x18, 0xce,
+  0xb0, 0xb5, 0x0b, 0x8c, 0xf8, 0x15, 0x00, 0x14,
+  0xd1, 0x05, 0xb9, 0x10, 0x13, 0xfe, 0xc7, 0xdb,
+  0x9e, 0xde, 0xdf, 0xad, 0x07, 0x4f, 0xe1, 0xfe,
+  0x6d, 0x6d, 0x42, 0x74, 0xfa, 0x9b, 0xf0, 0x80,
+  0xe9, 0xfb, 0x28, 0xeb, 0x2e, 0xec, 0xe8, 0xf2,
+  0x22, 0xf8, 0xd3, 0xe4, 0xf3, 0xb8, 0x68, 0x3a,
+  0x60, 0x29, 0xd3, 0xde, 0x56, 0x61, 0xd0, 0x74,
+  0xfd, 0xda, 0x6e, 0xa2, 0x03, 0xa3, 0x63, 0x6f,
+  0xf0, 0xa9, 0xff, 0xfc, 0xbe, 0xdb, 0xeb, 0xaa,
+  0x5f, 0x13, 0x65, 0x4d, 0xec, 0x3a, 0x60, 0x29,
+  0xd3, 0x2e, 0x93, 0xa7, 0xfb, 0x2f, 0x55, 0x66,
+  0xfc, 0x68, 0xe9, 0xfd, 0x5c, 0xb7, 0xab, 0xad,
+  0x07, 0x4c, 0x10, 0x95, 0x3f, 0xdf, 0xc6, 0xdc,
+  0xfa, 0xfb, 0x63, 0xa1, 0x13, 0xf7, 0xf0, 0xd8,
+  0x8a, 0xb1, 0x5e, 0xc4, 0x40, 0x62, 0x6e, 0xc5,
+  0x7e, 0x2f, 0x53, 0xa0, 0x9a, 0xef, 0x16, 0x9c,
+  0x10, 0x84, 0xa9, 0x30, 0xa7, 0x17, 0x93, 0xee,
+  0x6b, 0xb8, 0x4a, 0x72, 0x36, 0x77, 0xc2, 0xea,
+  0x7f, 0x53, 0x75, 0xcb, 0x65, 0x07, 0x42, 0xb6,
+  0x40, 0xf9, 0x1b, 0x46, 0x94, 0x1a, 0x4c, 0x7d,
+  0x1a, 0xa8, 0xa7, 0x5a, 0x1b, 0x1d, 0x49, 0x1e,
+  0xfa, 0x35, 0x61, 0xa3, 0xac, 0xaf, 0xf6, 0xc9,
+  0x73, 0xd8, 0x8b, 0x73, 0xa7, 0xb1, 0x99, 0x73,
+  0xa7, 0xba, 0x8d, 0xef, 0x3a, 0x14, 0xf8, 0xe9,
+  0x1f, 0x6f, 0x20, 0x9f, 0xbf, 0xae, 0xcc, 0xe7,
+  0x9d, 0x3f, 0xfd, 0x4b, 0xfe, 0xba, 0x19, 0xf5,
+  0xd3, 0x7f, 0x50, 0x74, 0xfe, 0xad, 0xdb, 0x67,
+  0xf3, 0x63, 0xa1, 0x51, 0x75, 0xe2, 0xfe, 0x56,
+  0x9d, 0xda, 0x37, 0x9d, 0x3f, 0xfd, 0xf7, 0xe8,
+  0xcd, 0xbd, 0x5a, 0x6f, 0xaf, 0x54, 0xe8, 0xd0,
+  0x7e, 0x98, 0x3f, 0x3f, 0x50, 0xd3, 0xdb, 0x83,
+  0x41, 0xd3, 0x3e, 0x83, 0xa7, 0xd6, 0xcf, 0x3e,
+  0xa7, 0x4f, 0xff, 0x59, 0x77, 0xba, 0xff, 0xe0,
+  0x56, 0xaa, 0x02, 0xa7, 0xf0, 0x30, 0x53, 0xb9,
+  0x0f, 0x10, 0x24, 0x3d, 0x16, 0x7b, 0x13, 0x8a,
+  0x8c, 0xcd, 0xef, 0x3a, 0x7a, 0xf4, 0x77, 0xce,
+  0x9e, 0xa6, 0xbd, 0x73, 0xa2, 0x83, 0xdd, 0xc1,
+  0x9b, 0x11, 0x4f, 0xef, 0xf0, 0x6b, 0x55, 0x01,
+  0xd3, 0x82, 0x10, 0x9f, 0x0f, 0xa9, 0xdd, 0xfd,
+  0x8b, 0x87, 0xd1, 0xc6, 0xa6, 0x36, 0x44, 0xa8,
+  0x16, 0xe7, 0xff, 0xd9, 0xff, 0x69, 0x75, 0x6f,
+  0x6d, 0x79, 0xef, 0x53, 0xa2, 0x83, 0xfc, 0xd2,
+  0x49, 0x1b, 0xa9, 0x57, 0x83, 0xcd, 0x32, 0x19,
+  0x5e, 0x84, 0x6f, 0x46, 0x81, 0x3e, 0xf5, 0xd6,
+  0xf5, 0x2a, 0x79, 0x16, 0xf5, 0x2a, 0x60, 0x84,
+  0xa8, 0x79, 0xee, 0xe1, 0x38, 0x48, 0x26, 0xc0,
+  0x94, 0xe3, 0x5d, 0x3f, 0xfe, 0xcb, 0xaa, 0x66,
+  0x7e, 0xf6, 0xf2, 0xfe, 0x83, 0xa0, 0x07, 0xf0,
+  0x12, 0x59, 0xff, 0xfc, 0xad, 0xbd, 0xf0, 0x68,
+  0xbd, 0x71, 0x2d, 0xdf, 0xbd, 0x4e, 0x9f, 0xcd,
+  0x52, 0xfb, 0x6a, 0xa2, 0x74, 0xe7, 0xf0, 0x9d,
+  0x3e, 0x7e, 0x5f, 0x36, 0x2a, 0x5e, 0x68, 0xf0,
+  0x6e, 0x35, 0x30, 0x14, 0xe9, 0x80, 0xa7, 0x4f,
+  0xdf, 0xd5, 0xf9, 0xf7, 0x78, 0xd5, 0x00, 0x56,
+  0x7f, 0xeb, 0xdb, 0x19, 0xbd, 0x41, 0x94, 0xdc,
+  0xe9, 0xfd, 0x4a, 0x78, 0x77, 0xae, 0xc7, 0x4f,
+  0x01, 0x9c, 0xfa, 0x9f, 0xdd, 0xd1, 0xa7, 0x6e,
+  0x65, 0x27, 0x42, 0x9e, 0xc7, 0x1c, 0xcf, 0x57,
+  0x5a, 0x6e, 0x74, 0xe0, 0x84, 0x25, 0x4f, 0xb3,
+  0x4f, 0xf5, 0xa9, 0x4e, 0x2f, 0x27, 0xd8, 0xe0,
+  0x84, 0x27, 0x42, 0x9f, 0x05, 0xce, 0x67, 0x83,
+  0xdf, 0x79, 0xd3, 0x25, 0x8e, 0x9c, 0x10, 0x84,
+  0xa9, 0xfb, 0xdd, 0xa6, 0xde, 0xb9, 0x4e, 0x2f,
+  0x27, 0xd8, 0x0c, 0xc6, 0x8e, 0x95, 0x74, 0x22,
+  0x54, 0x4c, 0x7e, 0x7d, 0x3d, 0xef, 0xea, 0xfd,
+  0x91, 0xdb, 0x90, 0xb6, 0x85, 0x5c, 0x76, 0x79,
+  0x16, 0x32, 0x69, 0x76, 0x15, 0x3b, 0x46, 0x31,
+  0xc4, 0x15, 0x85, 0x05, 0xe3, 0x0e, 0x9f, 0x95,
+  0x82, 0x3d, 0x73, 0xa7, 0xff, 0xbc, 0xca, 0x5f,
+  0x5d, 0x19, 0xff, 0xe7, 0x80, 0x74, 0x58, 0xff,
+  0x6e, 0x55, 0x27, 0x37, 0x48, 0x43, 0x36, 0x2c,
+  0xae, 0xda, 0x23, 0x23, 0x7c, 0xa4, 0xdd, 0xa5,
+  0x80, 0xe5, 0x6e, 0x95, 0xa6, 0x37, 0x14, 0x8e,
+  0xca, 0x99, 0x54, 0xfe, 0x84, 0xeb, 0x53, 0xce,
+  0x43, 0x3a, 0x6a, 0xc9, 0x41, 0x76, 0x9f, 0x0a,
+  0xea, 0x79, 0x68, 0x25, 0x9c, 0xfe, 0x75, 0x82,
+  0xb5, 0x92, 0xf5, 0xeb, 0x39, 0xfd, 0x63, 0x35,
+  0x6d, 0x0e, 0xc0, 0xc2, 0x8b, 0x72, 0x58, 0x9e,
+  0xf9, 0xdd, 0x96, 0xf8, 0xc3, 0x61, 0xd0, 0x88,
+  0xd3, 0x7e, 0x21, 0xae, 0x27, 0xf3, 0xb0, 0x53,
+  0xb9, 0x0d, 0x17, 0x1c, 0xfe, 0x76, 0x0a, 0x77,
+  0x21, 0xa2, 0xeb, 0x9f, 0xf9, 0xdc, 0xf7, 0x60,
+  0xa7, 0x72, 0x1a, 0x25, 0x18, 0x58, 0x46, 0x14,
+  0x3c, 0xa3, 0x63, 0xbd, 0x27, 0x68, 0x77, 0xe8,
+  0x78, 0x6e, 0xd0, 0x3b, 0x11, 0x24, 0xb5, 0x38,
+  0xb9, 0xdb, 0x79, 0xdc, 0xff, 0xe7, 0x33, 0x9e,
+  0xec, 0x14, 0xee, 0x43, 0x44, 0xb5, 0x3e, 0x14,
+  0xee, 0x43, 0x44, 0x6f, 0x3f, 0xee, 0x7b, 0xb0,
+  0x53, 0xb9, 0x0d, 0x12, 0xfc, 0x9d, 0x87, 0xec,
+  0xc3, 0x09, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
+  0x57, 0x3f, 0xda, 0x73, 0xf9, 0x4d, 0xf9, 0x87,
+  0x4d, 0xb7, 0x8e, 0x9f, 0xb0, 0x53, 0xb9, 0x0d,
+  0x12, 0x04, 0x68, 0x3c, 0xc7, 0x0b, 0xcf, 0xab,
+  0xdf, 0xea, 0x4e, 0x87, 0x9e, 0x5d, 0x24, 0x91,
+  0xa5, 0x1e, 0x9d, 0x0d, 0x19, 0xff, 0xbf, 0x94,
+  0x3b, 0x71, 0x7f, 0xfc, 0xb9, 0xd0, 0xe3, 0xf0,
+  0x12, 0x99, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
+  0x91, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb5,
+  0xe7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x17, 0x24,
+  0xf8, 0x53, 0xb9, 0x0d, 0x17, 0x64, 0xff, 0xb9,
+  0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x51, 0xd2, 0x76,
+  0x1f, 0xb3, 0x0c, 0x27, 0xc2, 0x9d, 0xc8, 0x68,
+  0xa5, 0x67, 0xff, 0xff, 0xac, 0xb4, 0x2d, 0xbc,
+  0xdb, 0xb6, 0xb7, 0x9c, 0x96, 0xf3, 0x56, 0x5a,
+  0x30, 0xe9, 0xf3, 0x99, 0xcf, 0x76, 0x22, 0xc9,
+  0xa3, 0x08, 0xa1, 0x73, 0xbd, 0xf0, 0xc8, 0xa4,
+  0x9f, 0xd1, 0xcf, 0xb0, 0x84, 0x07, 0x75, 0x3b,
+  0xbc, 0x2c, 0x5b, 0x43, 0x66, 0x7f, 0x9e, 0xec,
+  0x14, 0xee, 0x43, 0x44, 0x71, 0x3f, 0xde, 0x76,
+  0x0a, 0x77, 0x21, 0xa2, 0xb5, 0x93, 0xb9, 0x10,
+  0x57, 0x41, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82,
+  0x9d, 0xc8, 0x68, 0x96, 0xe6, 0xca, 0x4e, 0x9f,
+  0xdb, 0x63, 0x18, 0xbe, 0xa9, 0xd1, 0x49, 0xe4,
+  0xf8, 0x5a, 0x75, 0xb6, 0x79, 0xd3, 0x9e, 0xc4,
+  0x3a, 0x7f, 0xfe, 0xb7, 0x52, 0x0d, 0xad, 0xcf,
+  0xca, 0xff, 0x5e, 0xde, 0x74, 0x1a, 0x21, 0xb9,
+  0xff, 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x98,
+  0x27, 0x0e, 0xa0, 0x2a, 0x7f, 0x7f, 0x2f, 0x75,
+  0x1a, 0x9d, 0x27, 0x2a, 0x6c, 0x94, 0x11, 0xec,
+  0x3b, 0x83, 0x68, 0xbe, 0xc1, 0x7b, 0xa3, 0x6f,
+  0x1c, 0x9c, 0xcd, 0x44, 0xa9, 0xff, 0x73, 0xdd,
+  0x82, 0x9d, 0xc8, 0x68, 0x98, 0xe4, 0xef, 0x1f,
+  0x13, 0x07, 0x27, 0xe5, 0xae, 0x8b, 0xe5, 0x8e,
+  0x9f, 0xff, 0xfe, 0x7d, 0x6d, 0x9a, 0x86, 0xb6,
+  0xc4, 0xca, 0xe8, 0xca, 0x5f, 0x5f, 0x7f, 0xc7,
+  0x4f, 0x27, 0x72, 0x1a, 0x2b, 0x19, 0xff, 0x6e,
+  0x65, 0xff, 0x9a, 0xaf, 0xee, 0x74, 0x69, 0x4c,
+  0x6e, 0x92, 0xe1, 0x84, 0x0d, 0xca, 0xe7, 0xff,
+  0x2f, 0xef, 0xa7, 0x55, 0xfe, 0x22, 0x89, 0xd3,
+  0xfe, 0xcd, 0xad, 0x95, 0xa5, 0xeb, 0x63, 0xa7,
+  0xfd, 0x9b, 0x0f, 0xb5, 0xa0, 0x15, 0x79, 0xd3,
+  0xff, 0xff, 0x7f, 0x5a, 0x31, 0x34, 0x7f, 0x56,
+  0xfd, 0x19, 0x4b, 0xf3, 0x5f, 0x82, 0xa7, 0x4f,
+  0xed, 0xd5, 0x43, 0x4f, 0x6e, 0x0d, 0x07, 0x4e,
+  0xb7, 0x9d, 0x89, 0xe6, 0x22, 0x2d, 0x92, 0x7e,
+  0x7f, 0x74, 0x1d, 0xc7, 0xe9, 0xb5, 0x68, 0xe9,
+  0xf7, 0x7e, 0x8d, 0x6a, 0x74, 0x7c, 0xf0, 0x6a,
+  0x31, 0x3c, 0xa3, 0xdf, 0x3a, 0x7a, 0xb5, 0x50,
+  0x1d, 0x16, 0x3c, 0x00, 0x8f, 0xcf, 0x95, 0xe0,
+  0xd5, 0xe7, 0x4e, 0x5f, 0xbc, 0xe8, 0x68, 0xf0,
+  0xee, 0x51, 0x3f, 0x2b, 0x33, 0xfe, 0xd2, 0x74,
+  0xaa, 0x74, 0x78, 0xdf, 0x71, 0x74, 0xc0, 0x52,
+  0xa6, 0x08, 0x4a, 0x8f, 0x1a, 0xb0, 0x8a, 0xcf,
+  0xee, 0x7f, 0xf2, 0xf6, 0xf1, 0x4e, 0x34, 0x33,
+  0xdb, 0x75, 0x35, 0x3a, 0x72, 0xfd, 0xa3, 0xa6,
+  0xfa, 0x9d, 0x0d, 0x1b, 0x11, 0x1c, 0x9e, 0x10,
+  0x63, 0x79, 0xd3, 0xb7, 0x8e, 0x93, 0xa1, 0x51,
+  0x6f, 0x8a, 0x9e, 0x21, 0xb1, 0x1c, 0xd6, 0xb9,
+  0xd3, 0x82, 0x10, 0x95, 0x3f, 0xf6, 0x26, 0xcb,
+  0x46, 0xfc, 0xb7, 0x52, 0x53, 0x8b, 0xc9, 0xef,
+  0x0b, 0x7e, 0xc7, 0x48, 0x4e, 0x9f, 0x33, 0xd7,
+  0x07, 0x1d, 0x14, 0x1e, 0xde, 0xec, 0x97, 0x50,
+  0xf9, 0xfc, 0x9e, 0xaf, 0xf1, 0xb7, 0x1d, 0x36,
+  0x5c, 0xe8, 0xa4, 0xf2, 0x2c, 0x67, 0x3d, 0x7f,
+  0xe3, 0xce, 0x9f, 0xfd, 0xea, 0xdb, 0x36, 0xfe,
+  0x36, 0xfe, 0x54, 0xe8, 0x13, 0xed, 0xb9, 0x0c,
+  0x9c, 0xab, 0x9b, 0x1b, 0x31, 0x63, 0x28, 0xb0,
+  0xb1, 0xb2, 0xd0, 0xf9, 0xe3, 0xbf, 0x99, 0x56,
+  0x16, 0x17, 0x7d, 0xdf, 0x09, 0x09, 0xf0, 0xa7,
+  0x72, 0x1a, 0x2b, 0x79, 0xff, 0x73, 0xdd, 0x82,
+  0x9d, 0xc8, 0x68, 0x9c, 0x24, 0xec, 0x3f, 0x66,
+  0x18, 0x4f, 0x85, 0x3b, 0x90, 0xd1, 0x68, 0xcf,
+  0x63, 0x5e, 0xd2, 0x74, 0x9d, 0x87, 0xa9, 0x63,
+  0x09, 0xe4, 0xee, 0x43, 0x45, 0xb5, 0x3f, 0x59,
+  0x58, 0xbe, 0xd8, 0xe9, 0x9d, 0x82, 0x7b, 0x17,
+  0x2b, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x5c,
+  0xb3, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0xb6,
+  0x15, 0x9c, 0xad, 0x41, 0x43, 0xe3, 0xff, 0xda,
+  0x1b, 0x7a, 0x65, 0x87, 0xfa, 0x76, 0x13, 0x77,
+  0x19, 0x2d, 0x9e, 0xfe, 0xff, 0x52, 0xcb, 0x9d,
+  0xcf, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x2a, 0x79,
+  0xe4, 0xee, 0x43, 0x45, 0x73, 0x3f, 0x9d, 0x82,
+  0x9d, 0xc8, 0x68, 0xb3, 0xa0, 0x4f, 0x9a, 0xc5,
+  0x73, 0xe1, 0x4e, 0xe4, 0x34, 0x48, 0x53, 0xfd,
+  0xea, 0x6b, 0x7f, 0xab, 0x2a, 0x74, 0xcf, 0x76,
+  0x1f, 0x50, 0x0c, 0x27, 0x9b, 0xa5, 0x95, 0x87,
+  0x4f, 0xec, 0xb5, 0x6b, 0x83, 0x41, 0xd2, 0x76,
+  0x26, 0x23, 0xd0, 0x8b, 0xa9, 0x6d, 0xc9, 0xe7,
+  0xff, 0x39, 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a,
+  0x27, 0xc8, 0x45, 0x49, 0x7b, 0xb8, 0xec, 0xac,
+  0x8f, 0x3e, 0x14, 0xee, 0x43, 0x45, 0x65, 0x3f,
+  0xee, 0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x13, 0x74,
+  0xde, 0x76, 0x1f, 0xb3, 0x0c, 0x27, 0xc2, 0x9d,
+  0xc8, 0x68, 0x95, 0xa7, 0xfb, 0x4d, 0xbd, 0xa3,
+  0x54, 0xca, 0x9d, 0x3e, 0x73, 0x39, 0xee, 0xc3,
+  0xed, 0xe3, 0x09, 0xf0, 0xa7, 0x72, 0x1a, 0x25,
+  0xc9, 0xfe, 0xf7, 0x3e, 0xff, 0x56, 0x54, 0xe9,
+  0xe6, 0xde, 0xfa, 0x9d, 0x3e, 0x73, 0x39, 0xee,
+  0xc4, 0x45, 0xd8, 0xc3, 0x8e, 0x27, 0xfe, 0x77,
+  0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x88, 0xee, 0x7f,
+  0xaf, 0x6c, 0x7b, 0xbb, 0xf5, 0x3a, 0x7e, 0x6e,
+  0x7d, 0x53, 0x3e, 0x74, 0xfd, 0xba, 0x7f, 0x2d,
+  0xd7, 0x3a, 0x7c, 0x29, 0xdc, 0x86, 0x8a, 0x86,
+  0x7d, 0x96, 0xbe, 0x50, 0x74, 0xff, 0xff, 0x6b,
+  0xdb, 0xbf, 0x51, 0x6e, 0xf5, 0xd6, 0xde, 0xbd,
+  0x73, 0x63, 0xa4, 0xed, 0xd1, 0x32, 0x46, 0xe1,
+  0x7e, 0x18, 0xdc, 0xc3, 0x70, 0x9e, 0x7c, 0x29,
+  0xdc, 0x86, 0x8a, 0xa2, 0x7f, 0xdc, 0xf7, 0x60,
+  0xa7, 0x72, 0x1a, 0x26, 0xb9, 0x3b, 0x0f, 0xd9,
+  0x86, 0x13, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8a,
+  0xb2, 0x7f, 0xe7, 0x73, 0xdd, 0x82, 0x9d, 0xc8,
+  0x68, 0x91, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0xb4,
+  0xa7, 0xfd, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2,
+  0x7d, 0x93, 0xb0, 0xfd, 0x98, 0x61, 0x3f, 0xf9,
+  0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x42,
+  0x4f, 0xad, 0xea, 0x14, 0x4e, 0x9f, 0x0a, 0x77,
+  0x21, 0xa2, 0x8f, 0x9f, 0xff, 0xb3, 0x6b, 0x2e,
+  0xf7, 0x5f, 0xfc, 0x0a, 0xd5, 0x40, 0x54, 0xf9,
+  0xcc, 0xe7, 0xb9, 0x51, 0x69, 0x84, 0xfb, 0x86,
+  0x10, 0xab, 0xc5, 0x94, 0x43, 0x21, 0xe9, 0x78,
+  0x99, 0xa6, 0x35, 0xc4, 0x86, 0x95, 0x24, 0xed,
+  0x1d, 0xda, 0x18, 0x40, 0x27, 0xbc, 0x60, 0xd3,
+  0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x88, 0x8a, 0x7e,
+  0xc1, 0x4e, 0xe4, 0x34, 0x45, 0x73, 0xfd, 0xbb,
+  0x76, 0x0a, 0x77, 0x21, 0xa2, 0xb8, 0x87, 0x1f,
+  0xd7, 0x1a, 0xcf, 0x65, 0xba, 0xe7, 0x4f, 0xec,
+  0xf0, 0x80, 0x1a, 0xd4, 0xe9, 0x6e, 0x9f, 0x3d,
+  0x3a, 0x90, 0x4f, 0xfd, 0xde, 0x7f, 0xbf, 0x7d,
+  0x6c, 0x38, 0x74, 0xfb, 0x3d, 0xb0, 0xe1, 0xd3,
+  0xaf, 0x5f, 0x58, 0xfa, 0xae, 0x89, 0x3e, 0x14,
+  0xee, 0x43, 0x45, 0x3d, 0x0d, 0xc4, 0x7d, 0xac,
+  0x25, 0xf0, 0xd2, 0x7f, 0xf7, 0x3d, 0xdb, 0x7f,
+  0x83, 0x5a, 0xa8, 0x0e, 0x87, 0x22, 0x07, 0x63,
+  0x79, 0xce, 0xdb, 0x0e, 0x9f, 0x2b, 0xc1, 0xab,
+  0xce, 0x9e, 0x4e, 0xe4, 0x34, 0x56, 0x70, 0xd1,
+  0xe9, 0x89, 0x44, 0xfd, 0x43, 0x17, 0xef, 0xa9,
+  0xd3, 0x96, 0x8f, 0x1d, 0x3e, 0xb8, 0x37, 0xfd,
+  0xe7, 0x4e, 0xd7, 0xaa, 0x74, 0xfb, 0x1a, 0xa3,
+  0x50, 0x1d, 0x27, 0x62, 0x37, 0x04, 0x8a, 0xc5,
+  0xdc, 0x39, 0xf2, 0xad, 0xe3, 0x93, 0xff, 0x3b,
+  0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x8b, 0x3f,
+  0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb2, 0x67, 0xf3,
+  0xb0, 0x53, 0xb9, 0x0d, 0x16, 0xc4, 0xec, 0xae,
+  0x1d, 0x3e, 0x14, 0xee, 0x43, 0x45, 0xb7, 0x27,
+  0x3c, 0xf2, 0xb0, 0x6a, 0x7f, 0xcd, 0xc6, 0xe6,
+  0xeb, 0x5e, 0xd9, 0xf5, 0x01, 0xd3, 0xf2, 0xfd,
+  0xfb, 0x6a, 0xc3, 0xa7, 0xc2, 0x9d, 0xc8, 0x68,
+  0xbc, 0x27, 0xaf, 0xb9, 0x96, 0x3a, 0x7f, 0xe5,
+  0xde, 0xca, 0x5f, 0x7c, 0xfd, 0xea, 0x74, 0xfb,
+  0x3e, 0x06, 0xf5, 0x3a, 0x7c, 0xbb, 0xf5, 0xea,
+  0x9d, 0x3a, 0xea, 0x03, 0xa4, 0xed, 0xd7, 0x93,
+  0x84, 0xa1, 0x37, 0x0b, 0xe9, 0x30, 0xb1, 0x20,
+  0x11, 0xfe, 0x53, 0x72, 0x99, 0xde, 0xca, 0x4e,
+  0x9f, 0x0a, 0x77, 0x21, 0xa2, 0xf4, 0x9f, 0xf7,
+  0xfa, 0xef, 0x5d, 0x37, 0xf5, 0x07, 0x4f, 0xb1,
+  0x96, 0xed, 0x8e, 0x93, 0xb6, 0x45, 0xa6, 0x0e,
+  0x6f, 0x30, 0x6f, 0x41, 0x85, 0x64, 0x52, 0xd1,
+  0x0b, 0x5c, 0x8f, 0xc1, 0x09, 0x3d, 0x1a, 0x58,
+  0xae, 0x31, 0x30, 0x07, 0x7f, 0x84, 0x2e, 0xb1,
+  0xd5, 0x86, 0x33, 0x69, 0xec, 0xb7, 0x5c, 0xe9,
+  0xfd, 0x9e, 0x10, 0x03, 0x5a, 0x9d, 0x2d, 0xd3,
+  0xe7, 0xa7, 0x52, 0x09, 0xf0, 0xa7, 0x72, 0x1a,
+  0x22, 0x39, 0xff, 0xeb, 0x6b, 0x5a, 0xe3, 0x3f,
+  0x8d, 0xb4, 0x2b, 0x75, 0x3a, 0x7f, 0xcf, 0x5a,
+  0x07, 0x2f, 0x7f, 0x5c, 0xe9, 0xff, 0xfe, 0x5b,
+  0x77, 0xae, 0xb6, 0xfe, 0x5e, 0xde, 0xb6, 0x78,
+  0x27, 0x4d, 0x43, 0x0a, 0x98, 0x21, 0x2a, 0x7f,
+  0xe7, 0xb9, 0x2d, 0xe6, 0xac, 0xb4, 0x38, 0x06,
+  0xb4, 0x22, 0xf3, 0xfb, 0x37, 0x7f, 0xcb, 0x75,
+  0xce, 0x9f, 0xff, 0x91, 0xc3, 0xdf, 0xf5, 0xdc,
+  0x2b, 0x7f, 0xf0, 0x0e, 0x86, 0xe2, 0xa7, 0x1c,
+  0x2d, 0x43, 0x0a, 0x56, 0x84, 0xfb, 0xa1, 0x25,
+  0x75, 0xd6, 0xc6, 0xb3, 0xe1, 0x4e, 0xe4, 0x34,
+  0x45, 0xd3, 0xeb, 0x83, 0x7f, 0xde, 0x5b, 0x3d,
+  0x92, 0x76, 0x1f, 0x47, 0x18, 0x43, 0x93, 0x09,
+  0x7c, 0x38, 0xe7, 0xfe, 0x67, 0x3d, 0xd8, 0x29,
+  0xdc, 0x86, 0x89, 0x9a, 0x75, 0x2b, 0x53, 0xa7,
+  0x27, 0x98, 0x74, 0xed, 0xd5, 0xb9, 0xba, 0x8e,
+  0x9f, 0x27, 0x5b, 0xcd, 0x1d, 0x3f, 0xf3, 0x7f,
+  0xaf, 0xe4, 0xf6, 0xd7, 0xc4, 0x3a, 0x7f, 0xff,
+  0xb5, 0xef, 0xa7, 0xf3, 0x6b, 0x6b, 0xa2, 0xca,
+  0xf1, 0x5a, 0x0e, 0x8c, 0x45, 0x8d, 0x91, 0xe7,
+  0xff, 0xdb, 0x7b, 0xf4, 0x65, 0x7d, 0xd6, 0x70,
+  0x42, 0x12, 0xa7, 0x93, 0xb9, 0x0d, 0x16, 0x7c,
+  0xff, 0xbd, 0x65, 0x7f, 0xae, 0xb7, 0xa9, 0xd3,
+  0xff, 0xde, 0x1b, 0x76, 0x8c, 0x6d, 0xfc, 0xae,
+  0x7c, 0xe9, 0xc1, 0x08, 0x4a, 0x9f, 0xf7, 0x3e,
+  0xbf, 0xc4, 0xdb, 0x04, 0xa7, 0x17, 0x93, 0xfc,
+  0xb6, 0xf6, 0xdf, 0xee, 0x68, 0xe9, 0xfe, 0xf7,
+  0xf6, 0xdf, 0xb6, 0xb7, 0xa9, 0xd0, 0x89, 0xf8,
+  0x8a, 0xc3, 0x0a, 0xec, 0x7c, 0x06, 0xdb, 0xa5,
+  0xb6, 0x39, 0x9f, 0xff, 0xff, 0xb3, 0x01, 0x5c,
+  0xcf, 0xe9, 0xde, 0x3f, 0x5c, 0xb3, 0xab, 0xfc,
+  0xa1, 0x98, 0xc3, 0xa7, 0x55, 0x68, 0x3a, 0x76,
+  0xe6, 0x58, 0xe8, 0x7a, 0x31, 0x2b, 0x08, 0xab,
+  0x8e, 0x4f, 0x52, 0x0d, 0x50, 0xe9, 0xf5, 0xbe,
+  0xb8, 0x26, 0x4f, 0xfb, 0xc2, 0xfc, 0x1a, 0x35,
+  0xed, 0x8d, 0x10, 0x6b, 0x8d, 0x2c, 0xfb, 0x93,
+  0xcc, 0x53, 0xa7, 0xe7, 0xdb, 0xfd, 0x4d, 0xce,
+  0x96, 0x21, 0xe9, 0xfc, 0x96, 0x7f, 0xff, 0xdc,
+  0x1b, 0xe5, 0xae, 0xb9, 0xfa, 0x6f, 0x83, 0xea,
+  0x39, 0x87, 0x43, 0xd3, 0x40, 0xc8, 0x57, 0xfc,
+  0x9a, 0x7e, 0x1c, 0xda, 0xb6, 0x53, 0xa7, 0xff,
+  0xf6, 0xbf, 0xed, 0x3a, 0x37, 0xff, 0xaf, 0x5f,
+  0x53, 0x6f, 0x04, 0xe9, 0xff, 0xfe, 0xad, 0x54,
+  0x6e, 0xae, 0x66, 0x5e, 0xbb, 0xeb, 0xcf, 0xc3,
+  0xa7, 0xad, 0x9e, 0x6c, 0x74, 0x79, 0x11, 0x36,
+  0x66, 0x99, 0x9b, 0xa1, 0xa2, 0xfc, 0x9f, 0xf9,
+  0xf7, 0xd5, 0xef, 0x65, 0xee, 0xac, 0x3a, 0x7f,
+  0xef, 0x67, 0xf3, 0x2b, 0xa1, 0xf5, 0x61, 0xd1,
+  0x4a, 0x22, 0xea, 0x8d, 0x3d, 0xff, 0xaa, 0x1d,
+  0x0a, 0x98, 0xd6, 0xc4, 0x79, 0x0b, 0x3e, 0x24,
+  0x9f, 0xff, 0xf9, 0xbd, 0x6d, 0xe6, 0x39, 0xa7,
+  0xf0, 0xef, 0xb7, 0xa9, 0xaa, 0x7a, 0x83, 0xa7,
+  0xfd, 0xcf, 0x67, 0x3e, 0xf5, 0x5d, 0x27, 0x4f,
+  0x65, 0x7d, 0xf3, 0xa3, 0xe7, 0xc1, 0xa9, 0xfc,
+  0xf6, 0xfd, 0x7a, 0xa7, 0x4f, 0xfa, 0xf5, 0x07,
+  0xa9, 0xa5, 0xf9, 0x73, 0xa1, 0x4f, 0x97, 0x09,
+  0x26, 0x6b, 0x53, 0xa4, 0xc3, 0xa2, 0x93, 0x50,
+  0xdd, 0x8c, 0x4f, 0xff, 0xfa, 0xde, 0xa6, 0xf9,
+  0x4d, 0xc4, 0x56, 0xe0, 0xdf, 0xf7, 0xdb, 0x0e,
+  0x9c, 0x10, 0x84, 0xa9, 0xed, 0xb6, 0xef, 0x94,
+  0xe2, 0xf2, 0x7f, 0xdd, 0x64, 0xf7, 0x68, 0xaf,
+  0x58, 0xe8, 0x54, 0xc8, 0x90, 0x9f, 0xd0, 0x8b,
+  0xb1, 0x94, 0xff, 0xd9, 0xfa, 0x6f, 0x83, 0xea,
+  0x39, 0x87, 0x4f, 0xb2, 0xef, 0x65, 0x8e, 0x85,
+  0x3e, 0xba, 0xa2, 0x4c, 0x0b, 0x1d, 0x3f, 0x50,
+  0xd3, 0xdb, 0x83, 0x41, 0xd3, 0xfb, 0x4d, 0xb2,
+  0xf6, 0xf5, 0xce, 0x9b, 0xc2, 0x74, 0x6e, 0xa3,
+  0xfe, 0xf1, 0xa5, 0x8d, 0x67, 0xfe, 0xd9, 0x76,
+  0x15, 0xbf, 0x93, 0xdb, 0x1d, 0x3f, 0x5b, 0x5a,
+  0x1a, 0xb7, 0x8e, 0x8d, 0x8f, 0xda, 0xc8, 0xb2,
+  0x73, 0x74, 0x66, 0xee, 0xee, 0xb0, 0xe2, 0x8d,
+  0xd0, 0x57, 0xb4, 0x36, 0x32, 0x50, 0x9d, 0x31,
+  0x94, 0xf8, 0xd5, 0xa8, 0xe2, 0x04, 0xd5, 0x85,
+  0x96, 0x94, 0x1b, 0xc8, 0x20, 0x86, 0xd7, 0xe1,
+  0x11, 0x58, 0xda, 0xaf, 0x0a, 0xc0, 0x90, 0xee,
+  0x42, 0x53, 0x7c, 0x2a, 0xe1, 0xcc, 0xf9, 0x0b,
+  0x53, 0x8a, 0x67, 0xff, 0x39, 0x9c, 0xf7, 0x60,
+  0xa7, 0x72, 0x1a, 0x26, 0xc9, 0xfc, 0xec, 0x14,
+  0xee, 0x43, 0x45, 0x5b, 0x3f, 0x9e, 0xfd, 0x6f,
+  0xf5, 0x79, 0xd3, 0xd9, 0x6e, 0xb9, 0xd2, 0xdd,
+  0x30, 0xf5, 0x3e, 0x69, 0x3e, 0x14, 0xee, 0x43,
+  0x45, 0x69, 0x3f, 0xfc, 0x8a, 0x38, 0x0e, 0x67,
+  0x3d, 0x7c, 0x87, 0x4f, 0xff, 0x3e, 0xb9, 0xf5,
+  0x67, 0x65, 0xee, 0xac, 0x3a, 0x6b, 0xdd, 0x51,
+  0x2f, 0xc9, 0x53, 0xf9, 0x5b, 0x6f, 0xbf, 0xd4,
+  0x07, 0x4f, 0xd4, 0x65, 0xbd, 0x8c, 0x3a, 0x7f,
+  0xb1, 0xbf, 0xea, 0x1a, 0x5f, 0x53, 0xa7, 0xf3,
+  0xf2, 0xfd, 0xf0, 0x6a, 0x74, 0x9c, 0xdc, 0x4f,
+  0xcb, 0x0b, 0x3d, 0x0c, 0x7b, 0x16, 0xf1, 0xb7,
+  0xcb, 0x6e, 0x79, 0x3f, 0x9d, 0x82, 0x9d, 0xc8,
+  0x68, 0xb0, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0x9d,
+  0x67, 0xff, 0xf5, 0x96, 0x8d, 0xb1, 0x8e, 0xad,
+  0x72, 0xde, 0xae, 0xb4, 0x1d, 0x3e, 0x73, 0x39,
+  0xee, 0xc4, 0x4a, 0xb4, 0x61, 0x3e, 0x14, 0xee,
+  0x43, 0x45, 0xb3, 0x3f, 0xe0, 0x2d, 0x5d, 0x6f,
+  0x27, 0x09, 0xd2, 0x76, 0x1f, 0x67, 0x18, 0x4f,
+  0x27, 0x72, 0x1a, 0x2e, 0x69, 0x30, 0xe9, 0x9d,
+  0x82, 0x6e, 0xc2, 0x57, 0x3f, 0x9d, 0x82, 0x9d,
+  0xc8, 0x68, 0xbb, 0xe7, 0x9d, 0xa7, 0x60, 0x1d,
+  0x0a, 0xda, 0xcb, 0x65, 0x3e, 0xe5, 0x0c, 0x29,
+  0x52, 0xf4, 0xa8, 0x11, 0x72, 0x64, 0x34, 0x01,
+  0x0a, 0xca, 0xb0, 0xdc, 0xaf, 0x79, 0xdc, 0xff,
+  0xbf, 0xce, 0x5a, 0xd5, 0x9c, 0xf3, 0xa7, 0xf7,
+  0xe8, 0xc6, 0xfb, 0xae, 0x93, 0xa7, 0xc2, 0x9d,
+  0xc8, 0x68, 0x95, 0xe7, 0xfd, 0xfe, 0x0e, 0xd6,
+  0x5a, 0x30, 0x27, 0x4f, 0x6b, 0xc2, 0xf3, 0xa7,
+  0xff, 0xf7, 0xaf, 0xcc, 0xef, 0x82, 0xc1, 0xef,
+  0xd0, 0x9e, 0xa0, 0xe8, 0xd9, 0x10, 0x7c, 0x43,
+  0x1b, 0x23, 0x96, 0xd0, 0xc2, 0x9d, 0xcf, 0x72,
+  0xa6, 0xed, 0x87, 0x15, 0x8c, 0x56, 0x75, 0xd7,
+  0x62, 0xa7, 0xff, 0x5b, 0xbd, 0x75, 0x7f, 0x86,
+  0x8d, 0x40, 0x54, 0xfe, 0xe4, 0x76, 0xc2, 0xdd,
+  0xb9, 0x4f, 0x9e, 0xa3, 0x92, 0x72, 0x2a, 0xae,
+  0x64, 0x76, 0x6d, 0xa1, 0x5b, 0x3f, 0xf9, 0xcc,
+  0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x30, 0xcf,
+  0xff, 0xd8, 0xed, 0xe3, 0xc0, 0x76, 0x9b, 0xbc,
+  0x2b, 0x57, 0x9d, 0x3f, 0xf6, 0xe9, 0x94, 0xbf,
+  0x5e, 0xbf, 0xd5, 0xe7, 0x4f, 0xe5, 0xea, 0x2f,
+  0xa7, 0x84, 0xe9, 0xf7, 0x0b, 0xf9, 0x87, 0x47,
+  0xcf, 0x63, 0x53, 0x39, 0xf9, 0x8b, 0x9f, 0xbe,
+  0xe1, 0xd3, 0xe5, 0xcf, 0xdf, 0x70, 0xe9, 0xfa,
+  0xde, 0xbd, 0x7a, 0x9d, 0x07, 0xb0, 0xc2, 0xf9,
+  0xff, 0xff, 0x7f, 0x02, 0xdf, 0x7c, 0xb6, 0x8f,
+  0xe5, 0x1e, 0xcf, 0xd2, 0xfa, 0x9d, 0x3f, 0x36,
+  0xdf, 0x7f, 0xa8, 0x0e, 0x9f, 0xfc, 0xb7, 0x02,
+  0xbf, 0x29, 0xbd, 0x1a, 0x84, 0xe8, 0x53, 0xfd,
+  0xf1, 0x8c, 0xfd, 0x5f, 0x69, 0x67, 0x5c, 0xe9,
+  0xff, 0xff, 0x0e, 0x36, 0x5f, 0xdf, 0x46, 0xff,
+  0xad, 0xbb, 0xd7, 0x5b, 0xd4, 0xe9, 0x65, 0x28,
+  0x9f, 0x12, 0xf9, 0xef, 0xa8, 0x37, 0x9d, 0x3d,
+  0xdb, 0xf6, 0xc3, 0xa4, 0xe6, 0xe2, 0xb8, 0x3d,
+  0xa1, 0x44, 0x8f, 0x6d, 0x24, 0x5a, 0x1e, 0x1f,
+  0x86, 0x05, 0xca, 0x35, 0x23, 0x9f, 0x0a, 0x77,
+  0x21, 0xa2, 0xae, 0x9f, 0xe7, 0xbb, 0x05, 0x3b,
+  0x90, 0xd1, 0x1e, 0x49, 0xd8, 0x7e, 0x3c, 0x61,
+  0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb0, 0x67,
+  0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x16, 0x54, 0xfe,
+  0x76, 0x0a, 0x77, 0x21, 0xa2, 0xd3, 0x9e, 0x4e,
+  0xe4, 0x34, 0x5b, 0x93, 0xff, 0x2e, 0x0e, 0x7f,
+  0x45, 0xb2, 0x90, 0x9d, 0x02, 0x7d, 0xf5, 0x2b,
+  0x9f, 0xe5, 0xfe, 0xac, 0x5a, 0xdf, 0xc7, 0x4f,
+  0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x45, 0x0f,
+  0x3f, 0x57, 0xa9, 0xad, 0xfc, 0x74, 0xfd, 0xf6,
+  0xe6, 0x0a, 0xd4, 0xe9, 0xff, 0xfb, 0x36, 0xb2,
+  0xef, 0x75, 0xff, 0xc0, 0xad, 0x54, 0x05, 0x49,
+  0xd8, 0x9a, 0xd7, 0x88, 0x58, 0x73, 0x74, 0x6d,
+  0x4b, 0xb7, 0x0b, 0xe7, 0xf3, 0xb0, 0x53, 0xb9,
+  0x0d, 0x17, 0x9c, 0x2b, 0x22, 0xc9, 0xe8, 0x9b,
+  0x29, 0x64, 0xbe, 0x1a, 0x61, 0xfe, 0x24, 0xcc,
+  0x3b, 0xb1, 0xdf, 0xe5, 0x02, 0x36, 0x61, 0x9f,
+  0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x52, 0xd3, 0xf9,
+  0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x0a, 0x7f, 0x3b,
+  0x05, 0x3b, 0x90, 0xd1, 0x65, 0xcf, 0x3b, 0x4e,
+  0xeb, 0xe6, 0xea, 0x74, 0xe7, 0x6f, 0x61, 0xd3,
+  0xc8, 0xe5, 0xaa, 0x1e, 0x96, 0xa6, 0x93, 0xff,
+  0x9c, 0xce, 0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x14,
+  0x64, 0xfe, 0x72, 0xb6, 0x51, 0x50, 0x1d, 0x0f,
+  0x4e, 0xfc, 0x4e, 0xd8, 0x77, 0xd0, 0x8d, 0xa9,
+  0xc5, 0xd4, 0xa7, 0xfe, 0x77, 0x3d, 0xd8, 0x29,
+  0xdc, 0x86, 0x88, 0xe6, 0x7f, 0xf3, 0x99, 0xcf,
+  0x76, 0x0a, 0x77, 0x21, 0xa2, 0x72, 0x9f, 0xce,
+  0xc1, 0x4e, 0xe4, 0x34, 0x59, 0x93, 0xff, 0x39,
+  0x40, 0x2b, 0x7b, 0x75, 0x2f, 0x3a, 0x7f, 0x3b,
+  0x05, 0x3b, 0x90, 0xd1, 0x6e, 0xcf, 0xfe, 0x73,
+  0x39, 0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x52, 0x13,
+  0xff, 0x3b, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44,
+  0xa5, 0x14, 0x27, 0xea, 0xd2, 0x63, 0x14, 0x80,
+  0x77, 0xf4, 0x3b, 0x9d, 0xb7, 0xa9, 0x4f, 0xfb,
+  0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0xed, 0x3f,
+  0xfe, 0xf6, 0xda, 0xb1, 0x5b, 0xfb, 0x6f, 0xaf,
+  0xf1, 0x0e, 0x93, 0x98, 0x89, 0xfe, 0x46, 0x9f,
+  0xfb, 0x99, 0x6c, 0x4e, 0xb2, 0xef, 0x79, 0xd3,
+  0xff, 0x7f, 0x2d, 0xd4, 0x65, 0x7f, 0xd4, 0x9d,
+  0x36, 0xe3, 0xb6, 0x44, 0x3d, 0x50, 0xe1, 0x88,
+  0xe2, 0xdc, 0x85, 0x7c, 0xf8, 0x53, 0xb9, 0x0d,
+  0x11, 0x64, 0xff, 0xb9, 0xee, 0xc1, 0x4e, 0xe4,
+  0x34, 0x4b, 0xb3, 0xff, 0xf6, 0x6d, 0x65, 0xde,
+  0xeb, 0xff, 0x81, 0x5a, 0xa8, 0x0a, 0x93, 0xb1,
+  0x1a, 0x6c, 0x30, 0xdc, 0x46, 0x9f, 0xfc, 0xe6,
+  0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x98, 0xa7,
+  0xec, 0x14, 0xee, 0x43, 0x45, 0x53, 0x3f, 0xff,
+  0xf8, 0x7a, 0xd4, 0xbf, 0x2e, 0xeb, 0x75, 0x47,
+  0xc1, 0xbd, 0xbc, 0x2f, 0x3a, 0x1c, 0x8a, 0xce,
+  0x35, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d,
+  0xc8, 0x68, 0x9d, 0x27, 0xf7, 0xb8, 0x55, 0xfc,
+  0xd8, 0xe9, 0xf3, 0x4a, 0xd2, 0xd4, 0xe9, 0xf8,
+  0x39, 0xe6, 0xd9, 0xf3, 0xa7, 0xbd, 0x65, 0x77,
+  0x8f, 0x5a, 0xa5, 0x13, 0xff, 0x6b, 0x5b, 0xad,
+  0x2e, 0xd5, 0xaf, 0x30, 0xe8, 0x62, 0x20, 0xac,
+  0x73, 0x3f, 0xee, 0x7b, 0xb0, 0x53, 0xb9, 0x0d,
+  0x13, 0xbc, 0xfa, 0xfa, 0xf3, 0x3c, 0x54, 0x9d,
+  0xb2, 0x73, 0x79, 0x18, 0x53, 0x08, 0xf9, 0x1a,
+  0x7f, 0xf3, 0x99, 0xcf, 0x76, 0x0a, 0x77, 0x21,
+  0xa2, 0x85, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82,
+  0x9d, 0xc8, 0x68, 0xa4, 0xa7, 0xff, 0xf6, 0x55,
+  0xdb, 0xf1, 0xab, 0x73, 0x2f, 0x65, 0xbe, 0xac,
+  0x3a, 0x28, 0x5c, 0x96, 0x79, 0xc2, 0x43, 0xf8,
+  0x48, 0x99, 0x1f, 0x68, 0x12, 0x75, 0x52, 0xdc,
+  0x52, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x44,
+  0x93, 0xff, 0x9c, 0xce, 0x7b, 0xb0, 0x53, 0xb9,
+  0x0d, 0x12, 0xf4, 0xf8, 0x53, 0xb9, 0x0d, 0x14,
+  0xbc, 0xff, 0xec, 0x7a, 0x82, 0xa2, 0xb4, 0xbf,
+  0xcc, 0x3a, 0x7c, 0xdf, 0xe6, 0x2d, 0x4e, 0x9f,
+  0x73, 0x6c, 0x1a, 0x9d, 0x25, 0xd8, 0xf4, 0x58,
+  0x55, 0x27, 0x62, 0x3c, 0x9a, 0x30, 0xbc, 0x26,
+  0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x14, 0xe4,
+  0xff, 0xbc, 0x3d, 0x5b, 0x66, 0x7d, 0x0e, 0x9f,
+  0xf6, 0x59, 0x47, 0x1c, 0x10, 0x84, 0xa9, 0xbc,
+  0x13, 0xa6, 0xa1, 0xdb, 0x22, 0x37, 0x70, 0xed,
+  0xbc, 0xf2, 0x7c, 0x29, 0xdc, 0x86, 0x8a, 0xf2,
+  0x7f, 0xfe, 0xcd, 0xac, 0xbb, 0xdd, 0x7f, 0xf0,
+  0x2b, 0x55, 0x01, 0x52, 0x76, 0x22, 0x37, 0x70,
+  0xc2, 0x7f, 0xe7, 0x73, 0xdd, 0x82, 0x9d, 0xc8,
+  0x68, 0x91, 0xe7, 0x78, 0x0a, 0x74, 0xe4, 0xc6,
+  0x14, 0xe2, 0xee, 0x7c, 0x29, 0xdc, 0x86, 0x89,
+  0x22, 0x79, 0xdc, 0xf7, 0x29, 0xec, 0xe1, 0x4c,
+  0xff, 0xce, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1,
+  0x25, 0x4f, 0x85, 0x3b, 0x90, 0xd1, 0x78, 0xcf,
+  0xda, 0xfe, 0x9e, 0xa6, 0xa7, 0x4f, 0xab, 0x5b,
+  0xe2, 0x1d, 0x3f, 0xcf, 0x76, 0x0a, 0x77, 0x21,
+  0xa2, 0x4d, 0x93, 0xb1, 0x18, 0xf4, 0x98, 0x09,
+  0x87, 0x13, 0x42, 0xae, 0xe4, 0xd0, 0x76, 0xf8,
+  0xd1, 0x36, 0x3b, 0xf4, 0x32, 0x1a, 0x86, 0x8b,
+  0x0a, 0xed, 0x0c, 0x0b, 0x9b, 0xeb, 0x18, 0x9c,
+  0x2c, 0x6e, 0xd9, 0x14, 0x47, 0x5c, 0xf8, 0xf2,
+  0x76, 0x94, 0x35, 0x96, 0xeb, 0x5b, 0x4c, 0xa5,
+  0x84, 0xaf, 0xf7, 0xa9, 0x9e, 0x7b, 0xf4, 0xe7,
+  0xa6, 0xee, 0x3b, 0x06, 0xa9, 0xd8, 0x63, 0x48,
+  0xf5, 0x66, 0x23, 0x3e, 0xed, 0x3b, 0x51, 0xd4,
+  0xf7, 0x20, 0x4b, 0x0e, 0x6e, 0xe1, 0x63, 0xf9,
+  0xec, 0x6a, 0xd2, 0x57, 0x6f, 0x5d, 0x0f, 0xeb,
+  0x4c, 0x16, 0x6d, 0x29, 0x88, 0x32, 0x94, 0x37,
+  0x23, 0xeb, 0xdf, 0x3b, 0x28, 0xdf, 0x3c, 0x97,
+  0x00,
 };
 
-static const unsigned kPreloadedHSTSBits = 94538;
+static const unsigned kPreloadedHSTSBits = 97858;
 
-static const unsigned kHSTSRootPosition = 93961;
+static const unsigned kHSTSRootPosition = 97280;
 
 #endif // NET_HTTP_TRANSPORT_SECURITY_STATE_STATIC_H_
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 2517d20..39ca582 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -1395,7 +1395,7 @@
     // Facebook would like to have pinning enforced on (*.)facebook.com and
     // HSTS enforced on specific names. We can't (yet) represent that in JSON
     // So we're currently only applying pinning on the specific names.
-    { "name": "facebook.com", "mode": "force-https", "pins": "facebook" },
+    { "name": "facebook.com", "mode": "force-https", "pins": "facebook", "include_subdomains_for_pinning": true },
     { "name": "www.facebook.com", "include_subdomains": true, "mode": "force-https", "pins": "facebook" },
     { "name": "m.facebook.com", "include_subdomains": true, "mode": "force-https", "pins": "facebook" },
     { "name": "tablet.facebook.com", "include_subdomains": true, "mode": "force-https", "pins": "facebook" },
@@ -1472,7 +1472,50 @@
     { "name": "www.etsy.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "etsysecure.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "18f.gsa.gov", "include_subdomains": true, "mode": "force-https" },
-    { "name": "my.usa.gov", "include_subdomains": true, "mode": "force-https" }
+    { "name": "my.usa.gov", "include_subdomains": true, "mode": "force-https" },
+    { "name": "alexyang.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "beamitapp.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bonigo.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "certly.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "chontalpa.pw", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cktennis.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "clintwilson.technology", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cspbuilder.info", "include_subdomains": true, "mode": "force-https" },
+    { "name": "depechemode-live.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "destinationbijoux.fr", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dinamoelektrik.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ethack.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fabianfischer.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fastcomcorp.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gizzo.sk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "inkbunny.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "itsamurai.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "itshost.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jmedved.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jwilsson.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "keepclean.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "klausbrinch.dk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "leonardcamacho.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mdfnet.se", "include_subdomains": true, "mode": "force-https" },
+    { "name": "michalspacek.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mike-bland.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mocloud.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "oakslighting.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "onsitemassageco.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "propagandism.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "slevomat.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sour.is", "include_subdomains": true, "mode": "force-https" },
+    { "name": "spongepowered.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "staticanime.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sunjaydhama.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "swehack.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thusoy.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tls.li", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vhost.co.id", "include_subdomains": true, "mode": "force-https" },
+    { "name": "webandwords.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "webtiles.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "yoursecondphone.co", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zlavomat.sk", "include_subdomains": true, "mode": "force-https" }
   ],
 
   // |ReportUMAOnPinFailure| uses these to report which domain was associated
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index eb72050..cf5f243 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -299,7 +299,6 @@
 
   EXPECT_TRUE(HasStaticState("paypal.com"));
   EXPECT_FALSE(HasStaticState("www2.paypal.com"));
-  EXPECT_FALSE(HasStaticState("www2.paypal.com"));
 
   // Google hosts:
 
@@ -535,6 +534,24 @@
   EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
 
   EXPECT_TRUE(HasStaticPublicKeyPins("www.twitter.com"));
+
+  // Check that Facebook subdomains have pinning but not HSTS.
+  EXPECT_TRUE(state.GetStaticDomainState("facebook.com", &domain_state));
+  EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
+  EXPECT_TRUE(StaticShouldRedirect("facebook.com"));
+
+  EXPECT_TRUE(state.GetStaticDomainState("foo.facebook.com", &domain_state));
+  EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
+  EXPECT_FALSE(StaticShouldRedirect("foo.facebook.com"));
+
+  EXPECT_TRUE(state.GetStaticDomainState("www.facebook.com", &domain_state));
+  EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
+  EXPECT_TRUE(StaticShouldRedirect("www.facebook.com"));
+
+  EXPECT_TRUE(
+      state.GetStaticDomainState("foo.www.facebook.com", &domain_state));
+  EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
+  EXPECT_TRUE(StaticShouldRedirect("foo.www.facebook.com"));
 }
 
 TEST_F(TransportSecurityStateTest, LongNames) {
diff --git a/net/http/url_security_manager_win.cc b/net/http/url_security_manager_win.cc
index db5620f..5576366 100644
--- a/net/http/url_security_manager_win.cc
+++ b/net/http/url_security_manager_win.cc
@@ -111,11 +111,11 @@
 }
 
 bool URLSecurityManagerWin::EnsureSystemSecurityManager() {
-  if (!security_manager_) {
+  if (!security_manager_.get()) {
     HRESULT hr = CoInternetCreateSecurityManager(NULL,
                                                  security_manager_.Receive(),
                                                  NULL);
-    if (FAILED(hr) || !security_manager_) {
+    if (FAILED(hr) || !security_manager_.get()) {
       LOG(ERROR) << "Unable to create the Windows Security Manager instance";
       return false;
     }
diff --git a/net/net.gyp b/net/net.gyp
index 7b4b5d6..e9379e0 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -376,13 +376,8 @@
         }],
         [ 'enable_websockets != 1', {
             'sources/': [
-              ['exclude', '^socket_stream/'],
               ['exclude', '^websockets/'],
             ],
-            'sources!': [
-              'spdy/spdy_websocket_stream.cc',
-              'spdy/spdy_websocket_stream.h',
-            ],
         }],
         [ 'enable_mdns != 1', {
             'sources!' : [
@@ -654,9 +649,7 @@
         }],
         [ 'enable_websockets != 1', {
             'sources/': [
-              ['exclude', '^socket_stream/'],
               ['exclude', '^websockets/'],
-              ['exclude', '^spdy/spdy_websocket_stream_unittest\\.cc$'],
             ],
         }],
         ['disable_file_support==1', {
@@ -1654,23 +1647,35 @@
             'net_javatests',
             'net_unittests',
           ],
+          'conditions': [
+            ['v8_use_external_startup_data==1', {
+              'dependencies': [
+                '../v8/tools/gyp/v8.gyp:v8_external_snapshot',
+              ],
+              'copies': [
+                {
+                'destination': '<(asset_location)',
+                  'files': [
+                    '<(PRODUCT_DIR)/natives_blob.bin',
+                    '<(PRODUCT_DIR)/snapshot_blob.bin',
+                  ],
+                },
+              ],
+            }],
+          ],
           'variables': {
             'test_suite_name': 'net_unittests',
             'conditions': [
               ['v8_use_external_startup_data==1', {
+                'asset_location': '<(PRODUCT_DIR)/net_unittests_apk/assets',
                 'additional_input_paths': [
+                  '<(PRODUCT_DIR)/net_unittests_apk/assets/natives_blob.bin',
+                  '<(PRODUCT_DIR)/net_unittests_apk/assets/snapshot_blob.bin',
+                ],
+                'inputs': [
                   '<(PRODUCT_DIR)/natives_blob.bin',
                   '<(PRODUCT_DIR)/snapshot_blob.bin',
                 ],
-                'copies': [
-                  {
-                  'destination': '<(PRODUCT_DIR)/net_unittests_apk/assets',
-                    'files': [
-                      '<(PRODUCT_DIR)/natives_blob.bin',
-                      '<(PRODUCT_DIR)/snapshot_blob.bin',
-                    ],
-                  },
-                ],
               }],
             ],
           },
diff --git a/net/net.gypi b/net/net.gypi
index f43c67f..fef6136 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1016,14 +1016,6 @@
       'socket/websocket_transport_client_socket_pool.h',
       'socket/websocket_transport_connect_sub_job.cc',
       'socket/websocket_transport_connect_sub_job.h',
-      'socket_stream/socket_stream.cc',
-      'socket_stream/socket_stream.h',
-      'socket_stream/socket_stream_job.cc',
-      'socket_stream/socket_stream_job.h',
-      'socket_stream/socket_stream_job_manager.cc',
-      'socket_stream/socket_stream_job_manager.h',
-      'socket_stream/socket_stream_metrics.cc',
-      'socket_stream/socket_stream_metrics.h',
       'spdy/buffered_spdy_framer.cc',
       'spdy/buffered_spdy_framer.h',
       'spdy/fuzzing/hpack_fuzz_util.cc',
@@ -1089,8 +1081,6 @@
       'spdy/spdy_session_pool.h',
       'spdy/spdy_stream.cc',
       'spdy/spdy_stream.h',
-      'spdy/spdy_websocket_stream.cc',
-      'spdy/spdy_websocket_stream.h',
       'spdy/spdy_write_queue.cc',
       'spdy/spdy_write_queue.h',
       'spdy/write_blocked_list.h',
@@ -1249,15 +1239,9 @@
       'websockets/websocket_handshake_stream_create_helper.h',
       'websockets/websocket_inflater.cc',
       'websockets/websocket_inflater.h',
-      'websockets/websocket_job.cc',
-      'websockets/websocket_job.h',
       'websockets/websocket_mux.h',
-      'websockets/websocket_net_log_params.cc',
-      'websockets/websocket_net_log_params.h',
       'websockets/websocket_stream.cc',
       'websockets/websocket_stream.h',
-      'websockets/websocket_throttle.cc',
-      'websockets/websocket_throttle.h',
     ],
     'net_extras_sources': [
       'extras/sqlite/sqlite_channel_id_store.cc',
@@ -1613,8 +1597,6 @@
       'socket/unix_domain_server_socket_posix_unittest.cc',
       'socket/websocket_endpoint_lock_manager_unittest.cc',
       'socket/websocket_transport_client_socket_pool_unittest.cc',
-      'socket_stream/socket_stream_metrics_unittest.cc',
-      'socket_stream/socket_stream_unittest.cc',
       'spdy/buffered_spdy_framer_unittest.cc',
       'spdy/fuzzing/hpack_fuzz_util_test.cc',
       'spdy/hpack_decoder_test.cc',
@@ -1657,9 +1639,6 @@
       'spdy/spdy_test_util_common.h',
       'spdy/spdy_test_utils.cc',
       'spdy/spdy_test_utils.h',
-      'spdy/spdy_websocket_stream_unittest.cc',
-      'spdy/spdy_websocket_test_util.cc',
-      'spdy/spdy_websocket_test_util.h',
       'spdy/spdy_write_queue_unittest.cc',
       'spdy/write_blocked_list_test.cc',
       'ssl/channel_id_service_unittest.cc',
@@ -1722,16 +1701,12 @@
       'websockets/websocket_extension_parser_test.cc',
       'websockets/websocket_frame_parser_test.cc',
       'websockets/websocket_frame_test.cc',
-      'websockets/websocket_handshake_handler_spdy_test.cc',
       'websockets/websocket_handshake_handler_test.cc',
       'websockets/websocket_handshake_stream_create_helper_test.cc',
       'websockets/websocket_inflater_test.cc',
-      'websockets/websocket_job_test.cc',
-      'websockets/websocket_net_log_params_test.cc',
       'websockets/websocket_stream_test.cc',
       'websockets/websocket_test_util.cc',
       'websockets/websocket_test_util.h',
-      'websockets/websocket_throttle_test.cc',
     ],
     'net_linux_test_sources': [
       'quic/quic_end_to_end_unittest.cc',
diff --git a/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc b/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc
index 8e19001..dc0d1b4 100644
--- a/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc
+++ b/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc
@@ -86,7 +86,7 @@
     dhcp_query_ = new DelayingDhcpQuery();
     dhcp_query_->dhcp_delay_ = dhcp_delay_;
     dhcp_query_->configured_url_ = configured_url_;
-    return dhcp_query_;
+    return dhcp_query_.get();
   }
 
   // Use a shorter timeout so tests can finish more quickly.
@@ -116,7 +116,7 @@
   }
 
   void FinishTest() {
-    DCHECK(dhcp_query_);
+    DCHECK(dhcp_query_.get());
     dhcp_query_->test_finished_event_.Signal();
   }
 
diff --git a/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc b/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc
index eb98330..c3368ac 100644
--- a/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc
+++ b/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc
@@ -330,7 +330,7 @@
   }
 
   virtual AdapterQuery* ImplCreateAdapterQuery() override {
-    DCHECK(adapter_query_);
+    DCHECK(adapter_query_.get());
     return adapter_query_.get();
   }
 
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index 8b6dfb7..4828c3a 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -32,25 +32,21 @@
 
 namespace {
 
-enum ServerConfigState {
-  // WARNING: Do not change the numerical values of any of server config state.
-  // Do not remove deprecated server config states - just comment them as
-  // deprecated.
-  SERVER_CONFIG_EMPTY = 0,
-  SERVER_CONFIG_INVALID = 1,
-  SERVER_CONFIG_CORRUPTED = 2,
-  SERVER_CONFIG_EXPIRED = 3,
-  SERVER_CONFIG_INVALID_EXPIRY = 4,
+// Tracks the reason (the state of the server config) for sending inchoate
+// ClientHello to the server.
+void RecordInchoateClientHelloReason(
+    QuicCryptoClientConfig::CachedState::ServerConfigState state) {
+  UMA_HISTOGRAM_ENUMERATION(
+      "Net.QuicInchoateClientHelloReason", state,
+      QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT);
+}
 
-  // NOTE: Add new server config states only immediately above this line. Make
-  // sure to update the QuicServerConfigState enum in
-  // tools/metrics/histograms/histograms.xml accordingly.
-  SERVER_CONFIG_COUNT
-};
-
-void RecordServerConfigState(ServerConfigState server_config_state) {
-  UMA_HISTOGRAM_ENUMERATION("Net.QuicClientHelloServerConfigState",
-                            server_config_state, SERVER_CONFIG_COUNT);
+// Tracks the state of the QUIC server information loaded from the disk cache.
+void RecordDiskCacheServerConfigState(
+    QuicCryptoClientConfig::CachedState::ServerConfigState state) {
+  UMA_HISTOGRAM_ENUMERATION(
+      "Net.QuicServerInfo.DiskCacheState", state,
+      QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT);
 }
 
 }  // namespace
@@ -72,12 +68,12 @@
 
 bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const {
   if (server_config_.empty()) {
-    RecordServerConfigState(SERVER_CONFIG_EMPTY);
+    RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY);
     return false;
   }
 
   if (!server_config_valid_) {
-    RecordServerConfigState(SERVER_CONFIG_INVALID);
+    RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID);
     return false;
   }
 
@@ -85,13 +81,13 @@
   if (!scfg) {
     // Should be impossible short of cache corruption.
     DCHECK(false);
-    RecordServerConfigState(SERVER_CONFIG_CORRUPTED);
+    RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
     return false;
   }
 
   uint64 expiry_seconds;
   if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
-    RecordServerConfigState(SERVER_CONFIG_INVALID_EXPIRY);
+    RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID_EXPIRY);
     return false;
   }
   if (now.ToUNIXSeconds() >= expiry_seconds) {
@@ -99,7 +95,7 @@
         "Net.QuicClientHelloServerConfig.InvalidDuration",
         base::TimeDelta::FromSeconds(now.ToUNIXSeconds() - expiry_seconds),
         base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50);
-    RecordServerConfigState(SERVER_CONFIG_EXPIRED);
+    RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED);
     return false;
   }
 
@@ -123,7 +119,8 @@
   return scfg_.get();
 }
 
-QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig(
+QuicCryptoClientConfig::CachedState::ServerConfigState
+QuicCryptoClientConfig::CachedState::SetServerConfig(
     StringPiece server_config, QuicWallTime now, string* error_details) {
   const bool matches_existing = server_config == server_config_;
 
@@ -141,18 +138,18 @@
 
   if (!new_scfg) {
     *error_details = "SCFG invalid";
-    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+    return SERVER_CONFIG_INVALID;
   }
 
   uint64 expiry_seconds;
   if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
     *error_details = "SCFG missing EXPY";
-    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+    return SERVER_CONFIG_INVALID_EXPIRY;
   }
 
   if (now.ToUNIXSeconds() >= expiry_seconds) {
     *error_details = "SCFG has expired";
-    return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
+    return SERVER_CONFIG_EXPIRED;
   }
 
   if (!matches_existing) {
@@ -160,7 +157,7 @@
     SetProofInvalid();
     scfg_.reset(new_scfg_storage.release());
   }
-  return QUIC_NO_ERROR;
+  return SERVER_CONFIG_VALID;
 }
 
 void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
@@ -228,13 +225,15 @@
   DCHECK(server_config_.empty());
 
   if (server_config.empty()) {
+    RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY);
     return false;
   }
 
   string error_details;
-  QuicErrorCode error = SetServerConfig(server_config, now,
-                                        &error_details);
-  if (error != QUIC_NO_ERROR) {
+  ServerConfigState state = SetServerConfig(server_config, now,
+                                            &error_details);
+  RecordDiskCacheServerConfigState(state);
+  if (state != SERVER_CONFIG_VALID) {
     DVLOG(1) << "SetServerConfig failed with " << error_details;
     return false;
   }
@@ -325,7 +324,10 @@
 
   CachedState* cached = new CachedState;
   cached_states_.insert(make_pair(server_id, cached));
-  PopulateFromCanonicalConfig(server_id, cached);
+  bool cache_populated = PopulateFromCanonicalConfig(server_id, cached);
+  UMA_HISTOGRAM_BOOLEAN(
+      "Net.QuicCryptoClientConfig.PopulatedFromCanonicalConfig",
+      cache_populated);
   return cached;
 }
 
@@ -591,9 +593,15 @@
     return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
   }
 
-  QuicErrorCode error = cached->SetServerConfig(scfg, now, error_details);
-  if (error != QUIC_NO_ERROR) {
-    return error;
+  CachedState::ServerConfigState state = cached->SetServerConfig(
+      scfg, now, error_details);
+  if (state == CachedState::SERVER_CONFIG_EXPIRED) {
+    return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
+  }
+  // TODO(rtenneti): Return more specific error code than returning
+  // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER.
+  if (state != CachedState::SERVER_CONFIG_VALID) {
+    return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
   }
 
   StringPiece token;
@@ -829,7 +837,7 @@
   disable_ecdsa_ = true;
 }
 
-void QuicCryptoClientConfig::PopulateFromCanonicalConfig(
+bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
     const QuicServerId& server_id,
     CachedState* server_state) {
   DCHECK(server_state->IsEmpty());
@@ -840,7 +848,7 @@
     }
   }
   if (i == canonical_suffixes_.size())
-    return;
+    return false;
 
   QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(),
                                 server_id.is_https(),
@@ -849,20 +857,21 @@
     // This is the first host we've seen which matches the suffix, so make it
     // canonical.
     canonical_server_map_[suffix_server_id] = server_id;
-    return;
+    return false;
   }
 
   const QuicServerId& canonical_server_id =
       canonical_server_map_[suffix_server_id];
   CachedState* canonical_state = cached_states_[canonical_server_id];
   if (!canonical_state->proof_valid()) {
-    return;
+    return false;
   }
 
   // Update canonical version to point at the "most recent" entry.
   canonical_server_map_[suffix_server_id] = server_id;
 
   server_state->InitializeFrom(*canonical_state);
+  return true;
 }
 
 }  // namespace net
diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h
index 26fde24..4bfed1b 100644
--- a/net/quic/crypto/quic_crypto_client_config.h
+++ b/net/quic/crypto/quic_crypto_client_config.h
@@ -35,6 +35,24 @@
   // over several connections to the same server.
   class NET_EXPORT_PRIVATE CachedState {
    public:
+    // Enum to track if the server config is valid or not. If it is not valid,
+    // it specifies why it is invalid.
+    enum ServerConfigState {
+      // WARNING: Do not change the numerical values of any of server config
+      // state. Do not remove deprecated server config states - just comment
+      // them as deprecated.
+      SERVER_CONFIG_EMPTY = 0,
+      SERVER_CONFIG_INVALID = 1,
+      SERVER_CONFIG_CORRUPTED = 2,
+      SERVER_CONFIG_EXPIRED = 3,
+      SERVER_CONFIG_INVALID_EXPIRY = 4,
+      SERVER_CONFIG_VALID = 5,
+      // NOTE: Add new server config states only immediately above this line.
+      // Make sure to update the QuicServerConfigState enum in
+      // tools/metrics/histograms/histograms.xml accordingly.
+      SERVER_CONFIG_COUNT
+    };
+
     CachedState();
     ~CachedState();
 
@@ -54,9 +72,9 @@
     // SetServerConfig checks that |server_config| parses correctly and stores
     // it in |server_config_|. |now| is used to judge whether |server_config|
     // has expired.
-    QuicErrorCode SetServerConfig(base::StringPiece server_config,
-                                  QuicWallTime now,
-                                  std::string* error_details);
+    ServerConfigState SetServerConfig(base::StringPiece server_config,
+                                      QuicWallTime now,
+                                      std::string* error_details);
 
     // InvalidateServerConfig clears the cached server config (if any).
     void InvalidateServerConfig();
@@ -282,8 +300,9 @@
 
   // If the suffix of the hostname in |server_id| is in |canonical_suffixes_|,
   // then populate |cached| with the canonical cached state from
-  // |canonical_server_map_| for that suffix.
-  void PopulateFromCanonicalConfig(const QuicServerId& server_id,
+  // |canonical_server_map_| for that suffix. Returns true if |cached| is
+  // initialized with canonical cached state.
+  bool PopulateFromCanonicalConfig(const QuicServerId& server_id,
                                    CachedState* cached);
 
   // cached_states_ maps from the server_id to the cached information about
diff --git a/net/quic/crypto/quic_server_info.h b/net/quic/crypto/quic_server_info.h
index 2a5c6fc..c6525c8 100644
--- a/net/quic/crypto/quic_server_info.h
+++ b/net/quic/crypto/quic_server_info.h
@@ -64,6 +64,9 @@
   // callback.
   virtual void Persist() = 0;
 
+  // Called whenever an external cache reuses quic server config.
+  virtual void OnExternalCacheHit() = 0;
+
   struct State {
     State();
     ~State();
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 7c220ad..73a5aec 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -590,6 +590,8 @@
       ++it;
       observer->OnCryptoHandshakeConfirmed();
     }
+    if (server_info_)
+      server_info_->OnExternalCacheHit();
   }
   QuicSession::OnCryptoHandshakeEvent(event);
 }
@@ -682,7 +684,7 @@
     const QuicCryptoClientConfig::CachedState& cached) {
   DCHECK(cached.proof_valid());
 
-  if (!server_info_ || !server_info_->IsReadyToPersist()) {
+  if (!server_info_) {
     return;
   }
 
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc
index b99e9d2..10a02a7 100644
--- a/net/quic/quic_headers_stream.cc
+++ b/net/quic/quic_headers_stream.cc
@@ -115,7 +115,11 @@
     CloseConnection("SPDY GOAWAY frame received.");
   }
 
-  void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) override {
+  void OnHeaders(SpdyStreamId stream_id,
+                 bool has_priority,
+                 SpdyPriority priority,
+                 bool fin,
+                 bool end) override {
     CloseConnection("SPDY HEADERS frame received.");
   }
 
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc
index 32d22fe..8649a3e 100644
--- a/net/quic/quic_headers_stream_test.cc
+++ b/net/quic/quic_headers_stream_test.cc
@@ -52,7 +52,8 @@
   MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
   MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
                               SpdyGoAwayStatus status));
-  MOCK_METHOD3(OnHeaders, void(SpdyStreamId stream_id, bool fin, bool end));
+  MOCK_METHOD5(OnHeaders, void(SpdyStreamId stream_id, bool has_priority,
+                               SpdyPriority priority, bool fin, bool end));
   MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id,
                                     uint32 delta_window_size));
   MOCK_METHOD2(OnCredentialFrameData, bool(const char* credential_data,
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 62fe895..ab926d5 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -214,7 +214,7 @@
 
     if (use_next_protos) {
       params_.use_alternate_protocols = true;
-      params_.next_protos = NextProtosSpdy3();
+      params_.next_protos = NextProtosWithSpdyAndQuic(true, true);
     }
 
     session_ = new HttpNetworkSession(params_);
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index afd5ed4..ad920d0 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -76,6 +76,9 @@
 // Smaller values are ignored.
 const QuicByteCount kMinSocketReceiveBuffer = 16 * 1024;
 
+// Don't allow a client to suggest an RTT shorter than 10ms.
+const uint32 kMinInitialRoundTripTimeUs = 10 * kNumMicrosPerMilli;
+
 // Don't allow a client to suggest an RTT longer than 15 seconds.
 const uint32 kMaxInitialRoundTripTimeUs = 15 * kNumMicrosPerSecond;
 
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index bdf8690..9e2d04f 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -97,12 +97,16 @@
 void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
   if (config.HasReceivedInitialRoundTripTimeUs() &&
       config.ReceivedInitialRoundTripTimeUs() > 0) {
-    rtt_stats_.set_initial_rtt_us(min(kMaxInitialRoundTripTimeUs,
-                                      config.ReceivedInitialRoundTripTimeUs()));
-  } else if (config.HasInitialRoundTripTimeUsToSend()) {
     rtt_stats_.set_initial_rtt_us(
-        min(kMaxInitialRoundTripTimeUs,
-            config.GetInitialRoundTripTimeUsToSend()));
+        max(kMinInitialRoundTripTimeUs,
+            min(kMaxInitialRoundTripTimeUs,
+                config.ReceivedInitialRoundTripTimeUs())));
+  } else if (config.HasInitialRoundTripTimeUsToSend() &&
+             config.GetInitialRoundTripTimeUsToSend() > 0) {
+    rtt_stats_.set_initial_rtt_us(
+        max(kMinInitialRoundTripTimeUs,
+            min(kMaxInitialRoundTripTimeUs,
+                config.GetInitialRoundTripTimeUsToSend())));
   }
   // TODO(ianswett): BBR is currently a server only feature.
   if (FLAGS_quic_allow_bbr &&
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index cf70608..076797a 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -944,6 +944,14 @@
     }
   }
 
+  if (quic_server_info_factory_ && !server_info) {
+    // Start the disk cache loading so that we can persist the newer QUIC server
+    // information and/or inform the disk cache that we have reused
+    // |server_info|.
+    server_info.reset(quic_server_info_factory_->GetForServer(server_id));
+    server_info->Start();
+  }
+
   *session = new QuicClientSession(
       connection, socket.Pass(), this, transport_security_state_,
       server_info.Pass(), config, server_id.is_https(),
@@ -985,6 +993,8 @@
 void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
     const QuicServerId& server_id,
     const scoped_ptr<QuicServerInfo>& server_info) {
+  // |server_info| will be NULL, if a non-empty server config already exists in
+  // the memory cache. This is a minor optimization to avoid LookupOrCreate.
   if (!server_info)
     return;
 
@@ -993,6 +1003,27 @@
   if (!cached->IsEmpty())
     return;
 
+  if (http_server_properties_) {
+    if (quic_supported_servers_at_startup_.empty()) {
+      for (const std::pair<net::HostPortPair, net::AlternateProtocolInfo>&
+               key_value : http_server_properties_->alternate_protocol_map()) {
+        if (key_value.second.protocol == QUIC) {
+          quic_supported_servers_at_startup_.insert(key_value.first);
+        }
+      }
+    }
+
+    // TODO(rtenneti): Delete the following histogram after collecting stats.
+    // If the AlternateProtocolMap contained an entry for this host, check if
+    // the disk cache contained an entry for it.
+    if (ContainsKey(quic_supported_servers_at_startup_,
+                    server_id.host_port_pair())) {
+      UMA_HISTOGRAM_BOOLEAN(
+          "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
+          server_info->state().server_config.empty());
+    }
+  }
+
   if (!cached->Initialize(server_info->state().server_config,
                           server_info->state().source_address_token,
                           server_info->state().certs,
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index c892cb2..2fad1fc 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -299,6 +299,7 @@
   // Local address of socket that was created in CreateSession.
   IPEndPoint local_address_;
   bool check_persisted_supports_quic_;
+  std::set<HostPortPair> quic_supported_servers_at_startup_;
 
   base::TaskRunner* task_runner_;
 
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 1165b9c..05234c0 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -121,6 +121,8 @@
   virtual bool IsReadyToPersist() override { return false; }
 
   virtual void Persist() override {};
+
+  virtual void OnExternalCacheHit() override {};
 };
 
 class MockQuicServerInfoFactory : public QuicServerInfoFactory {
diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h
index 5fbe30c..53e5ebe 100644
--- a/net/quic/quic_time.h
+++ b/net/quic/quic_time.h
@@ -18,6 +18,8 @@
 namespace net {
 
 static const uint64 kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond;
+static const uint64 kNumMicrosPerMilli =
+    base::Time::kMicrosecondsPerMillisecond;
 
 // A QuicTime is a purely relative time. QuicTime values from different clocks
 // cannot be compared to each other. If you need an absolute time, see
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index d786a95..f144651 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -7,12 +7,15 @@
 #include <ctype.h>
 
 #include <algorithm>
+#include <vector>
 
 #include "base/basictypes.h"
+#include "base/containers/adapters.h"
 #include "base/logging.h"
 #include "base/port.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
 #include "net/quic/quic_write_blocked_list.h"
 
 using base::StringPiece;
@@ -280,6 +283,25 @@
 }
 
 // static
+QuicTagVector QuicUtils::ParseQuicConnectionOptions(
+    const std::string& connection_options) {
+  QuicTagVector options;
+  std::vector<std::string> tokens;
+  base::SplitString(connection_options, ',', &tokens);
+  // Tokens are expected to be no more than 4 characters long, but we
+  // handle overflow gracefully.
+  for (const std::string& token : tokens) {
+    uint32 option = 0;
+    for (char token_char : base::Reversed(token)) {
+      option <<= 8;
+      option |= static_cast<unsigned char>(token_char);
+    }
+    options.push_back(option);
+  }
+  return options;
+}
+
+// static
 string QuicUtils::StringToHexASCIIDump(StringPiece in_buffer) {
   int offset = 0;
   const int kBytesPerLine = 16;   // Max bytes dumped per line
diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h
index 1ecb37d..2c34ec4 100644
--- a/net/quic/quic_utils.h
+++ b/net/quic/quic_utils.h
@@ -7,6 +7,8 @@
 #ifndef NET_QUIC_QUIC_UTILS_H_
 #define NET_QUIC_QUIC_UTILS_H_
 
+#include <string>
+
 #include "net/base/int128.h"
 #include "net/base/net_export.h"
 #include "net/quic/quic_protocol.h"
@@ -68,6 +70,11 @@
   // if not.
   static std::string TagToString(QuicTag tag);
 
+  // Returns the list of QUIC tags represented by the comma separated
+  // string in |connection_options|.
+  static QuicTagVector ParseQuicConnectionOptions(
+      const std::string& connection_options);
+
   // Given a binary buffer, return a hex+ASCII dump in the style of
   // tcpdump's -X and -XX options:
   // "0x0000:  0090 69bd 5400 000d 610f 0189 0800 4500  ..i.T...a.....E.\n"
diff --git a/net/quic/quic_utils_test.cc b/net/quic/quic_utils_test.cc
index b7d23ed..d2f2631 100644
--- a/net/quic/quic_utils_test.cc
+++ b/net/quic/quic_utils_test.cc
@@ -84,6 +84,20 @@
             QuicUtils::TagToString(MakeQuicTag('C', 'H', 'L', '\x1f')));
 }
 
+TEST(QuicUtilsTest, ParseQuicConnectionOptions) {
+  QuicTagVector empty_options = QuicUtils::ParseQuicConnectionOptions("");
+  EXPECT_EQ(0ul, empty_options.size());
+
+  QuicTagVector parsed_options = QuicUtils::ParseQuicConnectionOptions(
+      "PACE,TIMER,TBBR,REJ");
+  QuicTagVector expected_options;
+  expected_options.push_back(net::kPACE);
+  expected_options.push_back(net::kTIME);
+  expected_options.push_back(net::kTBBR);
+  expected_options.push_back(net::kREJ);
+  EXPECT_EQ(expected_options, parsed_options);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/test_tools/crypto_test_utils_openssl.cc b/net/quic/test_tools/crypto_test_utils_openssl.cc
index 39b48a5..5bcbccb 100644
--- a/net/quic/test_tools/crypto_test_utils_openssl.cc
+++ b/net/quic/test_tools/crypto_test_utils_openssl.cc
@@ -64,9 +64,10 @@
     // The signature consists of a pair of 32-byte numbers.
     static const size_t kSignatureLength = 32 * 2;
     scoped_ptr<uint8[]> signature(new uint8[kSignatureLength]);
-    memset(signature.get(), 0, kSignatureLength);
-    BN_bn2bin(sig.get()->r, signature.get() + 32 - BN_num_bytes(sig.get()->r));
-    BN_bn2bin(sig.get()->s, signature.get() + 64 - BN_num_bytes(sig.get()->s));
+    if (!BN_bn2bin_padded(&signature[0], 32, sig->r) ||
+        !BN_bn2bin_padded(&signature[32], 32, sig->s)) {
+      return false;
+    }
 
     *out_signature = string(reinterpret_cast<char*>(signature.get()),
                             kSignatureLength);
diff --git a/net/socket/next_proto.cc b/net/socket/next_proto.cc
index 4ae4511..0e59ce7 100644
--- a/net/socket/next_proto.cc
+++ b/net/socket/next_proto.cc
@@ -31,13 +31,6 @@
   return next_protos;
 }
 
-NextProtoVector NextProtosSpdy3() {
-  NextProtoVector next_protos;
-  next_protos.push_back(kProtoHTTP11);
-  next_protos.push_back(kProtoQUIC1SPDY3);
-  return next_protos;
-}
-
 NextProtoVector NextProtosSpdy31() {
   NextProtoVector next_protos;
   next_protos.push_back(kProtoHTTP11);
@@ -46,21 +39,13 @@
   return next_protos;
 }
 
-NextProtoVector NextProtosSpdy31WithSpdy2() {
-  NextProtoVector next_protos;
-  next_protos.push_back(kProtoHTTP11);
-  next_protos.push_back(kProtoQUIC1SPDY3);
-  next_protos.push_back(kProtoDeprecatedSPDY2);
-  next_protos.push_back(kProtoSPDY31);
-  return next_protos;
-}
-
 NextProtoVector NextProtosSpdy4Http2() {
   NextProtoVector next_protos;
   next_protos.push_back(kProtoHTTP11);
   next_protos.push_back(kProtoQUIC1SPDY3);
   next_protos.push_back(kProtoSPDY31);
-  next_protos.push_back(kProtoSPDY4);
+  next_protos.push_back(kProtoSPDY4_14);
+  next_protos.push_back(kProtoSPDY4_15);
   return next_protos;
 }
 
diff --git a/net/socket/next_proto.h b/net/socket/next_proto.h
index 465001d..c12a45b 100644
--- a/net/socket/next_proto.h
+++ b/net/socket/next_proto.h
@@ -25,11 +25,14 @@
 
   kProtoDeprecatedSPDY2 = 100,
   kProtoSPDYMinimumVersion = kProtoDeprecatedSPDY2,
+  kProtoSPDYHistogramOffset = kProtoDeprecatedSPDY2,
   kProtoSPDY3 = 101,
   kProtoSPDY31 = 102,
-  // HTTP/2 draft-14 was 103,
-  kProtoSPDY4 = 104,  // SPDY4 is HTTP/2 draft-15.
-  kProtoSPDYMaximumVersion = kProtoSPDY4,
+  kProtoSPDY4_14 = 103,  // HTTP/2 draft-14
+  kProtoSPDY4MinimumVersion = kProtoSPDY4_14,
+  kProtoSPDY4_15 = 104,  // HTTP/2 draft-15
+  kProtoSPDY4MaximumVersion = kProtoSPDY4_15,
+  kProtoSPDYMaximumVersion = kProtoSPDY4MaximumVersion,
 
   kProtoQUIC1SPDY3 = 200,
 
@@ -51,9 +54,7 @@
                                                      bool quic_enabled);
 
 // All of these also enable QUIC.
-NET_EXPORT NextProtoVector NextProtosSpdy3();
 NET_EXPORT NextProtoVector NextProtosSpdy31();
-NET_EXPORT NextProtoVector NextProtosSpdy31WithSpdy2();
 NET_EXPORT NextProtoVector NextProtosSpdy4Http2();
 
 }  // namespace net
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc
index 269ca7e..a52e6a3 100644
--- a/net/socket/ssl_client_socket.cc
+++ b/net/socket/ssl_client_socket.cc
@@ -37,10 +37,13 @@
     return kProtoSPDY3;
   } else if (proto_string == "spdy/3.1") {
     return kProtoSPDY31;
+  } else if (proto_string == "h2-14") {
+    // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
+    // This is the HTTP/2 draft-14 identifier.
+    return kProtoSPDY4_14;
   } else if (proto_string == "h2-15") {
-    // This is the HTTP/2 draft-15 identifier. For internal
-    // consistency, HTTP/2 is named SPDY4 within Chromium.
-    return kProtoSPDY4;
+    // This is the HTTP/2 draft-15 identifier.
+    return kProtoSPDY4_15;
   } else if (proto_string == "quic/1+spdy/3") {
     return kProtoQUIC1SPDY3;
   } else {
@@ -59,9 +62,12 @@
       return "spdy/3";
     case kProtoSPDY31:
       return "spdy/3.1";
-    case kProtoSPDY4:
-      // This is the HTTP/2 draft-15 identifier. For internal
-      // consistency, HTTP/2 is named SPDY4 within Chromium.
+    case kProtoSPDY4_14:
+      // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
+      // This is the HTTP/2 draft-14 identifier.
+      return "h2-14";
+    case kProtoSPDY4_15:
+      // This is the HTTP/2 draft-15 identifier.
       return "h2-15";
     case kProtoQUIC1SPDY3:
       return "quic/1+spdy/3";
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 31a9b8d..3e5bde0 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -218,8 +218,6 @@
   return GetCacheOCSPResponseFromSideChannelFunction() != NULL;
 }
 #else
-// TODO(agl): Figure out if we can plumb the OCSP response into Mac's system
-// certificate validation functions.
 bool IsOCSPStaplingSupported() {
   return false;
 }
@@ -1292,7 +1290,7 @@
   core->client_auth_cert_needed_ = !core->ssl_config_.send_client_cert;
 #if defined(OS_WIN)
   if (core->ssl_config_.send_client_cert) {
-    if (core->ssl_config_.client_cert) {
+    if (core->ssl_config_.client_cert.get()) {
       PCCERT_CONTEXT cert_context =
           core->ssl_config_.client_cert->os_cert_handle();
 
@@ -1630,8 +1628,8 @@
 }
 
 void SSLClientSocketNSS::Core::HandshakeSucceeded() {
-  // TODO(vadimt): Remove ScopedProfile below once crbug.com/424386 is fixed.
-  tracked_objects::ScopedProfile tracking_profile(
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
           "424386 SSLClientSocketNSS::Core::HandshakeSucceeded"));
 
@@ -1661,8 +1659,8 @@
 }
 
 int SSLClientSocketNSS::Core::HandleNSSError(PRErrorCode nss_error) {
-  // TODO(vadimt): Remove ScopedProfile below once crbug.com/424386 is fixed.
-  tracked_objects::ScopedProfile tracking_profile(
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
           "424386 SSLClientSocketNSS::Core::HandleNSSError"));
 
@@ -1687,7 +1685,7 @@
   // re-insert the smart card if not.
   if ((net_error == ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY ||
        net_error == ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED) &&
-      ssl_config_.send_client_cert && ssl_config_.client_cert) {
+      ssl_config_.send_client_cert && ssl_config_.client_cert.get()) {
     CertSetCertificateContextProperty(
         ssl_config_.client_cert->os_cert_handle(),
         CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
@@ -1813,8 +1811,8 @@
   int net_error = OK;
   SECStatus rv = SSL_ForceHandshake(nss_fd_);
 
-  // TODO(vadimt): Remove ScopedProfile below once crbug.com/424386 is fixed.
-  tracked_objects::ScopedProfile tracking_profile1(
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
           "424386 SSLClientSocketNSS::Core::DoHandshake 1"));
 
@@ -2436,11 +2434,9 @@
       reinterpret_cast<char*>(ocsp_responses->items[0].data),
       ocsp_responses->items[0].len);
 
-  // TODO(agl): figure out how to plumb an OCSP response into the Mac
-  // system library and update IsOCSPStaplingSupported for Mac.
   if (IsOCSPStaplingSupported()) {
   #if defined(OS_WIN)
-    if (nss_handshake_state_.server_cert) {
+    if (nss_handshake_state_.server_cert.get()) {
       CRYPT_DATA_BLOB ocsp_response_blob;
       ocsp_response_blob.cbData = ocsp_responses->items[0].len;
       ocsp_response_blob.pbData = ocsp_responses->items[0].data;
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 9fdfe38..57aa619 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -140,6 +140,19 @@
   return 1;
 }
 
+bool IsOCSPStaplingSupported() {
+#if defined(OS_WIN)
+  // CERT_OCSP_RESPONSE_PROP_ID is only implemented on Vista+, but it can be
+  // set on Windows XP without error. There is some overhead from the server
+  // sending the OCSP response if it supports the extension, for the subset of
+  // XP clients who will request it but be unable to use it, but this is an
+  // acceptable trade-off for simplicity of implementation.
+  return true;
+#else
+  return false;
+#endif
+}
+
 }  // namespace
 
 class SSLClientSocketOpenSSL::SSLContext {
@@ -829,8 +842,8 @@
     SSL_enable_ocsp_stapling(ssl_);
   }
 
-  // TODO(davidben): Enable OCSP stapling on platforms which support it and pass
-  // into the certificate verifier. https://crbug.com/398677
+  if (IsOCSPStaplingSupported())
+    SSL_enable_ocsp_stapling(ssl_);
 
   return OK;
 }
@@ -933,10 +946,16 @@
                            ssl_config_.channel_id_enabled,
                            crypto::ECPrivateKey::IsSupported());
 
-    uint8_t* ocsp_response;
-    size_t ocsp_response_len;
-    SSL_get0_ocsp_response(ssl_, &ocsp_response, &ocsp_response_len);
-    set_stapled_ocsp_response_received(ocsp_response_len != 0);
+    // Only record OCSP histograms if OCSP was requested.
+    if (ssl_config_.signed_cert_timestamps_enabled ||
+        IsOCSPStaplingSupported()) {
+      uint8_t* ocsp_response;
+      size_t ocsp_response_len;
+      SSL_get0_ocsp_response(ssl_, &ocsp_response, &ocsp_response_len);
+
+      set_stapled_ocsp_response_received(ocsp_response_len != 0);
+      UMA_HISTOGRAM_BOOLEAN("Net.OCSPResponseStapled", ocsp_response_len != 0);
+    }
 
     uint8_t* sct_list;
     size_t sct_list_len;
@@ -1166,6 +1185,31 @@
         NetLog::TYPE_SSL_CERTIFICATES_RECEIVED,
         base::Bind(&NetLogX509CertificateCallback,
                    base::Unretained(server_cert_.get())));
+
+    // TODO(rsleevi): Plumb an OCSP response into the Mac system library and
+    // update IsOCSPStaplingSupported for Mac. https://crbug.com/430714
+    if (IsOCSPStaplingSupported()) {
+#if defined(OS_WIN)
+      uint8_t* ocsp_response_raw;
+      size_t ocsp_response_len;
+      SSL_get0_ocsp_response(ssl_, &ocsp_response_raw, &ocsp_response_len);
+
+      CRYPT_DATA_BLOB ocsp_response_blob;
+      ocsp_response_blob.cbData = ocsp_response_len;
+      ocsp_response_blob.pbData = ocsp_response_raw;
+      BOOL ok = CertSetCertificateContextProperty(
+          server_cert_->os_cert_handle(),
+          CERT_OCSP_RESPONSE_PROP_ID,
+          CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG,
+          &ocsp_response_blob);
+      if (!ok) {
+        VLOG(1) << "Failed to set OCSP response property: "
+                << GetLastError();
+      }
+#else
+      NOTREACHED();
+#endif
+    }
   }
 }
 
@@ -1567,6 +1611,8 @@
   DVLOG(3) << "OpenSSL ClientCertRequestCallback called";
   DCHECK(ssl == ssl_);
 
+  net_log_.AddEvent(NetLog::TYPE_SSL_CLIENT_CERT_REQUESTED);
+
   // Clear any currently configured certificates.
   SSL_certs_clear(ssl_);
 
@@ -1644,11 +1690,17 @@
       LOG(WARNING) << "Failed to set client certificate";
       return -1;
     }
+
+    int cert_count = 1 + sk_X509_num(chain.get());
+    net_log_.AddEvent(NetLog::TYPE_SSL_CLIENT_CERT_PROVIDED,
+                      NetLog::IntegerCallback("cert_count", cert_count));
     return 1;
   }
 #endif  // defined(OS_IOS)
 
   // Send no client certificate.
+  net_log_.AddEvent(NetLog::TYPE_SSL_CLIENT_CERT_PROVIDED,
+                    NetLog::IntegerCallback("cert_count", 0));
   return 1;
 }
 
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 202cd88..8ac29ef 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -240,7 +240,7 @@
     NextProto,
     SSLClientSocketPoolTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 // Tests that the final socket will connect even if all sockets
 // prior to it fail.
diff --git a/net/socket/tcp_socket_win.cc b/net/socket/tcp_socket_win.cc
index d5565ad..fd3c8b7 100644
--- a/net/socket/tcp_socket_win.cc
+++ b/net/socket/tcp_socket_win.cc
@@ -324,7 +324,7 @@
                                        const IPEndPoint& peer_address) {
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(socket_, INVALID_SOCKET);
-  DCHECK(!core_);
+  DCHECK(!core_.get());
 
   socket_ = socket;
 
@@ -436,7 +436,7 @@
   // again after a connection attempt failed on Windows, it results in
   // unspecified behavior according to POSIX. Therefore, we make it behave in
   // the same way as TCPSocketLibevent.
-  DCHECK(!peer_address_ && !core_);
+  DCHECK(!peer_address_ && !core_.get());
 
   if (!logging_multiple_connect_attempts_)
     LogConnectBegin(AddressList(address));
@@ -504,7 +504,7 @@
   DCHECK_NE(socket_, INVALID_SOCKET);
   DCHECK(!waiting_read_);
   CHECK(read_callback_.is_null());
-  DCHECK(!core_->read_iobuffer_);
+  DCHECK(!core_->read_iobuffer_.get());
 
   return DoRead(buf, buf_len, callback);
 }
@@ -517,7 +517,7 @@
   DCHECK(!waiting_write_);
   CHECK(write_callback_.is_null());
   DCHECK_GT(buf_len, 0);
-  DCHECK(!core_->write_iobuffer_);
+  DCHECK(!core_->write_iobuffer_.get());
 
   base::StatsCounter writes("tcp.writes");
   writes.Increment();
@@ -689,7 +689,7 @@
     accept_event_ = WSA_INVALID_EVENT;
   }
 
-  if (core_) {
+  if (core_.get()) {
     if (waiting_connect_) {
       // We closed the socket, so this notification will never come.
       // From MSDN' WSAEventSelect documentation:
@@ -796,7 +796,7 @@
 
 int TCPSocketWin::DoConnect() {
   DCHECK_EQ(connect_os_error_, 0);
-  DCHECK(!core_);
+  DCHECK(!core_.get());
 
   net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
                       CreateNetLogIPEndPointCallback(peer_address_.get()));
@@ -1018,7 +1018,7 @@
     // DoRead() because recv() reports a more accurate error code
     // (WSAECONNRESET vs. WSAECONNABORTED) when the connection was
     // reset.
-    rv = DoRead(core_->read_iobuffer_, core_->read_buffer_length_,
+    rv = DoRead(core_->read_iobuffer_.get(), core_->read_buffer_length_,
                 read_callback_);
     if (rv == ERR_IO_PENDING)
       return;
diff --git a/net/socket_stream/OWNERS b/net/socket_stream/OWNERS
deleted file mode 100644
index a2bac60..0000000
--- a/net/socket_stream/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tyoshino@chromium.org
diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc
deleted file mode 100644
index 422d61d..0000000
--- a/net/socket_stream/socket_stream.cc
+++ /dev/null
@@ -1,1353 +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.
-//
-// TODO(ukai): code is similar with http_network_transaction.cc.  We should
-//   think about ways to share code, if possible.
-
-#include "net/socket_stream/socket_stream.h"
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "net/base/auth.h"
-#include "net/base/io_buffer.h"
-#include "net/base/load_flags.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_util.h"
-#include "net/dns/host_resolver.h"
-#include "net/http/http_auth_controller.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_request_info.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_stream_factory.h"
-#include "net/http/http_transaction_factory.h"
-#include "net/http/http_util.h"
-#include "net/socket/client_socket_factory.h"
-#include "net/socket/client_socket_handle.h"
-#include "net/socket/socks5_client_socket.h"
-#include "net/socket/socks_client_socket.h"
-#include "net/socket/ssl_client_socket.h"
-#include "net/socket/tcp_client_socket.h"
-#include "net/socket_stream/socket_stream_metrics.h"
-#include "net/ssl/ssl_cert_request_info.h"
-#include "net/ssl/ssl_info.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-
-static const int kMaxPendingSendAllowed = 32768;  // 32 kilobytes.
-static const int kReadBufferSize = 4096;
-
-namespace net {
-
-int SocketStream::Delegate::OnStartOpenConnection(
-    SocketStream* socket, const CompletionCallback& callback) {
-  return OK;
-}
-
-void SocketStream::Delegate::OnAuthRequired(SocketStream* socket,
-                                            AuthChallengeInfo* auth_info) {
-  // By default, no credential is available and close the connection.
-  socket->Close();
-}
-
-void SocketStream::Delegate::OnSSLCertificateError(
-    SocketStream* socket,
-    const SSLInfo& ssl_info,
-    bool fatal) {
-  socket->CancelWithSSLError(ssl_info);
-}
-
-bool SocketStream::Delegate::CanGetCookies(SocketStream* socket,
-                                           const GURL& url) {
-  return true;
-}
-
-bool SocketStream::Delegate::CanSetCookie(SocketStream* request,
-                                          const GURL& url,
-                                          const std::string& cookie_line,
-                                          CookieOptions* options) {
-  return true;
-}
-
-SocketStream::ResponseHeaders::ResponseHeaders() : IOBuffer() {}
-
-void SocketStream::ResponseHeaders::Realloc(size_t new_size) {
-  headers_.reset(static_cast<char*>(realloc(headers_.release(), new_size)));
-}
-
-SocketStream::ResponseHeaders::~ResponseHeaders() { data_ = NULL; }
-
-SocketStream::SocketStream(const GURL& url, Delegate* delegate,
-                           URLRequestContext* context,
-                           CookieStore* cookie_store)
-    : delegate_(delegate),
-      url_(url),
-      max_pending_send_allowed_(kMaxPendingSendAllowed),
-      context_(context),
-      next_state_(STATE_NONE),
-      factory_(ClientSocketFactory::GetDefaultFactory()),
-      proxy_mode_(kDirectConnection),
-      proxy_url_(url),
-      pac_request_(NULL),
-      connection_(new ClientSocketHandle),
-      privacy_mode_(PRIVACY_MODE_DISABLED),
-      // Unretained() is required; without it, Bind() creates a circular
-      // dependency and the SocketStream object will not be freed.
-      io_callback_(base::Bind(&SocketStream::OnIOCompleted,
-                              base::Unretained(this))),
-      read_buf_(NULL),
-      current_write_buf_(NULL),
-      waiting_for_write_completion_(false),
-      closing_(false),
-      server_closed_(false),
-      metrics_(new SocketStreamMetrics(url)),
-      cookie_store_(cookie_store) {
-  DCHECK(base::MessageLoop::current())
-      << "The current base::MessageLoop must exist";
-  DCHECK(base::MessageLoopForIO::IsCurrent())
-      << "The current base::MessageLoop must be TYPE_IO";
-  DCHECK(delegate_);
-
-  if (context_) {
-    if (!cookie_store_.get())
-      cookie_store_ = context_->cookie_store();
-
-    net_log_ = BoundNetLog::Make(
-        context->net_log(),
-        NetLog::SOURCE_SOCKET_STREAM);
-
-    net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE);
-  }
-}
-
-SocketStream::UserData* SocketStream::GetUserData(
-    const void* key) const {
-  UserDataMap::const_iterator found = user_data_.find(key);
-  if (found != user_data_.end())
-    return found->second.get();
-  return NULL;
-}
-
-void SocketStream::SetUserData(const void* key, UserData* data) {
-  user_data_[key] = linked_ptr<UserData>(data);
-}
-
-bool SocketStream::is_secure() const {
-  return url_.SchemeIs("wss");
-}
-
-void SocketStream::DetachContext() {
-  if (!context_)
-    return;
-
-  if (pac_request_) {
-    context_->proxy_service()->CancelPacRequest(pac_request_);
-    pac_request_ = NULL;
-  }
-
-  net_log_.EndEvent(NetLog::TYPE_REQUEST_ALIVE);
-  net_log_ = BoundNetLog();
-
-  context_ = NULL;
-  cookie_store_ = NULL;
-}
-
-void SocketStream::CheckPrivacyMode() {
-  if (context_ && context_->network_delegate()) {
-    bool enable = context_->network_delegate()->CanEnablePrivacyMode(url_,
-                                                                     url_);
-    privacy_mode_ = enable ? PRIVACY_MODE_ENABLED : PRIVACY_MODE_DISABLED;
-    // Disable Channel ID if privacy mode is enabled.
-    if (enable)
-      server_ssl_config_.channel_id_enabled = false;
-  }
-}
-
-void SocketStream::Connect() {
-  DCHECK(base::MessageLoop::current())
-      << "The current base::MessageLoop must exist";
-  DCHECK(base::MessageLoopForIO::IsCurrent())
-      << "The current base::MessageLoop must be TYPE_IO";
-  if (context_) {
-    context_->ssl_config_service()->GetSSLConfig(&server_ssl_config_);
-    proxy_ssl_config_ = server_ssl_config_;
-  }
-  CheckPrivacyMode();
-
-  DCHECK_EQ(next_state_, STATE_NONE);
-
-  AddRef();  // Released in Finish()
-  // Open a connection asynchronously, so that delegate won't be called
-  // back before returning Connect().
-  next_state_ = STATE_BEFORE_CONNECT;
-  net_log_.BeginEvent(
-      NetLog::TYPE_SOCKET_STREAM_CONNECT,
-      NetLog::StringCallback("url", &url_.possibly_invalid_spec()));
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK));
-}
-
-size_t SocketStream::GetTotalSizeOfPendingWriteBufs() const {
-  size_t total_size = 0;
-  for (PendingDataQueue::const_iterator iter = pending_write_bufs_.begin();
-       iter != pending_write_bufs_.end();
-       ++iter)
-    total_size += (*iter)->size();
-  return total_size;
-}
-
-bool SocketStream::SendData(const char* data, int len) {
-  DCHECK(base::MessageLoop::current())
-      << "The current base::MessageLoop must exist";
-  DCHECK(base::MessageLoopForIO::IsCurrent())
-      << "The current base::MessageLoop must be TYPE_IO";
-  DCHECK_GT(len, 0);
-
-  if (!connection_->socket() ||
-      !connection_->socket()->IsConnected() || next_state_ == STATE_NONE) {
-    return false;
-  }
-
-  int total_buffered_bytes = len;
-  if (current_write_buf_.get()) {
-    // Since
-    // - the purpose of this check is to limit the amount of buffer used by
-    //   this instance.
-    // - the DrainableIOBuffer doesn't release consumed memory.
-    // we need to use not BytesRemaining() but size() here.
-    total_buffered_bytes += current_write_buf_->size();
-  }
-  total_buffered_bytes += GetTotalSizeOfPendingWriteBufs();
-  if (total_buffered_bytes > max_pending_send_allowed_)
-    return false;
-
-  // TODO(tyoshino): Split data into smaller chunks e.g. 8KiB to free consumed
-  // buffer progressively
-  pending_write_bufs_.push_back(make_scoped_refptr(
-      new IOBufferWithSize(len)));
-  memcpy(pending_write_bufs_.back()->data(), data, len);
-
-  // If current_write_buf_ is not NULL, it means that a) there's ongoing write
-  // operation or b) the connection is being closed. If a), the buffer we just
-  // pushed will be automatically handled when the completion callback runs
-  // the loop, and therefore we don't need to enqueue DoLoop(). If b), it's ok
-  // to do nothing. If current_write_buf_ is NULL, to make sure DoLoop() is
-  // ran soon, enequeue it.
-  if (!current_write_buf_.get()) {
-    // Send pending data asynchronously, so that delegate won't be called
-    // back before returning from SendData().
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK));
-  }
-
-  return true;
-}
-
-void SocketStream::Close() {
-  DCHECK(base::MessageLoop::current())
-      << "The current base::MessageLoop must exist";
-  DCHECK(base::MessageLoopForIO::IsCurrent())
-      << "The current base::MessageLoop must be TYPE_IO";
-  // If next_state_ is STATE_NONE, the socket was not opened, or already
-  // closed.  So, return immediately.
-  // Otherwise, it might call Finish() more than once, so breaks balance
-  // of AddRef() and Release() in Connect() and Finish(), respectively.
-  if (next_state_ == STATE_NONE)
-    return;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&SocketStream::DoClose, this));
-}
-
-void SocketStream::RestartWithAuth(const AuthCredentials& credentials) {
-  DCHECK(base::MessageLoop::current())
-      << "The current base::MessageLoop must exist";
-  DCHECK(base::MessageLoopForIO::IsCurrent())
-      << "The current base::MessageLoop must be TYPE_IO";
-  DCHECK(proxy_auth_controller_.get());
-  if (!connection_->socket()) {
-    DVLOG(1) << "Socket is closed before restarting with auth.";
-    return;
-  }
-
-  proxy_auth_controller_->ResetAuth(credentials);
-
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&SocketStream::DoRestartWithAuth, this));
-}
-
-void SocketStream::DetachDelegate() {
-  if (!delegate_)
-    return;
-  delegate_ = NULL;
-  // Prevent the rest of the function from executing if we are being called from
-  // within Finish().
-  if (next_state_ == STATE_NONE)
-    return;
-  net_log_.AddEvent(NetLog::TYPE_CANCELLED);
-  // We don't need to send pending data when client detach the delegate.
-  pending_write_bufs_.clear();
-  Close();
-}
-
-const ProxyServer& SocketStream::proxy_server() const {
-  return proxy_info_.proxy_server();
-}
-
-void SocketStream::SetClientSocketFactory(
-    ClientSocketFactory* factory) {
-  DCHECK(factory);
-  factory_ = factory;
-}
-
-void SocketStream::CancelWithError(int error) {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&SocketStream::DoLoop, this, error));
-}
-
-void SocketStream::CancelWithSSLError(const SSLInfo& ssl_info) {
-  CancelWithError(MapCertStatusToNetError(ssl_info.cert_status));
-}
-
-void SocketStream::ContinueDespiteError() {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK));
-}
-
-SocketStream::~SocketStream() {
-  DetachContext();
-  DCHECK(!delegate_);
-  DCHECK(!pac_request_);
-}
-
-SocketStream::RequestHeaders::~RequestHeaders() { data_ = NULL; }
-
-void SocketStream::set_addresses(const AddressList& addresses) {
-  addresses_ = addresses;
-}
-
-void SocketStream::DoClose() {
-  closing_ = true;
-  // If next_state_ is:
-  // - STATE_TCP_CONNECT_COMPLETE, it's waiting other socket establishing
-  //   connection.
-  // - STATE_AUTH_REQUIRED, it's waiting for restarting.
-  // - STATE_RESOLVE_PROTOCOL_COMPLETE, it's waiting for delegate_ to finish
-  //   OnStartOpenConnection method call
-  // In these states, we'll close the SocketStream now.
-  if (next_state_ == STATE_TCP_CONNECT_COMPLETE ||
-      next_state_ == STATE_AUTH_REQUIRED ||
-      next_state_ == STATE_RESOLVE_PROTOCOL_COMPLETE) {
-    DoLoop(ERR_ABORTED);
-    return;
-  }
-  // If next_state_ is STATE_READ_WRITE, we'll run DoLoop and close
-  // the SocketStream.
-  // If it's writing now, we should defer the closing after the current
-  // writing is completed.
-  if (next_state_ == STATE_READ_WRITE && !current_write_buf_.get())
-    DoLoop(ERR_ABORTED);
-
-  // In other next_state_, we'll wait for callback of other APIs, such as
-  // ResolveProxy().
-}
-
-void SocketStream::Finish(int result) {
-  DCHECK(base::MessageLoop::current())
-      << "The current base::MessageLoop must exist";
-  DCHECK(base::MessageLoopForIO::IsCurrent())
-      << "The current base::MessageLoop must be TYPE_IO";
-  DCHECK_LE(result, OK);
-  if (result == OK)
-    result = ERR_CONNECTION_CLOSED;
-  DCHECK_EQ(next_state_, STATE_NONE);
-  DVLOG(1) << "Finish result=" << ErrorToString(result);
-
-  metrics_->OnClose();
-
-  if (result != ERR_CONNECTION_CLOSED && delegate_)
-    delegate_->OnError(this, result);
-  if (result != ERR_PROTOCOL_SWITCHED && delegate_)
-    delegate_->OnClose(this);
-  delegate_ = NULL;
-
-  Release();
-}
-
-int SocketStream::DidEstablishConnection() {
-  if (!connection_->socket() || !connection_->socket()->IsConnected()) {
-    next_state_ = STATE_CLOSE;
-    return ERR_CONNECTION_FAILED;
-  }
-  next_state_ = STATE_READ_WRITE;
-  metrics_->OnConnected();
-
-  net_log_.EndEvent(NetLog::TYPE_SOCKET_STREAM_CONNECT);
-  if (delegate_)
-    delegate_->OnConnected(this, max_pending_send_allowed_);
-
-  return OK;
-}
-
-int SocketStream::DidReceiveData(int result) {
-  DCHECK(read_buf_.get());
-  DCHECK_GT(result, 0);
-  net_log_.AddEvent(NetLog::TYPE_SOCKET_STREAM_RECEIVED);
-  int len = result;
-  metrics_->OnRead(len);
-  if (delegate_) {
-    // Notify recevied data to delegate.
-    delegate_->OnReceivedData(this, read_buf_->data(), len);
-  }
-  read_buf_ = NULL;
-  return OK;
-}
-
-void SocketStream::DidSendData(int result) {
-  DCHECK_GT(result, 0);
-  DCHECK(current_write_buf_.get());
-  net_log_.AddEvent(NetLog::TYPE_SOCKET_STREAM_SENT);
-
-  int bytes_sent = result;
-
-  metrics_->OnWrite(bytes_sent);
-
-  current_write_buf_->DidConsume(result);
-
-  if (current_write_buf_->BytesRemaining())
-    return;
-
-  size_t bytes_freed = current_write_buf_->size();
-
-  current_write_buf_ = NULL;
-
-  // We freed current_write_buf_ and this instance is now able to accept more
-  // data via SendData() (note that DidConsume() doesn't free consumed memory).
-  // We can tell that to delegate_ by calling OnSentData().
-  if (delegate_)
-    delegate_->OnSentData(this, bytes_freed);
-}
-
-void SocketStream::OnIOCompleted(int result) {
-  DoLoop(result);
-}
-
-void SocketStream::OnReadCompleted(int result) {
-  if (result == 0) {
-    // 0 indicates end-of-file, so socket was closed.
-    // Don't close the socket if it's still writing.
-    server_closed_ = true;
-  } else if (result > 0 && read_buf_.get()) {
-    result = DidReceiveData(result);
-  }
-  DoLoop(result);
-}
-
-void SocketStream::OnWriteCompleted(int result) {
-  waiting_for_write_completion_ = false;
-  if (result > 0) {
-    DidSendData(result);
-    result = OK;
-  }
-  DoLoop(result);
-}
-
-void SocketStream::DoLoop(int result) {
-  if (next_state_ == STATE_NONE)
-    return;
-
-  // If context was not set, close immediately.
-  if (!context_)
-    next_state_ = STATE_CLOSE;
-
-  do {
-    State state = next_state_;
-    next_state_ = STATE_NONE;
-    switch (state) {
-      case STATE_BEFORE_CONNECT:
-        DCHECK_EQ(OK, result);
-        result = DoBeforeConnect();
-        break;
-      case STATE_BEFORE_CONNECT_COMPLETE:
-        result = DoBeforeConnectComplete(result);
-        break;
-      case STATE_RESOLVE_PROXY:
-        DCHECK_EQ(OK, result);
-        result = DoResolveProxy();
-        break;
-      case STATE_RESOLVE_PROXY_COMPLETE:
-        result = DoResolveProxyComplete(result);
-        break;
-      case STATE_RESOLVE_HOST:
-        DCHECK_EQ(OK, result);
-        result = DoResolveHost();
-        break;
-      case STATE_RESOLVE_HOST_COMPLETE:
-        result = DoResolveHostComplete(result);
-        break;
-      case STATE_RESOLVE_PROTOCOL:
-        result = DoResolveProtocol(result);
-        break;
-      case STATE_RESOLVE_PROTOCOL_COMPLETE:
-        result = DoResolveProtocolComplete(result);
-        break;
-      case STATE_TCP_CONNECT:
-        result = DoTcpConnect(result);
-        break;
-      case STATE_TCP_CONNECT_COMPLETE:
-        result = DoTcpConnectComplete(result);
-        break;
-      case STATE_GENERATE_PROXY_AUTH_TOKEN:
-        result = DoGenerateProxyAuthToken();
-        break;
-      case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
-        result = DoGenerateProxyAuthTokenComplete(result);
-        break;
-      case STATE_WRITE_TUNNEL_HEADERS:
-        DCHECK_EQ(OK, result);
-        result = DoWriteTunnelHeaders();
-        break;
-      case STATE_WRITE_TUNNEL_HEADERS_COMPLETE:
-        result = DoWriteTunnelHeadersComplete(result);
-        break;
-      case STATE_READ_TUNNEL_HEADERS:
-        DCHECK_EQ(OK, result);
-        result = DoReadTunnelHeaders();
-        break;
-      case STATE_READ_TUNNEL_HEADERS_COMPLETE:
-        result = DoReadTunnelHeadersComplete(result);
-        break;
-      case STATE_SOCKS_CONNECT:
-        DCHECK_EQ(OK, result);
-        result = DoSOCKSConnect();
-        break;
-      case STATE_SOCKS_CONNECT_COMPLETE:
-        result = DoSOCKSConnectComplete(result);
-        break;
-      case STATE_SECURE_PROXY_CONNECT:
-        DCHECK_EQ(OK, result);
-        result = DoSecureProxyConnect();
-        break;
-      case STATE_SECURE_PROXY_CONNECT_COMPLETE:
-        result = DoSecureProxyConnectComplete(result);
-        break;
-      case STATE_SECURE_PROXY_HANDLE_CERT_ERROR:
-        result = DoSecureProxyHandleCertError(result);
-        break;
-      case STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE:
-        result = DoSecureProxyHandleCertErrorComplete(result);
-        break;
-      case STATE_SSL_CONNECT:
-        DCHECK_EQ(OK, result);
-        result = DoSSLConnect();
-        break;
-      case STATE_SSL_CONNECT_COMPLETE:
-        result = DoSSLConnectComplete(result);
-        break;
-      case STATE_SSL_HANDLE_CERT_ERROR:
-        result = DoSSLHandleCertError(result);
-        break;
-      case STATE_SSL_HANDLE_CERT_ERROR_COMPLETE:
-        result = DoSSLHandleCertErrorComplete(result);
-        break;
-      case STATE_READ_WRITE:
-        result = DoReadWrite(result);
-        break;
-      case STATE_AUTH_REQUIRED:
-        // It might be called when DoClose is called while waiting in
-        // STATE_AUTH_REQUIRED.
-        Finish(result);
-        return;
-      case STATE_CLOSE:
-        DCHECK_LE(result, OK);
-        Finish(result);
-        return;
-      default:
-        NOTREACHED() << "bad state " << state;
-        Finish(result);
-        return;
-    }
-    if (state == STATE_RESOLVE_PROTOCOL && result == ERR_PROTOCOL_SWITCHED)
-      continue;
-    // If the connection is not established yet and had actual errors,
-    // record the error.  In next iteration, it will close the connection.
-    if (state != STATE_READ_WRITE && result < ERR_IO_PENDING) {
-      net_log_.EndEventWithNetErrorCode(
-          NetLog::TYPE_SOCKET_STREAM_CONNECT, result);
-    }
-  } while (result != ERR_IO_PENDING);
-}
-
-int SocketStream::DoBeforeConnect() {
-  next_state_ = STATE_BEFORE_CONNECT_COMPLETE;
-  if (!context_ || !context_->network_delegate())
-    return OK;
-
-  int result = context_->network_delegate()->NotifyBeforeSocketStreamConnect(
-      this, io_callback_);
-  if (result != OK && result != ERR_IO_PENDING)
-    next_state_ = STATE_CLOSE;
-
-  return result;
-}
-
-int SocketStream::DoBeforeConnectComplete(int result) {
-  DCHECK_NE(ERR_IO_PENDING, result);
-
-  if (result == OK)
-    next_state_ = STATE_RESOLVE_PROXY;
-  else
-    next_state_ = STATE_CLOSE;
-
-  return result;
-}
-
-int SocketStream::DoResolveProxy() {
-  DCHECK(context_);
-  DCHECK(!pac_request_);
-  next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
-
-  if (!proxy_url_.is_valid()) {
-    next_state_ = STATE_CLOSE;
-    return ERR_INVALID_ARGUMENT;
-  }
-
-  // TODO(toyoshim): Check server advertisement of SPDY through the HTTP
-  // Alternate-Protocol header, then switch to SPDY if SPDY is available.
-  // Usually we already have a session to the SPDY server because JavaScript
-  // running WebSocket itself would be served by SPDY. But, in some situation
-  // (E.g. Used by Chrome Extensions or used for cross origin connection), this
-  // connection might be the first one. At that time, we should check
-  // Alternate-Protocol header here for ws:// or TLS NPN extension for wss:// .
-
-  return context_->proxy_service()->ResolveProxy(
-      proxy_url_, net::LOAD_NORMAL, &proxy_info_, io_callback_, &pac_request_,
-      NULL, net_log_);
-}
-
-int SocketStream::DoResolveProxyComplete(int result) {
-  pac_request_ = NULL;
-  if (result != OK) {
-    DVLOG(1) << "Failed to resolve proxy: " << result;
-    if (delegate_)
-      delegate_->OnError(this, result);
-    proxy_info_.UseDirect();
-  }
-  if (proxy_info_.is_direct()) {
-    // If proxy was not found for original URL (i.e. websocket URL),
-    // try again with https URL, like Safari implementation.
-    // Note that we don't want to use http proxy, because we'll use tunnel
-    // proxy using CONNECT method, which is used by https proxy.
-    if (!proxy_url_.SchemeIs("https")) {
-      const std::string scheme = "https";
-      GURL::Replacements repl;
-      repl.SetSchemeStr(scheme);
-      proxy_url_ = url_.ReplaceComponents(repl);
-      DVLOG(1) << "Try https proxy: " << proxy_url_;
-      next_state_ = STATE_RESOLVE_PROXY;
-      return OK;
-    }
-  }
-
-  if (proxy_info_.is_empty()) {
-    // No proxies/direct to choose from. This happens when we don't support any
-    // of the proxies in the returned list.
-    return ERR_NO_SUPPORTED_PROXIES;
-  }
-
-  next_state_ = STATE_RESOLVE_HOST;
-  return OK;
-}
-
-int SocketStream::DoResolveHost() {
-  next_state_ = STATE_RESOLVE_HOST_COMPLETE;
-
-  DCHECK(!proxy_info_.is_empty());
-  if (proxy_info_.is_direct())
-    proxy_mode_ = kDirectConnection;
-  else if (proxy_info_.proxy_server().is_socks())
-    proxy_mode_ = kSOCKSProxy;
-  else
-    proxy_mode_ = kTunnelProxy;
-
-  // Determine the host and port to connect to.
-  HostPortPair host_port_pair;
-  if (proxy_mode_ != kDirectConnection) {
-    host_port_pair = proxy_info_.proxy_server().host_port_pair();
-  } else {
-    host_port_pair = HostPortPair::FromURL(url_);
-  }
-
-  HostResolver::RequestInfo resolve_info(host_port_pair);
-
-  DCHECK(context_->host_resolver());
-  resolver_.reset(new SingleRequestHostResolver(context_->host_resolver()));
-  return resolver_->Resolve(resolve_info,
-                            DEFAULT_PRIORITY,
-                            &addresses_,
-                            base::Bind(&SocketStream::OnIOCompleted, this),
-                            net_log_);
-}
-
-int SocketStream::DoResolveHostComplete(int result) {
-  if (result == OK)
-    next_state_ = STATE_RESOLVE_PROTOCOL;
-  else
-    next_state_ = STATE_CLOSE;
-  // TODO(ukai): if error occured, reconsider proxy after error.
-  return result;
-}
-
-int SocketStream::DoResolveProtocol(int result) {
-  DCHECK_EQ(OK, result);
-
-  if (!delegate_) {
-    next_state_ = STATE_CLOSE;
-    return result;
-  }
-
-  next_state_ = STATE_RESOLVE_PROTOCOL_COMPLETE;
-  result = delegate_->OnStartOpenConnection(this, io_callback_);
-  if (result == ERR_IO_PENDING)
-    metrics_->OnWaitConnection();
-  else if (result != OK && result != ERR_PROTOCOL_SWITCHED)
-    next_state_ = STATE_CLOSE;
-  return result;
-}
-
-int SocketStream::DoResolveProtocolComplete(int result) {
-  DCHECK_NE(ERR_IO_PENDING, result);
-
-  if (result == ERR_PROTOCOL_SWITCHED) {
-    next_state_ = STATE_CLOSE;
-    metrics_->OnCountWireProtocolType(
-        SocketStreamMetrics::WIRE_PROTOCOL_SPDY);
-  } else if (result == OK) {
-    next_state_ = STATE_TCP_CONNECT;
-    metrics_->OnCountWireProtocolType(
-        SocketStreamMetrics::WIRE_PROTOCOL_WEBSOCKET);
-  } else {
-    next_state_ = STATE_CLOSE;
-  }
-  return result;
-}
-
-int SocketStream::DoTcpConnect(int result) {
-  if (result != OK) {
-    next_state_ = STATE_CLOSE;
-    return result;
-  }
-  next_state_ = STATE_TCP_CONNECT_COMPLETE;
-  DCHECK(factory_);
-  connection_->SetSocket(
-      factory_->CreateTransportClientSocket(addresses_,
-                                            net_log_.net_log(),
-                                            net_log_.source()));
-  metrics_->OnStartConnection();
-  return connection_->socket()->Connect(io_callback_);
-}
-
-int SocketStream::DoTcpConnectComplete(int result) {
-  // TODO(ukai): if error occured, reconsider proxy after error.
-  if (result != OK) {
-    next_state_ = STATE_CLOSE;
-    return result;
-  }
-
-  if (proxy_mode_ == kTunnelProxy) {
-    if (proxy_info_.is_https())
-      next_state_ = STATE_SECURE_PROXY_CONNECT;
-    else
-      next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
-  } else if (proxy_mode_ == kSOCKSProxy) {
-    next_state_ = STATE_SOCKS_CONNECT;
-  } else if (is_secure()) {
-    next_state_ = STATE_SSL_CONNECT;
-  } else {
-    result = DidEstablishConnection();
-  }
-  return result;
-}
-
-int SocketStream::DoGenerateProxyAuthToken() {
-  next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE;
-  if (!proxy_auth_controller_.get()) {
-    DCHECK(context_);
-    DCHECK(context_->http_transaction_factory());
-    DCHECK(context_->http_transaction_factory()->GetSession());
-    HttpNetworkSession* session =
-        context_->http_transaction_factory()->GetSession();
-    const char* scheme = proxy_info_.is_https() ? "https://" : "http://";
-    GURL auth_url(scheme +
-                  proxy_info_.proxy_server().host_port_pair().ToString());
-    proxy_auth_controller_ =
-        new HttpAuthController(HttpAuth::AUTH_PROXY,
-                               auth_url,
-                               session->http_auth_cache(),
-                               session->http_auth_handler_factory());
-  }
-  HttpRequestInfo request_info;
-  request_info.url = url_;
-  request_info.method = "CONNECT";
-  return proxy_auth_controller_->MaybeGenerateAuthToken(
-      &request_info, io_callback_, net_log_);
-}
-
-int SocketStream::DoGenerateProxyAuthTokenComplete(int result) {
-  if (result != OK) {
-    next_state_ = STATE_CLOSE;
-    return result;
-  }
-
-  next_state_ = STATE_WRITE_TUNNEL_HEADERS;
-  return result;
-}
-
-int SocketStream::DoWriteTunnelHeaders() {
-  DCHECK_EQ(kTunnelProxy, proxy_mode_);
-
-  next_state_ = STATE_WRITE_TUNNEL_HEADERS_COMPLETE;
-
-  if (!tunnel_request_headers_.get()) {
-    metrics_->OnCountConnectionType(SocketStreamMetrics::TUNNEL_CONNECTION);
-    tunnel_request_headers_ = new RequestHeaders();
-    tunnel_request_headers_bytes_sent_ = 0;
-  }
-  if (tunnel_request_headers_->headers_.empty()) {
-    HttpRequestHeaders request_headers;
-    request_headers.SetHeader("Host", GetHostAndOptionalPort(url_));
-    request_headers.SetHeader("Proxy-Connection", "keep-alive");
-    if (proxy_auth_controller_.get() && proxy_auth_controller_->HaveAuth())
-      proxy_auth_controller_->AddAuthorizationHeader(&request_headers);
-    tunnel_request_headers_->headers_ = base::StringPrintf(
-        "CONNECT %s HTTP/1.1\r\n"
-        "%s",
-        GetHostAndPort(url_).c_str(),
-        request_headers.ToString().c_str());
-  }
-  tunnel_request_headers_->SetDataOffset(tunnel_request_headers_bytes_sent_);
-  int buf_len = static_cast<int>(tunnel_request_headers_->headers_.size() -
-                                 tunnel_request_headers_bytes_sent_);
-  DCHECK_GT(buf_len, 0);
-  return connection_->socket()->Write(
-      tunnel_request_headers_.get(), buf_len, io_callback_);
-}
-
-int SocketStream::DoWriteTunnelHeadersComplete(int result) {
-  DCHECK_EQ(kTunnelProxy, proxy_mode_);
-
-  if (result < 0) {
-    next_state_ = STATE_CLOSE;
-    return result;
-  }
-
-  tunnel_request_headers_bytes_sent_ += result;
-  if (tunnel_request_headers_bytes_sent_ <
-      tunnel_request_headers_->headers_.size()) {
-    next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
-  } else {
-    // Handling a cert error or a client cert request requires reconnection.
-    // DoWriteTunnelHeaders() will be called again.
-    // Thus |tunnel_request_headers_bytes_sent_| should be reset to 0 for
-    // sending |tunnel_request_headers_| correctly.
-    tunnel_request_headers_bytes_sent_ = 0;
-    next_state_ = STATE_READ_TUNNEL_HEADERS;
-  }
-  return OK;
-}
-
-int SocketStream::DoReadTunnelHeaders() {
-  DCHECK_EQ(kTunnelProxy, proxy_mode_);
-
-  next_state_ = STATE_READ_TUNNEL_HEADERS_COMPLETE;
-
-  if (!tunnel_response_headers_.get()) {
-    tunnel_response_headers_ = new ResponseHeaders();
-    tunnel_response_headers_capacity_ = kMaxTunnelResponseHeadersSize;
-    tunnel_response_headers_->Realloc(tunnel_response_headers_capacity_);
-    tunnel_response_headers_len_ = 0;
-  }
-
-  int buf_len = tunnel_response_headers_capacity_ -
-      tunnel_response_headers_len_;
-  tunnel_response_headers_->SetDataOffset(tunnel_response_headers_len_);
-  CHECK(tunnel_response_headers_->data());
-
-  return connection_->socket()->Read(
-      tunnel_response_headers_.get(), buf_len, io_callback_);
-}
-
-int SocketStream::DoReadTunnelHeadersComplete(int result) {
-  DCHECK_EQ(kTunnelProxy, proxy_mode_);
-
-  if (result < 0) {
-    next_state_ = STATE_CLOSE;
-    return result;
-  }
-
-  if (result == 0) {
-    // 0 indicates end-of-file, so socket was closed.
-    next_state_ = STATE_CLOSE;
-    return ERR_CONNECTION_CLOSED;
-  }
-
-  tunnel_response_headers_len_ += result;
-  DCHECK(tunnel_response_headers_len_ <= tunnel_response_headers_capacity_);
-
-  int eoh = HttpUtil::LocateEndOfHeaders(
-      tunnel_response_headers_->headers(), tunnel_response_headers_len_, 0);
-  if (eoh == -1) {
-    if (tunnel_response_headers_len_ >= kMaxTunnelResponseHeadersSize) {
-      next_state_ = STATE_CLOSE;
-      return ERR_RESPONSE_HEADERS_TOO_BIG;
-    }
-
-    next_state_ = STATE_READ_TUNNEL_HEADERS;
-    return OK;
-  }
-  // DidReadResponseHeaders
-  scoped_refptr<HttpResponseHeaders> headers;
-  headers = new HttpResponseHeaders(
-      HttpUtil::AssembleRawHeaders(tunnel_response_headers_->headers(), eoh));
-  if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
-    // Require the "HTTP/1.x" status line.
-    next_state_ = STATE_CLOSE;
-    return ERR_TUNNEL_CONNECTION_FAILED;
-  }
-  switch (headers->response_code()) {
-    case 200:  // OK
-      if (is_secure()) {
-        DCHECK_EQ(eoh, tunnel_response_headers_len_);
-        next_state_ = STATE_SSL_CONNECT;
-      } else {
-        result = DidEstablishConnection();
-        if (result < 0) {
-          next_state_ = STATE_CLOSE;
-          return result;
-        }
-        if ((eoh < tunnel_response_headers_len_) && delegate_)
-          delegate_->OnReceivedData(
-              this, tunnel_response_headers_->headers() + eoh,
-              tunnel_response_headers_len_ - eoh);
-      }
-      return OK;
-    case 407:  // Proxy Authentication Required.
-      if (proxy_mode_ != kTunnelProxy)
-        return ERR_UNEXPECTED_PROXY_AUTH;
-
-      result = proxy_auth_controller_->HandleAuthChallenge(
-          headers, false, true, net_log_);
-      if (result != OK)
-        return result;
-      DCHECK(!proxy_info_.is_empty());
-      next_state_ = STATE_AUTH_REQUIRED;
-      if (proxy_auth_controller_->HaveAuth()) {
-        base::MessageLoop::current()->PostTask(
-            FROM_HERE, base::Bind(&SocketStream::DoRestartWithAuth, this));
-        return ERR_IO_PENDING;
-      }
-      if (delegate_) {
-        // Wait until RestartWithAuth or Close is called.
-        base::MessageLoop::current()->PostTask(
-            FROM_HERE, base::Bind(&SocketStream::DoAuthRequired, this));
-        return ERR_IO_PENDING;
-      }
-      break;
-    default:
-      break;
-  }
-  next_state_ = STATE_CLOSE;
-  return ERR_TUNNEL_CONNECTION_FAILED;
-}
-
-int SocketStream::DoSOCKSConnect() {
-  DCHECK_EQ(kSOCKSProxy, proxy_mode_);
-
-  next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
-
-  HostResolver::RequestInfo req_info(HostPortPair::FromURL(url_));
-
-  DCHECK(!proxy_info_.is_empty());
-  scoped_ptr<StreamSocket> s;
-  if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5) {
-    s.reset(new SOCKS5ClientSocket(connection_.Pass(), req_info));
-  } else {
-    s.reset(new SOCKSClientSocket(connection_.Pass(),
-                                  req_info,
-                                  DEFAULT_PRIORITY,
-                                  context_->host_resolver()));
-  }
-  connection_.reset(new ClientSocketHandle);
-  connection_->SetSocket(s.Pass());
-  metrics_->OnCountConnectionType(SocketStreamMetrics::SOCKS_CONNECTION);
-  return connection_->socket()->Connect(io_callback_);
-}
-
-int SocketStream::DoSOCKSConnectComplete(int result) {
-  DCHECK_EQ(kSOCKSProxy, proxy_mode_);
-
-  if (result == OK) {
-    if (is_secure())
-      next_state_ = STATE_SSL_CONNECT;
-    else
-      result = DidEstablishConnection();
-  } else {
-    next_state_ = STATE_CLOSE;
-  }
-  return result;
-}
-
-int SocketStream::DoSecureProxyConnect() {
-  DCHECK(factory_);
-  SSLClientSocketContext ssl_context;
-  ssl_context.cert_verifier = context_->cert_verifier();
-  ssl_context.transport_security_state = context_->transport_security_state();
-  ssl_context.channel_id_service = context_->channel_id_service();
-  scoped_ptr<StreamSocket> socket(factory_->CreateSSLClientSocket(
-      connection_.Pass(),
-      proxy_info_.proxy_server().host_port_pair(),
-      proxy_ssl_config_,
-      ssl_context));
-  connection_.reset(new ClientSocketHandle);
-  connection_->SetSocket(socket.Pass());
-  next_state_ = STATE_SECURE_PROXY_CONNECT_COMPLETE;
-  metrics_->OnCountConnectionType(SocketStreamMetrics::SECURE_PROXY_CONNECTION);
-  return connection_->socket()->Connect(io_callback_);
-}
-
-int SocketStream::DoSecureProxyConnectComplete(int result) {
-  DCHECK_EQ(STATE_NONE, next_state_);
-  // Reconnect with client authentication.
-  if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED)
-    return HandleCertificateRequest(result, &proxy_ssl_config_);
-
-  if (IsCertificateError(result))
-    next_state_ = STATE_SECURE_PROXY_HANDLE_CERT_ERROR;
-  else if (result == OK)
-    next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
-  else
-    next_state_ = STATE_CLOSE;
-  return result;
-}
-
-int SocketStream::DoSecureProxyHandleCertError(int result) {
-  DCHECK_EQ(STATE_NONE, next_state_);
-  DCHECK(IsCertificateError(result));
-  result = HandleCertificateError(result);
-  if (result == ERR_IO_PENDING)
-    next_state_ = STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE;
-  else
-    next_state_ = STATE_CLOSE;
-  return result;
-}
-
-int SocketStream::DoSecureProxyHandleCertErrorComplete(int result) {
-  DCHECK_EQ(STATE_NONE, next_state_);
-  if (result == OK) {
-    if (!connection_->socket()->IsConnectedAndIdle())
-      return AllowCertErrorForReconnection(&proxy_ssl_config_);
-    next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
-  } else {
-    next_state_ = STATE_CLOSE;
-  }
-  return result;
-}
-
-int SocketStream::DoSSLConnect() {
-  DCHECK(factory_);
-  SSLClientSocketContext ssl_context;
-  ssl_context.cert_verifier = context_->cert_verifier();
-  ssl_context.transport_security_state = context_->transport_security_state();
-  ssl_context.channel_id_service = context_->channel_id_service();
-  scoped_ptr<StreamSocket> socket(
-      factory_->CreateSSLClientSocket(connection_.Pass(),
-                                      HostPortPair::FromURL(url_),
-                                      server_ssl_config_,
-                                      ssl_context));
-  connection_.reset(new ClientSocketHandle);
-  connection_->SetSocket(socket.Pass());
-  next_state_ = STATE_SSL_CONNECT_COMPLETE;
-  metrics_->OnCountConnectionType(SocketStreamMetrics::SSL_CONNECTION);
-  return connection_->socket()->Connect(io_callback_);
-}
-
-int SocketStream::DoSSLConnectComplete(int result) {
-  DCHECK_EQ(STATE_NONE, next_state_);
-  // Reconnect with client authentication.
-  if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED)
-    return HandleCertificateRequest(result, &server_ssl_config_);
-
-  if (IsCertificateError(result))
-    next_state_ = STATE_SSL_HANDLE_CERT_ERROR;
-  else if (result == OK)
-    result = DidEstablishConnection();
-  else
-    next_state_ = STATE_CLOSE;
-  return result;
-}
-
-int SocketStream::DoSSLHandleCertError(int result) {
-  DCHECK_EQ(STATE_NONE, next_state_);
-  DCHECK(IsCertificateError(result));
-  result = HandleCertificateError(result);
-  if (result == OK || result == ERR_IO_PENDING)
-    next_state_ = STATE_SSL_HANDLE_CERT_ERROR_COMPLETE;
-  else
-    next_state_ = STATE_CLOSE;
-  return result;
-}
-
-int SocketStream::DoSSLHandleCertErrorComplete(int result) {
-  DCHECK_EQ(STATE_NONE, next_state_);
-  // TODO(toyoshim): Upgrade to SPDY through TLS NPN extension if possible.
-  // If we use HTTPS and this is the first connection to the SPDY server,
-  // we should take care of TLS NPN extension here.
-
-  if (result == OK) {
-    if (!connection_->socket()->IsConnectedAndIdle())
-      return AllowCertErrorForReconnection(&server_ssl_config_);
-    result = DidEstablishConnection();
-  } else {
-    next_state_ = STATE_CLOSE;
-  }
-  return result;
-}
-
-int SocketStream::DoReadWrite(int result) {
-  if (result < OK) {
-    next_state_ = STATE_CLOSE;
-    return result;
-  }
-  if (!connection_->socket() || !connection_->socket()->IsConnected()) {
-    next_state_ = STATE_CLOSE;
-    return ERR_CONNECTION_CLOSED;
-  }
-
-  // If client has requested close(), and there's nothing to write, then
-  // let's close the socket.
-  // We don't care about receiving data after the socket is closed.
-  if (closing_ && !current_write_buf_.get() && pending_write_bufs_.empty()) {
-    connection_->socket()->Disconnect();
-    next_state_ = STATE_CLOSE;
-    return OK;
-  }
-
-  next_state_ = STATE_READ_WRITE;
-
-  // If server already closed the socket, we don't try to read.
-  if (!server_closed_) {
-    if (!read_buf_.get()) {
-      // No read pending and server didn't close the socket.
-      read_buf_ = new IOBuffer(kReadBufferSize);
-      result = connection_->socket()->Read(
-          read_buf_.get(),
-          kReadBufferSize,
-          base::Bind(&SocketStream::OnReadCompleted, base::Unretained(this)));
-      if (result > 0) {
-        return DidReceiveData(result);
-      } else if (result == 0) {
-        // 0 indicates end-of-file, so socket was closed.
-        next_state_ = STATE_CLOSE;
-        server_closed_ = true;
-        return ERR_CONNECTION_CLOSED;
-      }
-      // If read is pending, try write as well.
-      // Otherwise, return the result and do next loop (to close the
-      // connection).
-      if (result != ERR_IO_PENDING) {
-        next_state_ = STATE_CLOSE;
-        server_closed_ = true;
-        return result;
-      }
-    }
-    // Read is pending.
-    DCHECK(read_buf_.get());
-  }
-
-  if (waiting_for_write_completion_)
-    return ERR_IO_PENDING;
-
-  if (!current_write_buf_.get()) {
-    if (pending_write_bufs_.empty()) {
-      // Nothing buffered for send.
-      return ERR_IO_PENDING;
-    }
-
-    current_write_buf_ = new DrainableIOBuffer(
-        pending_write_bufs_.front().get(), pending_write_bufs_.front()->size());
-    pending_write_bufs_.pop_front();
-  }
-
-  result = connection_->socket()->Write(
-      current_write_buf_.get(),
-      current_write_buf_->BytesRemaining(),
-      base::Bind(&SocketStream::OnWriteCompleted, base::Unretained(this)));
-
-  if (result == ERR_IO_PENDING) {
-    waiting_for_write_completion_ = true;
-  } else if (result < 0) {
-    // Shortcut. Enter STATE_CLOSE now by changing next_state_ here than by
-    // calling DoReadWrite() again with the error code.
-    next_state_ = STATE_CLOSE;
-  } else if (result > 0) {
-    // Write is not pending. Return OK and do next loop.
-    DidSendData(result);
-    result = OK;
-  }
-
-  return result;
-}
-
-GURL SocketStream::ProxyAuthOrigin() const {
-  DCHECK(!proxy_info_.is_empty());
-  return GURL("http://" +
-              proxy_info_.proxy_server().host_port_pair().ToString());
-}
-
-int SocketStream::HandleCertificateRequest(int result, SSLConfig* ssl_config) {
-  if (ssl_config->send_client_cert) {
-    // We already have performed SSL client authentication once and failed.
-    return result;
-  }
-
-  DCHECK(connection_->socket());
-  scoped_refptr<SSLCertRequestInfo> cert_request_info = new SSLCertRequestInfo;
-  SSLClientSocket* ssl_socket =
-      static_cast<SSLClientSocket*>(connection_->socket());
-  ssl_socket->GetSSLCertRequestInfo(cert_request_info.get());
-
-  HttpTransactionFactory* factory = context_->http_transaction_factory();
-  if (!factory)
-    return result;
-  scoped_refptr<HttpNetworkSession> session = factory->GetSession();
-  if (!session.get())
-    return result;
-
-  // If the user selected one of the certificates in client_certs or declined
-  // to provide one for this server before, use the past decision
-  // automatically.
-  scoped_refptr<X509Certificate> client_cert;
-  if (!session->ssl_client_auth_cache()->Lookup(
-          cert_request_info->host_and_port, &client_cert)) {
-    return result;
-  }
-
-  // Note: |client_cert| may be NULL, indicating that the caller
-  // wishes to proceed anonymously (eg: continue the handshake
-  // without sending a client cert)
-  //
-  // Check that the certificate selected is still a certificate the server
-  // is likely to accept, based on the criteria supplied in the
-  // CertificateRequest message.
-  const std::vector<std::string>& cert_authorities =
-      cert_request_info->cert_authorities;
-  if (client_cert.get() && !cert_authorities.empty() &&
-      !client_cert->IsIssuedByEncoded(cert_authorities)) {
-    return result;
-  }
-
-  ssl_config->send_client_cert = true;
-  ssl_config->client_cert = client_cert;
-  next_state_ = STATE_TCP_CONNECT;
-  return OK;
-}
-
-int SocketStream::AllowCertErrorForReconnection(SSLConfig* ssl_config) {
-  DCHECK(ssl_config);
-  // The SSL handshake didn't finish, or the server closed the SSL connection.
-  // So, we should restart establishing connection with the certificate in
-  // allowed bad certificates in |ssl_config|.
-  // See also net/http/http_network_transaction.cc HandleCertificateError() and
-  // RestartIgnoringLastError().
-  SSLClientSocket* ssl_socket =
-      static_cast<SSLClientSocket*>(connection_->socket());
-  SSLInfo ssl_info;
-  ssl_socket->GetSSLInfo(&ssl_info);
-  if (ssl_info.cert.get() == NULL ||
-      ssl_config->IsAllowedBadCert(ssl_info.cert.get(), NULL)) {
-    // If we already have the certificate in the set of allowed bad
-    // certificates, we did try it and failed again, so we should not
-    // retry again: the connection should fail at last.
-    next_state_ = STATE_CLOSE;
-    return ERR_UNEXPECTED;
-  }
-  // Add the bad certificate to the set of allowed certificates in the
-  // SSL config object.
-  SSLConfig::CertAndStatus bad_cert;
-  if (!X509Certificate::GetDEREncoded(ssl_info.cert->os_cert_handle(),
-                                      &bad_cert.der_cert)) {
-    next_state_ = STATE_CLOSE;
-    return ERR_UNEXPECTED;
-  }
-  bad_cert.cert_status = ssl_info.cert_status;
-  ssl_config->allowed_bad_certs.push_back(bad_cert);
-  // Restart connection ignoring the bad certificate.
-  connection_->socket()->Disconnect();
-  connection_->SetSocket(scoped_ptr<StreamSocket>());
-  next_state_ = STATE_TCP_CONNECT;
-  return OK;
-}
-
-void SocketStream::DoAuthRequired() {
-  if (delegate_ && proxy_auth_controller_.get())
-    delegate_->OnAuthRequired(this, proxy_auth_controller_->auth_info().get());
-  else
-    DoLoop(ERR_UNEXPECTED);
-}
-
-void SocketStream::DoRestartWithAuth() {
-  DCHECK_EQ(next_state_, STATE_AUTH_REQUIRED);
-  tunnel_request_headers_ = NULL;
-  tunnel_request_headers_bytes_sent_ = 0;
-  tunnel_response_headers_ = NULL;
-  tunnel_response_headers_capacity_ = 0;
-  tunnel_response_headers_len_ = 0;
-
-  next_state_ = STATE_TCP_CONNECT;
-  DoLoop(OK);
-}
-
-int SocketStream::HandleCertificateError(int result) {
-  DCHECK(IsCertificateError(result));
-  SSLClientSocket* ssl_socket =
-      static_cast<SSLClientSocket*>(connection_->socket());
-  DCHECK(ssl_socket);
-
-  if (!context_)
-    return result;
-
-  if (SSLClientSocket::IgnoreCertError(result, LOAD_IGNORE_ALL_CERT_ERRORS)) {
-    const HttpNetworkSession::Params* session_params =
-        context_->GetNetworkSessionParams();
-    if (session_params && session_params->ignore_certificate_errors)
-      return OK;
-  }
-
-  if (!delegate_)
-    return result;
-
-  SSLInfo ssl_info;
-  ssl_socket->GetSSLInfo(&ssl_info);
-
-  TransportSecurityState* state = context_->transport_security_state();
-  const bool fatal = state && state->ShouldSSLErrorsBeFatal(url_.host());
-
-  delegate_->OnSSLCertificateError(this, ssl_info, fatal);
-  return ERR_IO_PENDING;
-}
-
-CookieStore* SocketStream::cookie_store() const {
-  return cookie_store_.get();
-}
-
-}  // namespace net
diff --git a/net/socket_stream/socket_stream.h b/net/socket_stream/socket_stream.h
deleted file mode 100644
index 7387eb6..0000000
--- a/net/socket_stream/socket_stream.h
+++ /dev/null
@@ -1,404 +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 NET_SOCKET_STREAM_SOCKET_STREAM_H_
-#define NET_SOCKET_STREAM_SOCKET_STREAM_H_
-
-#include <deque>
-#include <map>
-#include <string>
-
-#include "base/memory/linked_ptr.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/base/address_list.h"
-#include "net/base/completion_callback.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_export.h"
-#include "net/base/net_log.h"
-#include "net/base/privacy_mode.h"
-#include "net/cookies/cookie_store.h"
-#include "net/proxy/proxy_service.h"
-#include "net/ssl/ssl_config_service.h"
-#include "net/url_request/url_request.h"
-
-namespace net {
-
-class AuthChallengeInfo;
-class CertVerifier;
-class ChannelIDService;
-class ClientSocketFactory;
-class ClientSocketHandle;
-class CookieOptions;
-class HostResolver;
-class HttpAuthController;
-class SSLInfo;
-class SingleRequestHostResolver;
-class SocketStreamMetrics;
-class TransportSecurityState;
-class URLRequestContext;
-
-// SocketStream is used to implement Web Sockets.
-// It provides plain full-duplex stream with proxy and SSL support.
-// For proxy authentication, only basic mechanisum is supported.  It will try
-// authentication identity for proxy URL first.  If server requires proxy
-// authentication, it will try authentication identity for realm that server
-// requests.
-class NET_EXPORT SocketStream
-    : public base::RefCountedThreadSafe<SocketStream> {
- public:
-  // Derive from this class and add your own data members to associate extra
-  // information with a SocketStream.  Use GetUserData(key) and
-  // SetUserData(key, data).
-  class UserData {
-   public:
-    UserData() {}
-    virtual ~UserData() {}
-  };
-
-  class NET_EXPORT Delegate {
-   public:
-    virtual int OnStartOpenConnection(SocketStream* socket,
-                                      const CompletionCallback& callback);
-
-    // Called when a socket stream has been connected.  The socket stream is
-    // allowed to buffer pending send data at most |max_pending_send_allowed|
-    // bytes.  A client of the socket stream should keep track of how much
-    // pending send data it has and must not call SendData() if the pending
-    // data goes over |max_pending_send_allowed| bytes.
-    virtual void OnConnected(SocketStream* socket,
-                             int max_pending_send_allowed) = 0;
-
-    // Called when |amount_sent| bytes of data are sent.
-    virtual void OnSentData(SocketStream* socket,
-                            int amount_sent) = 0;
-
-    // Called when |len| bytes of |data| are received.
-    virtual void OnReceivedData(SocketStream* socket,
-                                const char* data, int len) = 0;
-
-    // Called when the socket stream has been closed.
-    virtual void OnClose(SocketStream* socket) = 0;
-
-    // Called when proxy authentication required.
-    // The delegate should call RestartWithAuth() if credential for |auth_info|
-    // is found in password database, or call Close() to close the connection.
-    virtual void OnAuthRequired(SocketStream* socket,
-                                AuthChallengeInfo* auth_info);
-
-    // Called when using SSL and the server responds with a certificate with an
-    // error. The delegate should call CancelBecauseOfCertError() or
-    // ContinueDespiteCertError() to resume connection handling.
-    virtual void OnSSLCertificateError(SocketStream* socket,
-                                       const SSLInfo& ssl_info,
-                                       bool fatal);
-
-    // Called when an error occured.
-    // This is only for error reporting to the delegate.
-    // |error| is net::Error.
-    virtual void OnError(const SocketStream* socket, int error) {}
-
-    // Called when reading cookies to allow the delegate to block access to the
-    // cookie.
-    virtual bool CanGetCookies(SocketStream* socket, const GURL& url);
-
-    // Called when a cookie is set to allow the delegate to block access to the
-    // cookie.
-    virtual bool CanSetCookie(SocketStream* request,
-                              const GURL& url,
-                              const std::string& cookie_line,
-                              CookieOptions* options);
-
-   protected:
-    virtual ~Delegate() {}
-  };
-
-  SocketStream(const GURL& url, Delegate* delegate, URLRequestContext* context,
-               CookieStore* cookie_store);
-
-  // The user data allows the clients to associate data with this job.
-  // Multiple user data values can be stored under different keys.
-  // This job will TAKE OWNERSHIP of the given data pointer, and will
-  // delete the object if it is changed or the job is destroyed.
-  UserData* GetUserData(const void* key) const;
-  void SetUserData(const void* key, UserData* data);
-
-  const GURL& url() const { return url_; }
-  bool is_secure() const;
-  const AddressList& address_list() const { return addresses_; }
-  Delegate* delegate() const { return delegate_; }
-  int max_pending_send_allowed() const { return max_pending_send_allowed_; }
-
-  URLRequestContext* context() { return context_; }
-
-  const SSLConfig& server_ssl_config() const { return server_ssl_config_; }
-  PrivacyMode privacy_mode() const { return privacy_mode_; }
-  void CheckPrivacyMode();
-
-  BoundNetLog* net_log() { return &net_log_; }
-
-  // Opens the connection on the IO thread.
-  // Once the connection is established, calls delegate's OnConnected.
-  virtual void Connect();
-
-  // Buffers |data| of |len| bytes for send and returns true if successful.
-  // If size of buffered data exceeds |max_pending_send_allowed_|, sends no
-  // data and returns false. |len| must be positive.
-  virtual bool SendData(const char* data, int len);
-
-  // Requests to close the connection.
-  // Once the connection is closed, calls delegate's OnClose.
-  virtual void Close();
-
-  // Restarts with authentication info.
-  // Should be used for response of OnAuthRequired.
-  virtual void RestartWithAuth(const AuthCredentials& credentials);
-
-  // Detach delegate.  Call before delegate is deleted.
-  // Once delegate is detached, close the socket stream and never call delegate
-  // back.
-  virtual void DetachDelegate();
-
-  // Detach the context.
-  virtual void DetachContext();
-
-  const ProxyServer& proxy_server() const;
-
-  // Sets an alternative ClientSocketFactory.  Doesn't take ownership of
-  // |factory|.  For testing purposes only.
-  void SetClientSocketFactory(ClientSocketFactory* factory);
-
-  // Cancels the connection because of an error.
-  // |error| is net::Error which represents the error.
-  void CancelWithError(int error);
-
-  // Cancels the connection because of receiving a certificate with an error.
-  void CancelWithSSLError(const SSLInfo& ssl_info);
-
-  // Continues to establish the connection in spite of an error. Usually this
-  // case happens because users allow certificate with an error by manual
-  // actions on alert dialog or browser cached such kinds of user actions.
-  void ContinueDespiteError();
-
-  CookieStore* cookie_store() const;
-
- protected:
-  friend class base::RefCountedThreadSafe<SocketStream>;
-  virtual ~SocketStream();
-
-  Delegate* delegate_;
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(SocketStreamTest, IOPending);
-  FRIEND_TEST_ALL_PREFIXES(SocketStreamTest, SwitchAfterPending);
-  FRIEND_TEST_ALL_PREFIXES(SocketStreamTest,
-                           NullContextSocketStreamShouldNotCrash);
-
-  friend class WebSocketThrottleTest;
-
-  typedef std::map<const void*, linked_ptr<UserData> > UserDataMap;
-  typedef std::deque< scoped_refptr<IOBufferWithSize> > PendingDataQueue;
-
-  class RequestHeaders : public IOBuffer {
-   public:
-    RequestHeaders() : IOBuffer() {}
-
-    void SetDataOffset(size_t offset) {
-      data_ = const_cast<char*>(headers_.data()) + offset;
-    }
-
-    std::string headers_;
-
-    private:
-     ~RequestHeaders() override;
-  };
-
-  class ResponseHeaders : public IOBuffer {
-   public:
-    ResponseHeaders();
-
-    void SetDataOffset(size_t offset) { data_ = headers_.get() + offset; }
-    char* headers() const { return headers_.get(); }
-    void Reset() { headers_.reset(); }
-    void Realloc(size_t new_size);
-
-   private:
-    ~ResponseHeaders() override;
-
-    scoped_ptr<char, base::FreeDeleter> headers_;
-  };
-
-  enum State {
-    STATE_NONE,
-    STATE_BEFORE_CONNECT,
-    STATE_BEFORE_CONNECT_COMPLETE,
-    STATE_RESOLVE_PROXY,
-    STATE_RESOLVE_PROXY_COMPLETE,
-    STATE_RESOLVE_HOST,
-    STATE_RESOLVE_HOST_COMPLETE,
-    STATE_RESOLVE_PROTOCOL,
-    STATE_RESOLVE_PROTOCOL_COMPLETE,
-    STATE_TCP_CONNECT,
-    STATE_TCP_CONNECT_COMPLETE,
-    STATE_GENERATE_PROXY_AUTH_TOKEN,
-    STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE,
-    STATE_WRITE_TUNNEL_HEADERS,
-    STATE_WRITE_TUNNEL_HEADERS_COMPLETE,
-    STATE_READ_TUNNEL_HEADERS,
-    STATE_READ_TUNNEL_HEADERS_COMPLETE,
-    STATE_SOCKS_CONNECT,
-    STATE_SOCKS_CONNECT_COMPLETE,
-    STATE_SECURE_PROXY_CONNECT,
-    STATE_SECURE_PROXY_CONNECT_COMPLETE,
-    STATE_SECURE_PROXY_HANDLE_CERT_ERROR,
-    STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE,
-    STATE_SSL_CONNECT,
-    STATE_SSL_CONNECT_COMPLETE,
-    STATE_SSL_HANDLE_CERT_ERROR,
-    STATE_SSL_HANDLE_CERT_ERROR_COMPLETE,
-    STATE_READ_WRITE,
-    STATE_AUTH_REQUIRED,
-    STATE_CLOSE,
-  };
-
-  enum ProxyMode {
-    kDirectConnection,  // If using a direct connection
-    kTunnelProxy,  // If using a tunnel (CONNECT method as HTTPS)
-    kSOCKSProxy,  // If using a SOCKS proxy
-  };
-
-  // Use the same number as HttpNetworkTransaction::kMaxHeaderBufSize.
-  enum { kMaxTunnelResponseHeadersSize = 32768 };  // 32 kilobytes.
-
-  // Used for WebSocketThrottleTest.
-  void set_addresses(const AddressList& addresses);
-
-  void DoClose();
-
-  // Finishes the job.
-  // Calls OnError and OnClose of delegate, and no more
-  // notifications will be sent to delegate.
-  void Finish(int result);
-
-  int DidEstablishConnection();
-  int DidReceiveData(int result);
-  // Given the number of bytes sent,
-  // - notifies the |delegate_| and |metrics_| of this event.
-  // - drains sent data from |current_write_buf_|.
-  // - if |current_write_buf_| has been fully sent, sets NULL to
-  //   |current_write_buf_| to get ready for next write.
-  // and then, returns OK.
-  void DidSendData(int result);
-
-  void OnIOCompleted(int result);
-  void OnReadCompleted(int result);
-  void OnWriteCompleted(int result);
-
-  void DoLoop(int result);
-
-  int DoBeforeConnect();
-  int DoBeforeConnectComplete(int result);
-  int DoResolveProxy();
-  int DoResolveProxyComplete(int result);
-  int DoResolveHost();
-  int DoResolveHostComplete(int result);
-  int DoResolveProtocol(int result);
-  int DoResolveProtocolComplete(int result);
-  int DoTcpConnect(int result);
-  int DoTcpConnectComplete(int result);
-  int DoGenerateProxyAuthToken();
-  int DoGenerateProxyAuthTokenComplete(int result);
-  int DoWriteTunnelHeaders();
-  int DoWriteTunnelHeadersComplete(int result);
-  int DoReadTunnelHeaders();
-  int DoReadTunnelHeadersComplete(int result);
-  int DoSOCKSConnect();
-  int DoSOCKSConnectComplete(int result);
-  int DoSecureProxyConnect();
-  int DoSecureProxyConnectComplete(int result);
-  int DoSecureProxyHandleCertError(int result);
-  int DoSecureProxyHandleCertErrorComplete(int result);
-  int DoSSLConnect();
-  int DoSSLConnectComplete(int result);
-  int DoSSLHandleCertError(int result);
-  int DoSSLHandleCertErrorComplete(int result);
-  int DoReadWrite(int result);
-
-  GURL ProxyAuthOrigin() const;
-  int HandleAuthChallenge(const HttpResponseHeaders* headers);
-  int HandleCertificateRequest(int result, SSLConfig* ssl_config);
-  void DoAuthRequired();
-  void DoRestartWithAuth();
-
-  int HandleCertificateError(int result);
-  int AllowCertErrorForReconnection(SSLConfig* ssl_config);
-
-  // Returns the sum of the size of buffers in |pending_write_bufs_|.
-  size_t GetTotalSizeOfPendingWriteBufs() const;
-
-  BoundNetLog net_log_;
-
-  GURL url_;
-  // The number of bytes allowed to be buffered in this object. If the size of
-  // buffered data which is
-  //   current_write_buf_.BytesRemaining() +
-  //   sum of the size of buffers in |pending_write_bufs_|
-  // exceeds this limit, SendData() fails.
-  int max_pending_send_allowed_;
-  URLRequestContext* context_;
-
-  UserDataMap user_data_;
-
-  State next_state_;
-  ClientSocketFactory* factory_;
-
-  ProxyMode proxy_mode_;
-
-  GURL proxy_url_;
-  ProxyService::PacRequest* pac_request_;
-  ProxyInfo proxy_info_;
-
-  scoped_refptr<HttpAuthController> proxy_auth_controller_;
-
-  scoped_refptr<RequestHeaders> tunnel_request_headers_;
-  size_t tunnel_request_headers_bytes_sent_;
-  scoped_refptr<ResponseHeaders> tunnel_response_headers_;
-  int tunnel_response_headers_capacity_;
-  int tunnel_response_headers_len_;
-
-  scoped_ptr<SingleRequestHostResolver> resolver_;
-  AddressList addresses_;
-  scoped_ptr<ClientSocketHandle> connection_;
-
-  SSLConfig server_ssl_config_;
-  SSLConfig proxy_ssl_config_;
-  PrivacyMode privacy_mode_;
-
-  CompletionCallback io_callback_;
-
-  scoped_refptr<IOBuffer> read_buf_;
-  int read_buf_size_;
-
-  // Buffer to hold data to pass to socket_.
-  scoped_refptr<DrainableIOBuffer> current_write_buf_;
-  // True iff there's no error and this instance is waiting for completion of
-  // Write operation by socket_.
-  bool waiting_for_write_completion_;
-  PendingDataQueue pending_write_bufs_;
-
-  bool closing_;
-  bool server_closed_;
-
-  scoped_ptr<SocketStreamMetrics> metrics_;
-
-  // Cookie store to use for this socket stream.
-  scoped_refptr<CookieStore> cookie_store_;
-
-  DISALLOW_COPY_AND_ASSIGN(SocketStream);
-};
-
-}  // namespace net
-
-#endif  // NET_SOCKET_STREAM_SOCKET_STREAM_H_
diff --git a/net/socket_stream/socket_stream_job.cc b/net/socket_stream/socket_stream_job.cc
deleted file mode 100644
index 66da741..0000000
--- a/net/socket_stream/socket_stream_job.cc
+++ /dev/null
@@ -1,92 +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 "net/socket_stream/socket_stream_job.h"
-
-#include "base/memory/singleton.h"
-#include "net/http/transport_security_state.h"
-#include "net/socket_stream/socket_stream_job_manager.h"
-#include "net/ssl/ssl_config_service.h"
-#include "net/url_request/url_request_context.h"
-
-namespace net {
-
-// static
-SocketStreamJob::ProtocolFactory* SocketStreamJob::RegisterProtocolFactory(
-    const std::string& scheme, ProtocolFactory* factory) {
-  return SocketStreamJobManager::GetInstance()->RegisterProtocolFactory(
-      scheme, factory);
-}
-
-// static
-SocketStreamJob* SocketStreamJob::CreateSocketStreamJob(
-    const GURL& url,
-    SocketStream::Delegate* delegate,
-    TransportSecurityState* sts,
-    SSLConfigService* ssl,
-    URLRequestContext* context,
-    CookieStore* cookie_store) {
-  GURL socket_url(url);
-  if (url.scheme() == "ws" && sts &&
-      sts->ShouldUpgradeToSSL(url.host())) {
-    url::Replacements<char> replacements;
-    static const char kNewScheme[] = "wss";
-    replacements.SetScheme(kNewScheme, url::Component(0, strlen(kNewScheme)));
-    socket_url = url.ReplaceComponents(replacements);
-  }
-  return SocketStreamJobManager::GetInstance()->CreateJob(
-      socket_url, delegate, context, cookie_store);
-}
-
-SocketStreamJob::SocketStreamJob() {}
-
-SocketStream::UserData* SocketStreamJob::GetUserData(const void* key) const {
-  return socket_->GetUserData(key);
-}
-
-void SocketStreamJob::SetUserData(const void* key,
-                                  SocketStream::UserData* data) {
-  socket_->SetUserData(key, data);
-}
-
-void SocketStreamJob::Connect() {
-  socket_->Connect();
-}
-
-bool SocketStreamJob::SendData(const char* data, int len) {
-  return socket_->SendData(data, len);
-}
-
-void SocketStreamJob::Close() {
-  socket_->Close();
-}
-
-void SocketStreamJob::RestartWithAuth(const AuthCredentials& credentials) {
-  socket_->RestartWithAuth(credentials);
-}
-
-void SocketStreamJob::CancelWithError(int error) {
-  socket_->CancelWithError(error);
-}
-
-void SocketStreamJob::CancelWithSSLError(const net::SSLInfo& ssl_info) {
-  socket_->CancelWithSSLError(ssl_info);
-}
-
-void SocketStreamJob::ContinueDespiteError() {
-  socket_->ContinueDespiteError();
-}
-
-void SocketStreamJob::DetachDelegate() {
-  socket_->DetachDelegate();
-}
-
-void SocketStreamJob::DetachContext() {
-  if (socket_.get())
-    socket_->DetachContext();
-}
-
-SocketStreamJob::~SocketStreamJob() {}
-
-}  // namespace net
diff --git a/net/socket_stream/socket_stream_job.h b/net/socket_stream/socket_stream_job.h
deleted file mode 100644
index 9fc27d9..0000000
--- a/net/socket_stream/socket_stream_job.h
+++ /dev/null
@@ -1,94 +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 NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_
-#define NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_
-
-#include <string>
-
-#include "base/memory/ref_counted.h"
-#include "net/base/net_export.h"
-#include "net/socket_stream/socket_stream.h"
-
-class GURL;
-
-namespace net {
-
-class CookieStore;
-class SSLConfigService;
-class SSLInfo;
-class TransportSecurityState;
-
-// SocketStreamJob represents full-duplex communication over SocketStream.
-// If a protocol (e.g. WebSocket protocol) needs to inspect/modify data
-// over SocketStream, you can implement protocol specific job (e.g.
-// WebSocketJob) to do some work on data over SocketStream.
-// Registers the protocol specific SocketStreamJob by RegisterProtocolFactory
-// and call CreateSocketStreamJob to create SocketStreamJob for the URL.
-class NET_EXPORT SocketStreamJob
-    : public base::RefCountedThreadSafe<SocketStreamJob> {
- public:
-  // Callback function implemented by protocol handlers to create new jobs.
-  typedef SocketStreamJob* (ProtocolFactory)(const GURL& url,
-                                             SocketStream::Delegate* delegate,
-                                             URLRequestContext* context,
-                                             CookieStore* cookie_store);
-
-  static ProtocolFactory* RegisterProtocolFactory(const std::string& scheme,
-                                                  ProtocolFactory* factory);
-
-  static SocketStreamJob* CreateSocketStreamJob(
-      const GURL& url,
-      SocketStream::Delegate* delegate,
-      TransportSecurityState* sts,
-      SSLConfigService* ssl,
-      URLRequestContext* context,
-      CookieStore* cookie_store);
-
-  SocketStreamJob();
-  void InitSocketStream(SocketStream* socket) {
-    socket_ = socket;
-  }
-
-  virtual SocketStream::UserData* GetUserData(const void* key) const;
-  virtual void SetUserData(const void* key, SocketStream::UserData* data);
-
-  URLRequestContext* context() const {
-    return socket_.get() ? socket_->context() : 0;
-  }
-  CookieStore* cookie_store() const {
-    return socket_.get() ? socket_->cookie_store() : 0;
-  }
-
-  virtual void Connect();
-
-  virtual bool SendData(const char* data, int len);
-
-  virtual void Close();
-
-  virtual void RestartWithAuth(const AuthCredentials& credentials);
-
-  virtual void CancelWithError(int error);
-
-  virtual void CancelWithSSLError(const net::SSLInfo& ssl_info);
-
-  virtual void ContinueDespiteError();
-
-  virtual void DetachDelegate();
-
-  virtual void DetachContext();
-
- protected:
-  friend class WebSocketJobTest;
-  friend class base::RefCountedThreadSafe<SocketStreamJob>;
-  virtual ~SocketStreamJob();
-
-  scoped_refptr<SocketStream> socket_;
-
-  DISALLOW_COPY_AND_ASSIGN(SocketStreamJob);
-};
-
-}  // namespace net
-
-#endif  // NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_
diff --git a/net/socket_stream/socket_stream_job_manager.cc b/net/socket_stream/socket_stream_job_manager.cc
deleted file mode 100644
index 6418be4..0000000
--- a/net/socket_stream/socket_stream_job_manager.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/socket_stream/socket_stream_job_manager.h"
-
-#include "base/memory/singleton.h"
-
-namespace net {
-
-SocketStreamJobManager::SocketStreamJobManager() {
-}
-
-SocketStreamJobManager::~SocketStreamJobManager() {
-}
-
-// static
-SocketStreamJobManager* SocketStreamJobManager::GetInstance() {
-  return Singleton<SocketStreamJobManager>::get();
-}
-
-SocketStreamJob* SocketStreamJobManager::CreateJob(
-    const GURL& url, SocketStream::Delegate* delegate,
-    URLRequestContext* context, CookieStore* cookie_store) const {
-  // If url is invalid, create plain SocketStreamJob, which will close
-  // the socket immediately.
-  if (!url.is_valid()) {
-    SocketStreamJob* job = new SocketStreamJob();
-    job->InitSocketStream(new SocketStream(url, delegate, context,
-                                           cookie_store));
-    return job;
-  }
-
-  const std::string& scheme = url.scheme();  // already lowercase
-
-  base::AutoLock locked(lock_);
-  FactoryMap::const_iterator found = factories_.find(scheme);
-  if (found != factories_.end()) {
-    SocketStreamJob* job = found->second(url, delegate, context, cookie_store);
-    if (job)
-      return job;
-  }
-  SocketStreamJob* job = new SocketStreamJob();
-  job->InitSocketStream(new SocketStream(url, delegate, context, cookie_store));
-  return job;
-}
-
-SocketStreamJob::ProtocolFactory*
-SocketStreamJobManager::RegisterProtocolFactory(
-    const std::string& scheme, SocketStreamJob::ProtocolFactory* factory) {
-  base::AutoLock locked(lock_);
-
-  SocketStreamJob::ProtocolFactory* old_factory;
-  FactoryMap::iterator found = factories_.find(scheme);
-  if (found != factories_.end()) {
-    old_factory = found->second;
-  } else {
-    old_factory = NULL;
-  }
-  if (factory) {
-    factories_[scheme] = factory;
-  } else if (found != factories_.end()) {
-    factories_.erase(found);
-  }
-  return old_factory;
-}
-
-}  // namespace net
diff --git a/net/socket_stream/socket_stream_job_manager.h b/net/socket_stream/socket_stream_job_manager.h
deleted file mode 100644
index 2363fb5..0000000
--- a/net/socket_stream/socket_stream_job_manager.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2010 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 NET_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_
-#define NET_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_
-
-#include <map>
-#include <string>
-
-#include "net/socket_stream/socket_stream.h"
-#include "net/socket_stream/socket_stream_job.h"
-
-template <typename T> struct DefaultSingletonTraits;
-class GURL;
-
-namespace net {
-
-class SocketStreamJobManager {
- public:
-  // Returns the singleton instance.
-  static SocketStreamJobManager* GetInstance();
-
-  SocketStreamJob* CreateJob(
-      const GURL& url, SocketStream::Delegate* delegate,
-      URLRequestContext* context, CookieStore* cookie_store) const;
-
-  SocketStreamJob::ProtocolFactory* RegisterProtocolFactory(
-      const std::string& scheme, SocketStreamJob::ProtocolFactory* factory);
-
- private:
-  friend struct DefaultSingletonTraits<SocketStreamJobManager>;
-  typedef std::map<std::string, SocketStreamJob::ProtocolFactory*> FactoryMap;
-
-  SocketStreamJobManager();
-  ~SocketStreamJobManager();
-
-  mutable base::Lock lock_;
-  FactoryMap factories_;
-
-  DISALLOW_COPY_AND_ASSIGN(SocketStreamJobManager);
-};
-
-}  // namespace net
-
-#endif  // NET_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_
diff --git a/net/socket_stream/socket_stream_metrics.cc b/net/socket_stream/socket_stream_metrics.cc
deleted file mode 100644
index e026887..0000000
--- a/net/socket_stream/socket_stream_metrics.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/socket_stream/socket_stream_metrics.h"
-
-#include <string.h>
-
-#include "base/metrics/histogram.h"
-#include "base/time/time.h"
-#include "url/gurl.h"
-
-namespace net {
-
-SocketStreamMetrics::SocketStreamMetrics(const GURL& url)
-    : received_bytes_(0),
-      received_counts_(0),
-      sent_bytes_(0),
-      sent_counts_(0) {
-  ProtocolType protocol_type = PROTOCOL_UNKNOWN;
-  if (url.SchemeIs("ws"))
-    protocol_type = PROTOCOL_WEBSOCKET;
-  else if (url.SchemeIs("wss"))
-    protocol_type = PROTOCOL_WEBSOCKET_SECURE;
-
-  UMA_HISTOGRAM_ENUMERATION("Net.SocketStream.ProtocolType",
-                            protocol_type, NUM_PROTOCOL_TYPES);
-}
-
-SocketStreamMetrics::~SocketStreamMetrics() {}
-
-void SocketStreamMetrics::OnWaitConnection() {
-  wait_start_time_ = base::TimeTicks::Now();
-}
-
-void SocketStreamMetrics::OnStartConnection() {
-  connect_start_time_ = base::TimeTicks::Now();
-  if (!wait_start_time_.is_null())
-    UMA_HISTOGRAM_TIMES("Net.SocketStream.ConnectionLatency",
-                        connect_start_time_ - wait_start_time_);
-  OnCountConnectionType(ALL_CONNECTIONS);
-}
-
-void SocketStreamMetrics::OnConnected() {
-  connect_establish_time_ = base::TimeTicks::Now();
-  UMA_HISTOGRAM_TIMES("Net.SocketStream.ConnectionEstablish",
-                      connect_establish_time_ - connect_start_time_);
-}
-
-void SocketStreamMetrics::OnRead(int len) {
-  received_bytes_ += len;
-  ++received_counts_;
-}
-
-void SocketStreamMetrics::OnWrite(int len) {
-  sent_bytes_ += len;
-  ++sent_counts_;
-}
-
-void SocketStreamMetrics::OnClose() {
-  base::TimeTicks closed_time = base::TimeTicks::Now();
-  if (!connect_establish_time_.is_null()) {
-    UMA_HISTOGRAM_LONG_TIMES("Net.SocketStream.Duration",
-                             closed_time - connect_establish_time_);
-    UMA_HISTOGRAM_COUNTS("Net.SocketStream.ReceivedBytes",
-                         received_bytes_);
-    UMA_HISTOGRAM_COUNTS("Net.SocketStream.ReceivedCounts",
-                         received_counts_);
-    UMA_HISTOGRAM_COUNTS("Net.SocketStream.SentBytes",
-                         sent_bytes_);
-    UMA_HISTOGRAM_COUNTS("Net.SocketStream.SentCounts",
-                         sent_counts_);
-  }
-}
-
-void SocketStreamMetrics::OnCountConnectionType(ConnectionType type) {
-  UMA_HISTOGRAM_ENUMERATION("Net.SocketStream.ConnectionType", type,
-                            NUM_CONNECTION_TYPES);
-}
-
-void SocketStreamMetrics::OnCountWireProtocolType(WireProtocolType type) {
-  UMA_HISTOGRAM_ENUMERATION("Net.SocketStream.WireProtocolType", type,
-                            NUM_WIRE_PROTOCOL_TYPES);
-}
-
-}  // namespace net
diff --git a/net/socket_stream/socket_stream_metrics.h b/net/socket_stream/socket_stream_metrics.h
deleted file mode 100644
index 0040a9a..0000000
--- a/net/socket_stream/socket_stream_metrics.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// Collect metrics of SocketStream usage.
-// TODO(ukai): collect WebSocket specific metrics (e.g. handshake time, etc).
-
-#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_
-#define NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_
-
-#include "base/basictypes.h"
-#include "base/time/time.h"
-#include "net/base/net_export.h"
-
-class GURL;
-
-namespace net {
-
-class NET_EXPORT_PRIVATE SocketStreamMetrics {
- public:
-  enum ProtocolType {
-    PROTOCOL_UNKNOWN,
-    PROTOCOL_WEBSOCKET,
-    PROTOCOL_WEBSOCKET_SECURE,
-    NUM_PROTOCOL_TYPES,
-  };
-
-  enum ConnectionType {
-    CONNECTION_NONE,
-    ALL_CONNECTIONS,
-    TUNNEL_CONNECTION,
-    SOCKS_CONNECTION,
-    SSL_CONNECTION,
-    SECURE_PROXY_CONNECTION,
-    NUM_CONNECTION_TYPES,
-  };
-
-  enum WireProtocolType {
-    WIRE_PROTOCOL_WEBSOCKET,
-    WIRE_PROTOCOL_SPDY,
-    NUM_WIRE_PROTOCOL_TYPES,
-  };
-
-  explicit SocketStreamMetrics(const GURL& url);
-  ~SocketStreamMetrics();
-
-  void OnWaitConnection();
-  void OnStartConnection();
-  void OnConnected();
-  void OnRead(int len);
-  void OnWrite(int len);
-  void OnClose();
-  void OnCountConnectionType(ConnectionType type);
-  void OnCountWireProtocolType(WireProtocolType type);
-
- private:
-  base::TimeTicks wait_start_time_;
-  base::TimeTicks connect_start_time_;
-  base::TimeTicks connect_establish_time_;
-  int received_bytes_;
-  int received_counts_;
-  int sent_bytes_;
-  int sent_counts_;
-
-  DISALLOW_COPY_AND_ASSIGN(SocketStreamMetrics);
-};
-
-}  // namespace net
-
-#endif  // NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_
diff --git a/net/socket_stream/socket_stream_metrics_unittest.cc b/net/socket_stream/socket_stream_metrics_unittest.cc
deleted file mode 100644
index 219e692..0000000
--- a/net/socket_stream/socket_stream_metrics_unittest.cc
+++ /dev/null
@@ -1,221 +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 "net/socket_stream/socket_stream_metrics.h"
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/histogram_samples.h"
-#include "base/metrics/statistics_recorder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "url/gurl.h"
-
-using base::Histogram;
-using base::HistogramBase;
-using base::HistogramSamples;
-using base::StatisticsRecorder;
-
-namespace net {
-
-TEST(SocketStreamMetricsTest, ProtocolType) {
-  // First we'll preserve the original values. We need to do this
-  // as histograms can get affected by other tests. In particular,
-  // SocketStreamTest and WebSocketTest can affect the histograms.
-  scoped_ptr<HistogramSamples> original;
-  HistogramBase* histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.ProtocolType");
-  if (histogram) {
-    original = histogram->SnapshotSamples();
-  }
-
-  SocketStreamMetrics unknown(GURL("unknown://www.example.com/"));
-  SocketStreamMetrics ws1(GURL("ws://www.example.com/"));
-  SocketStreamMetrics ws2(GURL("ws://www.example.com/"));
-  SocketStreamMetrics wss1(GURL("wss://www.example.com/"));
-  SocketStreamMetrics wss2(GURL("wss://www.example.com/"));
-  SocketStreamMetrics wss3(GURL("wss://www.example.com/"));
-
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.ProtocolType");
-  ASSERT_TRUE(histogram != NULL);
-  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-
-  scoped_ptr<HistogramSamples> samples(histogram->SnapshotSamples());
-  if (original.get()) {
-    samples->Subtract(*original);  // Cancel the original values.
-  }
-  EXPECT_EQ(1, samples->GetCount(SocketStreamMetrics::PROTOCOL_UNKNOWN));
-  EXPECT_EQ(2, samples->GetCount(SocketStreamMetrics::PROTOCOL_WEBSOCKET));
-  EXPECT_EQ(3,
-            samples->GetCount(SocketStreamMetrics::PROTOCOL_WEBSOCKET_SECURE));
-}
-
-TEST(SocketStreamMetricsTest, ConnectionType) {
-  // First we'll preserve the original values.
-  scoped_ptr<HistogramSamples> original;
-  HistogramBase* histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionType");
-  if (histogram) {
-    original = histogram->SnapshotSamples();
-  }
-
-  SocketStreamMetrics metrics(GURL("ws://www.example.com/"));
-  for (int i = 0; i < 1; ++i)
-    metrics.OnStartConnection();
-  for (int i = 0; i < 2; ++i)
-    metrics.OnCountConnectionType(SocketStreamMetrics::TUNNEL_CONNECTION);
-  for (int i = 0; i < 3; ++i)
-    metrics.OnCountConnectionType(SocketStreamMetrics::SOCKS_CONNECTION);
-  for (int i = 0; i < 4; ++i)
-    metrics.OnCountConnectionType(SocketStreamMetrics::SSL_CONNECTION);
-
-
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionType");
-  ASSERT_TRUE(histogram != NULL);
-  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-
-  scoped_ptr<HistogramSamples> samples(histogram->SnapshotSamples());
-  if (original.get()) {
-    samples->Subtract(*original);  // Cancel the original values.
-  }
-  EXPECT_EQ(1, samples->GetCount(SocketStreamMetrics::ALL_CONNECTIONS));
-  EXPECT_EQ(2, samples->GetCount(SocketStreamMetrics::TUNNEL_CONNECTION));
-  EXPECT_EQ(3, samples->GetCount(SocketStreamMetrics::SOCKS_CONNECTION));
-  EXPECT_EQ(4, samples->GetCount(SocketStreamMetrics::SSL_CONNECTION));
-}
-
-TEST(SocketStreamMetricsTest, WireProtocolType) {
-  // First we'll preserve the original values.
-  scoped_ptr<HistogramSamples> original;
-  HistogramBase* histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.WireProtocolType");
-  if (histogram) {
-    original = histogram->SnapshotSamples();
-  }
-
-  SocketStreamMetrics metrics(GURL("ws://www.example.com/"));
-  for (int i = 0; i < 3; ++i)
-    metrics.OnCountWireProtocolType(
-        SocketStreamMetrics::WIRE_PROTOCOL_WEBSOCKET);
-  for (int i = 0; i < 7; ++i)
-    metrics.OnCountWireProtocolType(SocketStreamMetrics::WIRE_PROTOCOL_SPDY);
-
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.WireProtocolType");
-  ASSERT_TRUE(histogram != NULL);
-  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-
-  scoped_ptr<HistogramSamples> samples(histogram->SnapshotSamples());
-  if (original.get()) {
-    samples->Subtract(*original);  // Cancel the original values.
-  }
-  EXPECT_EQ(3, samples->GetCount(SocketStreamMetrics::WIRE_PROTOCOL_WEBSOCKET));
-  EXPECT_EQ(7, samples->GetCount(SocketStreamMetrics::WIRE_PROTOCOL_SPDY));
-}
-
-TEST(SocketStreamMetricsTest, OtherNumbers) {
-  // First we'll preserve the original values.
-  int64 original_received_bytes = 0;
-  int64 original_received_counts = 0;
-  int64 original_sent_bytes = 0;
-  int64 original_sent_counts = 0;
-
-  scoped_ptr<HistogramSamples> original;
-
-  HistogramBase* histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedBytes");
-  if (histogram) {
-    original = histogram->SnapshotSamples();
-    original_received_bytes = original->sum();
-  }
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedCounts");
-  if (histogram) {
-    original = histogram->SnapshotSamples();
-    original_received_counts = original->sum();
-  }
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.SentBytes");
-  if (histogram) {
-    original = histogram->SnapshotSamples();
-    original_sent_bytes = original->sum();
-  }
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.SentCounts");
-  if (histogram) {
-    original = histogram->SnapshotSamples();
-    original_sent_counts = original->sum();
-  }
-
-  SocketStreamMetrics metrics(GURL("ws://www.example.com/"));
-  metrics.OnWaitConnection();
-  metrics.OnStartConnection();
-  metrics.OnConnected();
-  metrics.OnRead(1);
-  metrics.OnRead(10);
-  metrics.OnWrite(2);
-  metrics.OnWrite(20);
-  metrics.OnWrite(200);
-  metrics.OnClose();
-
-  scoped_ptr<HistogramSamples> samples;
-
-  // ConnectionLatency.
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionLatency");
-  ASSERT_TRUE(histogram != NULL);
-  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-  // We don't check the contents of the histogram as it's time sensitive.
-
-  // ConnectionEstablish.
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionEstablish");
-  ASSERT_TRUE(histogram != NULL);
-  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-  // We don't check the contents of the histogram as it's time sensitive.
-
-  // Duration.
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.Duration");
-  ASSERT_TRUE(histogram != NULL);
-  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-  // We don't check the contents of the histogram as it's time sensitive.
-
-  // ReceivedBytes.
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedBytes");
-  ASSERT_TRUE(histogram != NULL);
-  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-  samples = histogram->SnapshotSamples();
-  EXPECT_EQ(11, samples->sum() - original_received_bytes);  // 11 bytes read.
-
-  // ReceivedCounts.
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedCounts");
-  ASSERT_TRUE(histogram != NULL);
-  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-  samples = histogram->SnapshotSamples();
-  EXPECT_EQ(2, samples->sum() - original_received_counts);  // 2 read requests.
-
-  // SentBytes.
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.SentBytes");
-  ASSERT_TRUE(histogram != NULL);
-  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-  samples = histogram->SnapshotSamples();
-  EXPECT_EQ(222, samples->sum() - original_sent_bytes);  // 222 bytes sent.
-
-  // SentCounts.
-  histogram =
-      StatisticsRecorder::FindHistogram("Net.SocketStream.SentCounts");
-  ASSERT_TRUE(histogram != NULL);
-  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-  samples = histogram->SnapshotSamples();
-  EXPECT_EQ(3, samples->sum() - original_sent_counts);  // 3 write requests.
-}
-
-}  // namespace net
diff --git a/net/socket_stream/socket_stream_unittest.cc b/net/socket_stream/socket_stream_unittest.cc
deleted file mode 100644
index b5ee002..0000000
--- a/net/socket_stream/socket_stream_unittest.cc
+++ /dev/null
@@ -1,1041 +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 "net/socket_stream/socket_stream.h"
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/strings/utf_string_conversions.h"
-#include "net/base/auth.h"
-#include "net/base/net_log.h"
-#include "net/base/net_log_unittest.h"
-#include "net/base/test_completion_callback.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/http/http_network_session.h"
-#include "net/proxy/proxy_service.h"
-#include "net/socket/socket_test_util.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-using base::ASCIIToUTF16;
-
-namespace net {
-
-namespace {
-
-struct SocketStreamEvent {
-  enum EventType {
-    EVENT_START_OPEN_CONNECTION, EVENT_CONNECTED, EVENT_SENT_DATA,
-    EVENT_RECEIVED_DATA, EVENT_CLOSE, EVENT_AUTH_REQUIRED, EVENT_ERROR,
-  };
-
-  SocketStreamEvent(EventType type,
-                    SocketStream* socket_stream,
-                    int num,
-                    const std::string& str,
-                    AuthChallengeInfo* auth_challenge_info,
-                    int error)
-      : event_type(type), socket(socket_stream), number(num), data(str),
-        auth_info(auth_challenge_info), error_code(error) {}
-
-  EventType event_type;
-  SocketStream* socket;
-  int number;
-  std::string data;
-  scoped_refptr<AuthChallengeInfo> auth_info;
-  int error_code;
-};
-
-class SocketStreamEventRecorder : public SocketStream::Delegate {
- public:
-  // |callback| will be run when the OnClose() or OnError() method is called.
-  // For OnClose(), |callback| is called with OK. For OnError(), it's called
-  // with the error code.
-  explicit SocketStreamEventRecorder(const CompletionCallback& callback)
-      : callback_(callback) {}
-  ~SocketStreamEventRecorder() override {}
-
-  void SetOnStartOpenConnection(
-      const base::Callback<int(SocketStreamEvent*)>& callback) {
-    on_start_open_connection_ = callback;
-  }
-  void SetOnConnected(
-      const base::Callback<void(SocketStreamEvent*)>& callback) {
-    on_connected_ = callback;
-  }
-  void SetOnSentData(
-      const base::Callback<void(SocketStreamEvent*)>& callback) {
-    on_sent_data_ = callback;
-  }
-  void SetOnReceivedData(
-      const base::Callback<void(SocketStreamEvent*)>& callback) {
-    on_received_data_ = callback;
-  }
-  void SetOnClose(const base::Callback<void(SocketStreamEvent*)>& callback) {
-    on_close_ = callback;
-  }
-  void SetOnAuthRequired(
-      const base::Callback<void(SocketStreamEvent*)>& callback) {
-    on_auth_required_ = callback;
-  }
-  void SetOnError(const base::Callback<void(SocketStreamEvent*)>& callback) {
-    on_error_ = callback;
-  }
-
-  int OnStartOpenConnection(SocketStream* socket,
-                            const CompletionCallback& callback) override {
-    connection_callback_ = callback;
-    events_.push_back(
-        SocketStreamEvent(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-                          socket, 0, std::string(), NULL, OK));
-    if (!on_start_open_connection_.is_null())
-      return on_start_open_connection_.Run(&events_.back());
-    return OK;
-  }
-  void OnConnected(SocketStream* socket,
-                   int num_pending_send_allowed) override {
-    events_.push_back(
-        SocketStreamEvent(SocketStreamEvent::EVENT_CONNECTED,
-                          socket, num_pending_send_allowed, std::string(),
-                          NULL, OK));
-    if (!on_connected_.is_null())
-      on_connected_.Run(&events_.back());
-  }
-  void OnSentData(SocketStream* socket, int amount_sent) override {
-    events_.push_back(
-        SocketStreamEvent(SocketStreamEvent::EVENT_SENT_DATA, socket,
-                          amount_sent, std::string(), NULL, OK));
-    if (!on_sent_data_.is_null())
-      on_sent_data_.Run(&events_.back());
-  }
-  void OnReceivedData(SocketStream* socket,
-                      const char* data,
-                      int len) override {
-    events_.push_back(
-        SocketStreamEvent(SocketStreamEvent::EVENT_RECEIVED_DATA, socket, len,
-                          std::string(data, len), NULL, OK));
-    if (!on_received_data_.is_null())
-      on_received_data_.Run(&events_.back());
-  }
-  void OnClose(SocketStream* socket) override {
-    events_.push_back(
-        SocketStreamEvent(SocketStreamEvent::EVENT_CLOSE, socket, 0,
-                          std::string(), NULL, OK));
-    if (!on_close_.is_null())
-      on_close_.Run(&events_.back());
-    if (!callback_.is_null())
-      callback_.Run(OK);
-  }
-  void OnAuthRequired(SocketStream* socket,
-                      AuthChallengeInfo* auth_info) override {
-    events_.push_back(
-        SocketStreamEvent(SocketStreamEvent::EVENT_AUTH_REQUIRED, socket, 0,
-                          std::string(), auth_info, OK));
-    if (!on_auth_required_.is_null())
-      on_auth_required_.Run(&events_.back());
-  }
-  void OnError(const SocketStream* socket, int error) override {
-    events_.push_back(
-        SocketStreamEvent(SocketStreamEvent::EVENT_ERROR, NULL, 0,
-                          std::string(), NULL, error));
-    if (!on_error_.is_null())
-      on_error_.Run(&events_.back());
-    if (!callback_.is_null())
-      callback_.Run(error);
-  }
-
-  void DoClose(SocketStreamEvent* event) {
-    event->socket->Close();
-  }
-  void DoRestartWithAuth(SocketStreamEvent* event) {
-    VLOG(1) << "RestartWithAuth username=" << credentials_.username()
-            << " password=" << credentials_.password();
-    event->socket->RestartWithAuth(credentials_);
-  }
-  void SetAuthInfo(const AuthCredentials& credentials) {
-    credentials_ = credentials;
-  }
-  // Wakes up the SocketStream waiting for completion of OnStartOpenConnection()
-  // of its delegate.
-  void CompleteConnection(int result) {
-    connection_callback_.Run(result);
-  }
-
-  const std::vector<SocketStreamEvent>& GetSeenEvents() const {
-    return events_;
-  }
-
- private:
-  std::vector<SocketStreamEvent> events_;
-  base::Callback<int(SocketStreamEvent*)> on_start_open_connection_;
-  base::Callback<void(SocketStreamEvent*)> on_connected_;
-  base::Callback<void(SocketStreamEvent*)> on_sent_data_;
-  base::Callback<void(SocketStreamEvent*)> on_received_data_;
-  base::Callback<void(SocketStreamEvent*)> on_close_;
-  base::Callback<void(SocketStreamEvent*)> on_auth_required_;
-  base::Callback<void(SocketStreamEvent*)> on_error_;
-  const CompletionCallback callback_;
-  CompletionCallback connection_callback_;
-  AuthCredentials credentials_;
-
-  DISALLOW_COPY_AND_ASSIGN(SocketStreamEventRecorder);
-};
-
-// This is used for the test OnErrorDetachDelegate.
-class SelfDeletingDelegate : public SocketStream::Delegate {
- public:
-  // |callback| must cause the test message loop to exit when called.
-  explicit SelfDeletingDelegate(const CompletionCallback& callback)
-      : socket_stream_(), callback_(callback) {}
-
-  ~SelfDeletingDelegate() override {}
-
-  // Call DetachDelegate(), delete |this|, then run the callback.
-  void OnError(const SocketStream* socket, int error) override {
-    // callback_ will be deleted when we delete |this|, so copy it to call it
-    // afterwards.
-    CompletionCallback callback = callback_;
-    socket_stream_->DetachDelegate();
-    delete this;
-    callback.Run(OK);
-  }
-
-  // This can't be passed in the constructor because this object needs to be
-  // created before SocketStream.
-  void set_socket_stream(const scoped_refptr<SocketStream>& socket_stream) {
-    socket_stream_ = socket_stream;
-    EXPECT_EQ(socket_stream_->delegate(), this);
-  }
-
-  void OnConnected(SocketStream* socket,
-                   int max_pending_send_allowed) override {
-    ADD_FAILURE() << "OnConnected() should not be called";
-  }
-  void OnSentData(SocketStream* socket, int amount_sent) override {
-    ADD_FAILURE() << "OnSentData() should not be called";
-  }
-  void OnReceivedData(SocketStream* socket,
-                      const char* data,
-                      int len) override {
-    ADD_FAILURE() << "OnReceivedData() should not be called";
-  }
-  void OnClose(SocketStream* socket) override {
-    ADD_FAILURE() << "OnClose() should not be called";
-  }
-
- private:
-  scoped_refptr<SocketStream> socket_stream_;
-  const CompletionCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(SelfDeletingDelegate);
-};
-
-class TestURLRequestContextWithProxy : public TestURLRequestContext {
- public:
-  explicit TestURLRequestContextWithProxy(const std::string& proxy)
-      : TestURLRequestContext(true) {
-    context_storage_.set_proxy_service(ProxyService::CreateFixed(proxy));
-    Init();
-  }
-  ~TestURLRequestContextWithProxy() override {}
-};
-
-class TestSocketStreamNetworkDelegate : public TestNetworkDelegate {
- public:
-  TestSocketStreamNetworkDelegate()
-      : before_connect_result_(OK) {}
-  ~TestSocketStreamNetworkDelegate() override {}
-
-  int OnBeforeSocketStreamConnect(SocketStream* stream,
-                                  const CompletionCallback& callback) override {
-    return before_connect_result_;
-  }
-
-  void SetBeforeConnectResult(int result) {
-    before_connect_result_ = result;
-  }
-
- private:
-  int before_connect_result_;
-};
-
-}  // namespace
-
-class SocketStreamTest : public PlatformTest {
- public:
-  ~SocketStreamTest() override {}
-  void SetUp() override {
-    mock_socket_factory_.reset();
-    handshake_request_ = kWebSocketHandshakeRequest;
-    handshake_response_ = kWebSocketHandshakeResponse;
-  }
-  void TearDown() override { mock_socket_factory_.reset(); }
-
-  virtual void SetWebSocketHandshakeMessage(
-      const char* request, const char* response) {
-    handshake_request_ = request;
-    handshake_response_ = response;
-  }
-  virtual void AddWebSocketMessage(const std::string& message) {
-    messages_.push_back(message);
-  }
-
-  virtual MockClientSocketFactory* GetMockClientSocketFactory() {
-    mock_socket_factory_.reset(new MockClientSocketFactory);
-    return mock_socket_factory_.get();
-  }
-
-  // Functions for SocketStreamEventRecorder to handle calls to the
-  // SocketStream::Delegate methods from the SocketStream.
-
-  virtual void DoSendWebSocketHandshake(SocketStreamEvent* event) {
-    event->socket->SendData(
-        handshake_request_.data(), handshake_request_.size());
-  }
-
-  virtual void DoCloseFlushPendingWriteTest(SocketStreamEvent* event) {
-    // handshake response received.
-    for (size_t i = 0; i < messages_.size(); i++) {
-      std::vector<char> frame;
-      frame.push_back('\0');
-      frame.insert(frame.end(), messages_[i].begin(), messages_[i].end());
-      frame.push_back('\xff');
-      EXPECT_TRUE(event->socket->SendData(&frame[0], frame.size()));
-    }
-    // Actual StreamSocket close must happen after all frames queued by
-    // SendData above are sent out.
-    event->socket->Close();
-  }
-
-  virtual void DoCloseFlushPendingWriteTestWithSetContextNull(
-      SocketStreamEvent* event) {
-    event->socket->DetachContext();
-    // handshake response received.
-    for (size_t i = 0; i < messages_.size(); i++) {
-      std::vector<char> frame;
-      frame.push_back('\0');
-      frame.insert(frame.end(), messages_[i].begin(), messages_[i].end());
-      frame.push_back('\xff');
-      EXPECT_TRUE(event->socket->SendData(&frame[0], frame.size()));
-    }
-    // Actual StreamSocket close must happen after all frames queued by
-    // SendData above are sent out.
-    event->socket->Close();
-  }
-
-  virtual void DoFailByTooBigDataAndClose(SocketStreamEvent* event) {
-    std::string frame(event->number + 1, 0x00);
-    VLOG(1) << event->number;
-    EXPECT_FALSE(event->socket->SendData(&frame[0], frame.size()));
-    event->socket->Close();
-  }
-
-  virtual int DoSwitchToSpdyTest(SocketStreamEvent* event) {
-    return ERR_PROTOCOL_SWITCHED;
-  }
-
-  // Notifies |io_test_callback_| of that this method is called, and keeps the
-  // SocketStream waiting.
-  virtual int DoIOPending(SocketStreamEvent* event) {
-    io_test_callback_.callback().Run(OK);
-    return ERR_IO_PENDING;
-  }
-
-  static const char kWebSocketHandshakeRequest[];
-  static const char kWebSocketHandshakeResponse[];
-
- protected:
-  TestCompletionCallback io_test_callback_;
-
- private:
-  std::string handshake_request_;
-  std::string handshake_response_;
-  std::vector<std::string> messages_;
-
-  scoped_ptr<MockClientSocketFactory> mock_socket_factory_;
-};
-
-const char SocketStreamTest::kWebSocketHandshakeRequest[] =
-    "GET /demo HTTP/1.1\r\n"
-    "Host: example.com\r\n"
-    "Connection: Upgrade\r\n"
-    "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n"
-    "Sec-WebSocket-Protocol: sample\r\n"
-    "Upgrade: WebSocket\r\n"
-    "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n"
-    "Origin: http://example.com\r\n"
-    "\r\n"
-    "^n:ds[4U";
-
-const char SocketStreamTest::kWebSocketHandshakeResponse[] =
-    "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
-    "Upgrade: WebSocket\r\n"
-    "Connection: Upgrade\r\n"
-    "Sec-WebSocket-Origin: http://example.com\r\n"
-    "Sec-WebSocket-Location: ws://example.com/demo\r\n"
-    "Sec-WebSocket-Protocol: sample\r\n"
-    "\r\n"
-    "8jKS'y:G*Co,Wxa-";
-
-TEST_F(SocketStreamTest, CloseFlushPendingWrite) {
-  TestCompletionCallback test_callback;
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  delegate->SetOnConnected(base::Bind(
-      &SocketStreamTest::DoSendWebSocketHandshake, base::Unretained(this)));
-  delegate->SetOnReceivedData(base::Bind(
-      &SocketStreamTest::DoCloseFlushPendingWriteTest,
-      base::Unretained(this)));
-
-  TestURLRequestContext context;
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  MockWrite data_writes[] = {
-    MockWrite(SocketStreamTest::kWebSocketHandshakeRequest),
-    MockWrite(ASYNC, "\0message1\xff", 10),
-    MockWrite(ASYNC, "\0message2\xff", 10)
-  };
-  MockRead data_reads[] = {
-    MockRead(SocketStreamTest::kWebSocketHandshakeResponse),
-    // Server doesn't close the connection after handshake.
-    MockRead(ASYNC, ERR_IO_PENDING)
-  };
-  AddWebSocketMessage("message1");
-  AddWebSocketMessage("message2");
-
-  DelayedSocketData data_provider(
-      1, data_reads, arraysize(data_reads),
-      data_writes, arraysize(data_writes));
-
-  MockClientSocketFactory* mock_socket_factory =
-      GetMockClientSocketFactory();
-  mock_socket_factory->AddSocketDataProvider(&data_provider);
-
-  socket_stream->SetClientSocketFactory(mock_socket_factory);
-
-  socket_stream->Connect();
-
-  test_callback.WaitForResult();
-
-  EXPECT_TRUE(data_provider.at_read_eof());
-  EXPECT_TRUE(data_provider.at_write_eof());
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(7U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[2].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_RECEIVED_DATA, events[3].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[4].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[5].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[6].event_type);
-}
-
-TEST_F(SocketStreamTest, ResolveFailure) {
-  TestCompletionCallback test_callback;
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-
-  // Make resolver fail.
-  TestURLRequestContext context;
-  scoped_ptr<MockHostResolver> mock_host_resolver(
-      new MockHostResolver());
-  mock_host_resolver->rules()->AddSimulatedFailure("example.com");
-  context.set_host_resolver(mock_host_resolver.get());
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  // No read/write on socket is expected.
-  StaticSocketDataProvider data_provider(NULL, 0, NULL, 0);
-  MockClientSocketFactory* mock_socket_factory =
-      GetMockClientSocketFactory();
-  mock_socket_factory->AddSocketDataProvider(&data_provider);
-  socket_stream->SetClientSocketFactory(mock_socket_factory);
-
-  socket_stream->Connect();
-
-  test_callback.WaitForResult();
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(2U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[1].event_type);
-}
-
-TEST_F(SocketStreamTest, ExceedMaxPendingSendAllowed) {
-  TestCompletionCallback test_callback;
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  delegate->SetOnConnected(base::Bind(
-      &SocketStreamTest::DoFailByTooBigDataAndClose, base::Unretained(this)));
-
-  TestURLRequestContext context;
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  DelayedSocketData data_provider(1, NULL, 0, NULL, 0);
-
-  MockClientSocketFactory* mock_socket_factory =
-      GetMockClientSocketFactory();
-  mock_socket_factory->AddSocketDataProvider(&data_provider);
-
-  socket_stream->SetClientSocketFactory(mock_socket_factory);
-
-  socket_stream->Connect();
-
-  test_callback.WaitForResult();
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(4U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[2].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type);
-}
-
-TEST_F(SocketStreamTest, BasicAuthProxy) {
-  MockClientSocketFactory mock_socket_factory;
-  MockWrite data_writes1[] = {
-    MockWrite("CONNECT example.com:80 HTTP/1.1\r\n"
-              "Host: example.com\r\n"
-              "Proxy-Connection: keep-alive\r\n\r\n"),
-  };
-  MockRead data_reads1[] = {
-    MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
-    MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
-    MockRead("\r\n"),
-  };
-  StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
-                                 data_writes1, arraysize(data_writes1));
-  mock_socket_factory.AddSocketDataProvider(&data1);
-
-  MockWrite data_writes2[] = {
-    MockWrite("CONNECT example.com:80 HTTP/1.1\r\n"
-              "Host: example.com\r\n"
-              "Proxy-Connection: keep-alive\r\n"
-              "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
-  };
-  MockRead data_reads2[] = {
-    MockRead("HTTP/1.1 200 Connection Established\r\n"),
-    MockRead("Proxy-agent: Apache/2.2.8\r\n"),
-    MockRead("\r\n"),
-    // SocketStream::DoClose is run asynchronously.  Socket can be read after
-    // "\r\n".  We have to give ERR_IO_PENDING to SocketStream then to indicate
-    // server doesn't close the connection.
-    MockRead(ASYNC, ERR_IO_PENDING)
-  };
-  StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
-                                 data_writes2, arraysize(data_writes2));
-  mock_socket_factory.AddSocketDataProvider(&data2);
-
-  TestCompletionCallback test_callback;
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose,
-                                      base::Unretained(delegate.get())));
-  delegate->SetAuthInfo(AuthCredentials(ASCIIToUTF16("foo"),
-                                        ASCIIToUTF16("bar")));
-  delegate->SetOnAuthRequired(base::Bind(
-      &SocketStreamEventRecorder::DoRestartWithAuth,
-      base::Unretained(delegate.get())));
-
-  TestURLRequestContextWithProxy context("myproxy:70");
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  socket_stream->SetClientSocketFactory(&mock_socket_factory);
-
-  socket_stream->Connect();
-
-  test_callback.WaitForResult();
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(5U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_AUTH_REQUIRED, events[1].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[2].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[3].event_type);
-  EXPECT_EQ(ERR_ABORTED, events[3].error_code);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[4].event_type);
-
-  // TODO(eroman): Add back NetLogTest here...
-}
-
-TEST_F(SocketStreamTest, BasicAuthProxyWithAuthCache) {
-  MockClientSocketFactory mock_socket_factory;
-  MockWrite data_writes[] = {
-    // WebSocket(SocketStream) always uses CONNECT when it is configured to use
-    // proxy so the port may not be 443.
-    MockWrite("CONNECT example.com:80 HTTP/1.1\r\n"
-              "Host: example.com\r\n"
-              "Proxy-Connection: keep-alive\r\n"
-              "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
-  };
-  MockRead data_reads[] = {
-    MockRead("HTTP/1.1 200 Connection Established\r\n"),
-    MockRead("Proxy-agent: Apache/2.2.8\r\n"),
-    MockRead("\r\n"),
-    MockRead(ASYNC, ERR_IO_PENDING)
-  };
-  StaticSocketDataProvider data(data_reads, arraysize(data_reads),
-                                 data_writes, arraysize(data_writes));
-  mock_socket_factory.AddSocketDataProvider(&data);
-
-  TestCompletionCallback test_callback;
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose,
-                                      base::Unretained(delegate.get())));
-
-  TestURLRequestContextWithProxy context("myproxy:70");
-  HttpAuthCache* auth_cache =
-      context.http_transaction_factory()->GetSession()->http_auth_cache();
-  auth_cache->Add(GURL("http://myproxy:70"),
-                  "MyRealm1",
-                  HttpAuth::AUTH_SCHEME_BASIC,
-                  "Basic realm=MyRealm1",
-                  AuthCredentials(ASCIIToUTF16("foo"),
-                                  ASCIIToUTF16("bar")),
-                  "/");
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  socket_stream->SetClientSocketFactory(&mock_socket_factory);
-
-  socket_stream->Connect();
-
-  test_callback.WaitForResult();
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(4U, events.size());
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
-  EXPECT_EQ(ERR_ABORTED, events[2].error_code);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type);
-}
-
-TEST_F(SocketStreamTest, WSSBasicAuthProxyWithAuthCache) {
-  MockClientSocketFactory mock_socket_factory;
-  MockWrite data_writes1[] = {
-    MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
-              "Host: example.com\r\n"
-              "Proxy-Connection: keep-alive\r\n"
-              "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
-  };
-  MockRead data_reads1[] = {
-    MockRead("HTTP/1.1 200 Connection Established\r\n"),
-    MockRead("Proxy-agent: Apache/2.2.8\r\n"),
-    MockRead("\r\n"),
-    MockRead(ASYNC, ERR_IO_PENDING)
-  };
-  StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
-                                 data_writes1, arraysize(data_writes1));
-  mock_socket_factory.AddSocketDataProvider(&data1);
-
-  SSLSocketDataProvider data2(ASYNC, OK);
-  mock_socket_factory.AddSSLSocketDataProvider(&data2);
-
-  TestCompletionCallback test_callback;
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose,
-                                      base::Unretained(delegate.get())));
-
-  TestURLRequestContextWithProxy context("myproxy:70");
-  HttpAuthCache* auth_cache =
-      context.http_transaction_factory()->GetSession()->http_auth_cache();
-  auth_cache->Add(GURL("http://myproxy:70"),
-                  "MyRealm1",
-                  HttpAuth::AUTH_SCHEME_BASIC,
-                  "Basic realm=MyRealm1",
-                  AuthCredentials(ASCIIToUTF16("foo"),
-                                  ASCIIToUTF16("bar")),
-                  "/");
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("wss://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  socket_stream->SetClientSocketFactory(&mock_socket_factory);
-
-  socket_stream->Connect();
-
-  test_callback.WaitForResult();
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(4U, events.size());
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
-  EXPECT_EQ(ERR_ABORTED, events[2].error_code);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type);
-}
-
-TEST_F(SocketStreamTest, IOPending) {
-  TestCompletionCallback test_callback;
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  delegate->SetOnStartOpenConnection(base::Bind(
-      &SocketStreamTest::DoIOPending, base::Unretained(this)));
-  delegate->SetOnConnected(base::Bind(
-      &SocketStreamTest::DoSendWebSocketHandshake, base::Unretained(this)));
-  delegate->SetOnReceivedData(base::Bind(
-      &SocketStreamTest::DoCloseFlushPendingWriteTest,
-      base::Unretained(this)));
-
-  TestURLRequestContext context;
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  MockWrite data_writes[] = {
-    MockWrite(SocketStreamTest::kWebSocketHandshakeRequest),
-    MockWrite(ASYNC, "\0message1\xff", 10),
-    MockWrite(ASYNC, "\0message2\xff", 10)
-  };
-  MockRead data_reads[] = {
-    MockRead(SocketStreamTest::kWebSocketHandshakeResponse),
-    // Server doesn't close the connection after handshake.
-    MockRead(ASYNC, ERR_IO_PENDING)
-  };
-  AddWebSocketMessage("message1");
-  AddWebSocketMessage("message2");
-
-  DelayedSocketData data_provider(
-      1, data_reads, arraysize(data_reads),
-      data_writes, arraysize(data_writes));
-
-  MockClientSocketFactory* mock_socket_factory =
-      GetMockClientSocketFactory();
-  mock_socket_factory->AddSocketDataProvider(&data_provider);
-
-  socket_stream->SetClientSocketFactory(mock_socket_factory);
-
-  socket_stream->Connect();
-  io_test_callback_.WaitForResult();
-  EXPECT_EQ(SocketStream::STATE_RESOLVE_PROTOCOL_COMPLETE,
-            socket_stream->next_state_);
-  delegate->CompleteConnection(OK);
-
-  EXPECT_EQ(OK, test_callback.WaitForResult());
-
-  EXPECT_TRUE(data_provider.at_read_eof());
-  EXPECT_TRUE(data_provider.at_write_eof());
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(7U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[2].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_RECEIVED_DATA, events[3].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[4].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[5].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[6].event_type);
-}
-
-TEST_F(SocketStreamTest, SwitchToSpdy) {
-  TestCompletionCallback test_callback;
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  delegate->SetOnStartOpenConnection(base::Bind(
-      &SocketStreamTest::DoSwitchToSpdyTest, base::Unretained(this)));
-
-  TestURLRequestContext context;
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  socket_stream->Connect();
-
-  EXPECT_EQ(ERR_PROTOCOL_SWITCHED, test_callback.WaitForResult());
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(2U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[1].event_type);
-  EXPECT_EQ(ERR_PROTOCOL_SWITCHED, events[1].error_code);
-}
-
-TEST_F(SocketStreamTest, SwitchAfterPending) {
-  TestCompletionCallback test_callback;
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  delegate->SetOnStartOpenConnection(base::Bind(
-      &SocketStreamTest::DoIOPending, base::Unretained(this)));
-
-  TestURLRequestContext context;
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  socket_stream->Connect();
-  io_test_callback_.WaitForResult();
-
-  EXPECT_EQ(SocketStream::STATE_RESOLVE_PROTOCOL_COMPLETE,
-            socket_stream->next_state_);
-  delegate->CompleteConnection(ERR_PROTOCOL_SWITCHED);
-
-  EXPECT_EQ(ERR_PROTOCOL_SWITCHED, test_callback.WaitForResult());
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(2U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[1].event_type);
-  EXPECT_EQ(ERR_PROTOCOL_SWITCHED, events[1].error_code);
-}
-
-// Test a connection though a secure proxy.
-TEST_F(SocketStreamTest, SecureProxyConnectError) {
-  MockClientSocketFactory mock_socket_factory;
-  MockWrite data_writes[] = {
-    MockWrite("CONNECT example.com:80 HTTP/1.1\r\n"
-              "Host: example.com\r\n"
-              "Proxy-Connection: keep-alive\r\n\r\n")
-  };
-  MockRead data_reads[] = {
-    MockRead("HTTP/1.1 200 Connection Established\r\n"),
-    MockRead("Proxy-agent: Apache/2.2.8\r\n"),
-    MockRead("\r\n"),
-    // SocketStream::DoClose is run asynchronously.  Socket can be read after
-    // "\r\n".  We have to give ERR_IO_PENDING to SocketStream then to indicate
-    // server doesn't close the connection.
-    MockRead(ASYNC, ERR_IO_PENDING)
-  };
-  StaticSocketDataProvider data(data_reads, arraysize(data_reads),
-                                data_writes, arraysize(data_writes));
-  mock_socket_factory.AddSocketDataProvider(&data);
-  SSLSocketDataProvider ssl(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
-  mock_socket_factory.AddSSLSocketDataProvider(&ssl);
-
-  TestCompletionCallback test_callback;
-  TestURLRequestContextWithProxy context("https://myproxy:70");
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose,
-                                      base::Unretained(delegate.get())));
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  socket_stream->SetClientSocketFactory(&mock_socket_factory);
-
-  socket_stream->Connect();
-
-  test_callback.WaitForResult();
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(3U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[1].event_type);
-  EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, events[1].error_code);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[2].event_type);
-}
-
-// Test a connection though a secure proxy.
-TEST_F(SocketStreamTest, SecureProxyConnect) {
-  MockClientSocketFactory mock_socket_factory;
-  MockWrite data_writes[] = {
-    MockWrite("CONNECT example.com:80 HTTP/1.1\r\n"
-              "Host: example.com\r\n"
-              "Proxy-Connection: keep-alive\r\n\r\n")
-  };
-  MockRead data_reads[] = {
-    MockRead("HTTP/1.1 200 Connection Established\r\n"),
-    MockRead("Proxy-agent: Apache/2.2.8\r\n"),
-    MockRead("\r\n"),
-    // SocketStream::DoClose is run asynchronously.  Socket can be read after
-    // "\r\n".  We have to give ERR_IO_PENDING to SocketStream then to indicate
-    // server doesn't close the connection.
-    MockRead(ASYNC, ERR_IO_PENDING)
-  };
-  StaticSocketDataProvider data(data_reads, arraysize(data_reads),
-                                data_writes, arraysize(data_writes));
-  mock_socket_factory.AddSocketDataProvider(&data);
-  SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
-  mock_socket_factory.AddSSLSocketDataProvider(&ssl);
-
-  TestCompletionCallback test_callback;
-  TestURLRequestContextWithProxy context("https://myproxy:70");
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose,
-                                      base::Unretained(delegate.get())));
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  socket_stream->SetClientSocketFactory(&mock_socket_factory);
-
-  socket_stream->Connect();
-
-  test_callback.WaitForResult();
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(4U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[2].event_type);
-  EXPECT_EQ(ERR_ABORTED, events[2].error_code);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type);
-}
-
-TEST_F(SocketStreamTest, BeforeConnectFailed) {
-  TestCompletionCallback test_callback;
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-
-  TestURLRequestContext context;
-  TestSocketStreamNetworkDelegate network_delegate;
-  network_delegate.SetBeforeConnectResult(ERR_ACCESS_DENIED);
-  context.set_network_delegate(&network_delegate);
-
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-
-  socket_stream->Connect();
-
-  test_callback.WaitForResult();
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(2U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[0].event_type);
-  EXPECT_EQ(ERR_ACCESS_DENIED, events[0].error_code);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[1].event_type);
-}
-
-// Check that a connect failure, followed by the delegate calling DetachDelegate
-// and deleting itself in the OnError callback, is handled correctly.
-TEST_F(SocketStreamTest, OnErrorDetachDelegate) {
-  MockClientSocketFactory mock_socket_factory;
-  TestCompletionCallback test_callback;
-
-  // SelfDeletingDelegate is self-owning; we just need a pointer to it to
-  // connect it and the SocketStream.
-  SelfDeletingDelegate* delegate =
-      new SelfDeletingDelegate(test_callback.callback());
-  MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
-  StaticSocketDataProvider data;
-  data.set_connect_data(mock_connect);
-  mock_socket_factory.AddSocketDataProvider(&data);
-
-  TestURLRequestContext context;
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://localhost:9998/echo"), delegate,
-                       &context, NULL));
-  socket_stream->SetClientSocketFactory(&mock_socket_factory);
-  delegate->set_socket_stream(socket_stream);
-  // The delegate pointer will become invalid during the test. Set it to NULL to
-  // avoid holding a dangling pointer.
-  delegate = NULL;
-
-  socket_stream->Connect();
-
-  EXPECT_EQ(OK, test_callback.WaitForResult());
-}
-
-TEST_F(SocketStreamTest, NullContextSocketStreamShouldNotCrash) {
-  TestCompletionCallback test_callback;
-
-  scoped_ptr<SocketStreamEventRecorder> delegate(
-      new SocketStreamEventRecorder(test_callback.callback()));
-  TestURLRequestContext context;
-  scoped_refptr<SocketStream> socket_stream(
-      new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
-                       &context, NULL));
-  delegate->SetOnStartOpenConnection(base::Bind(
-      &SocketStreamTest::DoIOPending, base::Unretained(this)));
-  delegate->SetOnConnected(base::Bind(
-      &SocketStreamTest::DoSendWebSocketHandshake, base::Unretained(this)));
-  delegate->SetOnReceivedData(base::Bind(
-      &SocketStreamTest::DoCloseFlushPendingWriteTestWithSetContextNull,
-      base::Unretained(this)));
-
-  MockWrite data_writes[] = {
-    MockWrite(SocketStreamTest::kWebSocketHandshakeRequest),
-  };
-  MockRead data_reads[] = {
-    MockRead(SocketStreamTest::kWebSocketHandshakeResponse),
-  };
-  AddWebSocketMessage("message1");
-  AddWebSocketMessage("message2");
-
-  DelayedSocketData data_provider(
-      1, data_reads, arraysize(data_reads),
-      data_writes, arraysize(data_writes));
-
-  MockClientSocketFactory* mock_socket_factory = GetMockClientSocketFactory();
-  mock_socket_factory->AddSocketDataProvider(&data_provider);
-  socket_stream->SetClientSocketFactory(mock_socket_factory);
-
-  socket_stream->Connect();
-  io_test_callback_.WaitForResult();
-  delegate->CompleteConnection(OK);
-  EXPECT_EQ(OK, test_callback.WaitForResult());
-
-  EXPECT_TRUE(data_provider.at_read_eof());
-  EXPECT_TRUE(data_provider.at_write_eof());
-
-  const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
-  ASSERT_EQ(5U, events.size());
-
-  EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
-            events[0].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[2].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_RECEIVED_DATA, events[3].event_type);
-  EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[4].event_type);
-}
-
-}  // namespace net
diff --git a/net/spdy/buffered_spdy_framer.cc b/net/spdy/buffered_spdy_framer.cc
index fdc65a9..f3fc575 100644
--- a/net/spdy/buffered_spdy_framer.cc
+++ b/net/spdy/buffered_spdy_framer.cc
@@ -15,7 +15,8 @@
     case kProtoSPDY3:
     case kProtoSPDY31:
       return SPDY3;
-    case kProtoSPDY4:
+    case kProtoSPDY4_14:
+    case kProtoSPDY4_15:
       return SPDY4;
     case kProtoUnknown:
     case kProtoHTTP11:
@@ -76,6 +77,8 @@
 }
 
 void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id,
+                                   bool has_priority,
+                                   SpdyPriority priority,
                                    bool fin,
                                    bool end) {
   frames_received_++;
@@ -83,6 +86,10 @@
   control_frame_fields_.reset(new ControlFrameFields());
   control_frame_fields_->type = HEADERS;
   control_frame_fields_->stream_id = stream_id;
+  control_frame_fields_->has_priority = has_priority;
+  if (control_frame_fields_->has_priority) {
+    control_frame_fields_->priority = priority;
+  }
   control_frame_fields_->fin = fin;
 
   InitHeaderStreaming(stream_id);
@@ -136,6 +143,8 @@
         break;
       case HEADERS:
         visitor_->OnHeaders(control_frame_fields_->stream_id,
+                            control_frame_fields_->has_priority,
+                            control_frame_fields_->priority,
                             control_frame_fields_->fin,
                             headers);
         break;
@@ -346,9 +355,14 @@
 SpdyFrame* BufferedSpdyFramer::CreateHeaders(
     SpdyStreamId stream_id,
     SpdyControlFlags flags,
+    SpdyPriority priority,
     const SpdyHeaderBlock* headers) {
   SpdyHeadersIR headers_ir(stream_id);
   headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0);
+  if (flags & HEADERS_FLAG_PRIORITY) {
+    headers_ir.set_has_priority(true);
+    headers_ir.set_priority(priority);
+  }
   headers_ir.set_name_value_block(*headers);
   return spdy_framer_.SerializeHeaders(headers_ir);
 }
diff --git a/net/spdy/buffered_spdy_framer.h b/net/spdy/buffered_spdy_framer.h
index 02fa583..1227a42 100644
--- a/net/spdy/buffered_spdy_framer.h
+++ b/net/spdy/buffered_spdy_framer.h
@@ -49,6 +49,8 @@
 
   // Called after all the header data for HEADERS control frame is received.
   virtual void OnHeaders(SpdyStreamId stream_id,
+                         bool has_priority,
+                         SpdyPriority priority,
                          bool fin,
                          const SpdyHeaderBlock& headers) = 0;
 
@@ -142,7 +144,11 @@
                    bool fin,
                    bool unidirectional) override;
   void OnSynReply(SpdyStreamId stream_id, bool fin) override;
-  void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) override;
+  void OnHeaders(SpdyStreamId stream_id,
+                 bool has_priority,
+                 SpdyPriority priority,
+                 bool fin,
+                 bool end) override;
   bool OnControlFrameHeaderData(SpdyStreamId stream_id,
                                 const char* header_data,
                                 size_t len) override;
@@ -194,6 +200,7 @@
       SpdyGoAwayStatus status) const;
   SpdyFrame* CreateHeaders(SpdyStreamId stream_id,
                            SpdyControlFlags flags,
+                           SpdyPriority priority,
                            const SpdyHeaderBlock* headers);
   SpdyFrame* CreateWindowUpdate(
       SpdyStreamId stream_id,
@@ -262,6 +269,7 @@
     SpdyStreamId stream_id;
     SpdyStreamId associated_stream_id;
     SpdyStreamId promised_stream_id;
+    bool has_priority;
     SpdyPriority priority;
     uint8 credential_slot;
     bool fin;
diff --git a/net/spdy/buffered_spdy_framer_unittest.cc b/net/spdy/buffered_spdy_framer_unittest.cc
index 6be20dd..11f8d08 100644
--- a/net/spdy/buffered_spdy_framer_unittest.cc
+++ b/net/spdy/buffered_spdy_framer_unittest.cc
@@ -59,6 +59,8 @@
   }
 
   void OnHeaders(SpdyStreamId stream_id,
+                 bool has_priority,
+                 SpdyPriority priority,
                  bool fin,
                  const SpdyHeaderBlock& headers) override {
     header_stream_id_ = stream_id;
@@ -207,7 +209,7 @@
     NextProto,
     BufferedSpdyFramerTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 TEST_P(BufferedSpdyFramerTest, OnSetting) {
   SpdyFramer framer(spdy_version());
@@ -293,6 +295,7 @@
   scoped_ptr<SpdyFrame> control_frame(
       framer.CreateHeaders(1,                        // stream_id
                            CONTROL_FLAG_NONE,
+                           0,                        // priority
                            &headers));
   EXPECT_TRUE(control_frame.get() != NULL);
 
diff --git a/net/spdy/mock_spdy_framer_visitor.h b/net/spdy/mock_spdy_framer_visitor.h
index b8467ba..480c367 100644
--- a/net/spdy/mock_spdy_framer_visitor.h
+++ b/net/spdy/mock_spdy_framer_visitor.h
@@ -42,7 +42,8 @@
   MOCK_METHOD0(OnSettingsEnd, void());
   MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
                               SpdyGoAwayStatus status));
-  MOCK_METHOD3(OnHeaders, void(SpdyStreamId stream_id, bool fin, bool end));
+  MOCK_METHOD5(OnHeaders, void(SpdyStreamId stream_id, bool has_priority,
+                               SpdyPriority priority, bool fin, bool end));
   MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id,
                                     uint32 delta_window_size));
   MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index de7a7a3..c08b597 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -480,6 +480,10 @@
       return "CONNECT_ERROR";
     case RST_STREAM_ENHANCE_YOUR_CALM:
       return "ENHANCE_YOUR_CALM";
+    case RST_STREAM_INADEQUATE_SECURITY:
+      return "INADEQUATE_SECURITY";
+    case RST_STREAM_HTTP_1_1_REQUIRED:
+      return "HTTP_1_1_REQUIRED";
   }
   return "UNKNOWN_STATUS";
 }
@@ -1497,33 +1501,19 @@
           }
           DCHECK(reader.IsDoneReading());
           if (debug_visitor_) {
-            // SPDY 4 reports HEADERS with PRIORITY as SYN_STREAM.
-            SpdyFrameType reported_type = current_frame_type_;
-            if (protocol_version() > SPDY3 && has_priority) {
-              reported_type = SYN_STREAM;
-            }
             debug_visitor_->OnReceiveCompressedFrame(
                 current_frame_stream_id_,
-                reported_type,
+                current_frame_type_,
                 current_frame_length_);
           }
           if (current_frame_type_ == SYN_REPLY) {
             visitor_->OnSynReply(
                 current_frame_stream_id_,
                 (current_frame_flags_ & CONTROL_FLAG_FIN) != 0);
-          } else if (protocol_version() > SPDY3 &&
-              current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
-            // SPDY 4+ is missing SYN_STREAM. Simulate it so that API changes
-            // can be made independent of wire changes.
-            visitor_->OnSynStream(
-                current_frame_stream_id_,
-                0,  // associated_to_stream_id
-                priority,
-                current_frame_flags_ & CONTROL_FLAG_FIN,
-                false);  // unidirectional
           } else {
             visitor_->OnHeaders(
                 current_frame_stream_id_,
+                (current_frame_flags_ & HEADERS_FLAG_PRIORITY) != 0, priority,
                 (current_frame_flags_ & CONTROL_FLAG_FIN) != 0,
                 expect_continuation_ == 0);
           }
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index 29cab72..dcb2911 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -37,8 +37,6 @@
 class SpdyProxyClientSocketTest;
 class SpdySessionTest;
 class SpdyStreamTest;
-class SpdyWebSocketStreamTest;
-class WebSocketJobTest;
 
 class SpdyFramer;
 class SpdyFrameBuilder;
@@ -237,7 +235,11 @@
   // Called when a HEADERS frame is received.
   // Note that header block data is not included. See
   // OnControlFrameHeaderData().
-  virtual void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) = 0;
+  virtual void OnHeaders(SpdyStreamId stream_id,
+                         bool has_priority,
+                         SpdyPriority priority,
+                         bool fin,
+                         bool end) = 0;
 
   // Called when a WINDOW_UPDATE frame has been parsed.
   virtual void OnWindowUpdate(SpdyStreamId stream_id,
@@ -612,16 +614,14 @@
                            TooLargeHeadersFrameUsesContinuation);
   FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
                            TooLargePushPromiseFrameUsesContinuation);
-  friend class net::HttpNetworkLayer;  // This is temporary for the server.
-  friend class net::HttpNetworkTransactionTest;
-  friend class net::HttpProxyClientSocketPoolTest;
-  friend class net::SpdyHttpStreamTest;
-  friend class net::SpdyNetworkTransactionTest;
-  friend class net::SpdyProxyClientSocketTest;
-  friend class net::SpdySessionTest;
-  friend class net::SpdyStreamTest;
-  friend class net::SpdyWebSocketStreamTest;
-  friend class net::WebSocketJobTest;
+  friend class HttpNetworkLayer;  // This is temporary for the server.
+  friend class HttpNetworkTransactionTest;
+  friend class HttpProxyClientSocketPoolTest;
+  friend class SpdyHttpStreamTest;
+  friend class SpdyNetworkTransactionTest;
+  friend class SpdyProxyClientSocketTest;
+  friend class SpdySessionTest;
+  friend class SpdyStreamTest;
   friend class test::TestSpdyVisitor;
 
  private:
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 7a1c3df..2b7bc4b 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -154,10 +154,15 @@
       LOG(FATAL);
     }
 
-    void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) override {
+    void OnHeaders(SpdyStreamId stream_id, bool has_priority,
+                   SpdyPriority priority, bool fin, bool end) override {
       SpdyFramer framer(version_);
       framer.set_enable_compression(false);
       SpdyHeadersIR headers(stream_id);
+      headers.set_has_priority(has_priority);
+      if (headers.has_priority()) {
+        headers.set_priority(priority);
+      }
       headers.set_fin(fin);
       scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers));
       ResetBuffer();
@@ -389,7 +394,8 @@
     ++goaway_count_;
   }
 
-  void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) override {
+  void OnHeaders(SpdyStreamId stream_id, bool has_priority,
+                 SpdyPriority priority, bool fin, bool end) override {
     ++headers_frame_count_;
     InitHeaderStreaming(HEADERS, stream_id);
     if (fin) {
@@ -1225,18 +1231,19 @@
     visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
   }
 
-  EXPECT_EQ(2, visitor.syn_frame_count_);
   EXPECT_EQ(0, visitor.syn_reply_frame_count_);
-  EXPECT_EQ(1, visitor.headers_frame_count_);
   EXPECT_EQ(24, visitor.data_bytes_);
-
   EXPECT_EQ(0, visitor.error_count_);
   EXPECT_EQ(2, visitor.fin_frame_count_);
 
   if (IsSpdy4()) {
+    EXPECT_EQ(3, visitor.headers_frame_count_);
+    EXPECT_EQ(0, visitor.syn_frame_count_);
     base::StringPiece reset_stream = "RESETSTREAM";
     EXPECT_EQ(reset_stream, visitor.fin_opaque_data_);
   } else {
+    EXPECT_EQ(1, visitor.headers_frame_count_);
+    EXPECT_EQ(2, visitor.syn_frame_count_);
     EXPECT_TRUE(visitor.fin_opaque_data_.empty());
   }
 
@@ -1339,11 +1346,12 @@
   }
 
   EXPECT_EQ(0, visitor.error_count_);
-  EXPECT_EQ(1, visitor.syn_frame_count_);
   if (IsSpdy4()) {
+    EXPECT_EQ(0, visitor.syn_frame_count_);
     EXPECT_EQ(0, visitor.syn_reply_frame_count_);
-    EXPECT_EQ(1, visitor.headers_frame_count_);
+    EXPECT_EQ(2, visitor.headers_frame_count_);
   } else {
+    EXPECT_EQ(1, visitor.syn_frame_count_);
     EXPECT_EQ(1, visitor.syn_reply_frame_count_);
     EXPECT_EQ(0, visitor.headers_frame_count_);
   }
@@ -1418,11 +1426,12 @@
   }
 
   EXPECT_EQ(0, visitor.error_count_);
-  EXPECT_EQ(1, visitor.syn_frame_count_);
   if (IsSpdy4()) {
+    EXPECT_EQ(0, visitor.syn_frame_count_);
     EXPECT_EQ(0, visitor.syn_reply_frame_count_);
-    EXPECT_EQ(1, visitor.headers_frame_count_);
+    EXPECT_EQ(2, visitor.headers_frame_count_);
   } else {
+    EXPECT_EQ(1, visitor.syn_frame_count_);
     EXPECT_EQ(1, visitor.syn_reply_frame_count_);
     EXPECT_EQ(0, visitor.headers_frame_count_);
   }
@@ -5210,13 +5219,14 @@
       EXPECT_CALL(visitor, OnError(_));
     } else {
       if (spdy_version_ > SPDY3 && flags & HEADERS_FLAG_PRIORITY) {
-        EXPECT_CALL(visitor, OnSynStream(57,        // stream id
-                                         0,         // associated stream id
-                                         3,         // priority
-                                         flags & CONTROL_FLAG_FIN,
-                                         false));  // unidirectional
+        EXPECT_CALL(visitor, OnHeaders(57,    // stream id
+                                       true,  // has priority?
+                                       3,     // priority
+                                       flags & CONTROL_FLAG_FIN,  // fin?
+                                       (flags & HEADERS_FLAG_END_HEADERS) ||
+                                           !IsSpdy4()));  // end headers?
       } else {
-        EXPECT_CALL(visitor, OnHeaders(57,
+        EXPECT_CALL(visitor, OnHeaders(57, false, 0,
                                        flags & CONTROL_FLAG_FIN,
                                        (flags & HEADERS_FLAG_END_HEADERS) ||
                                         !IsSpdy4()));
@@ -5391,7 +5401,7 @@
 
     EXPECT_CALL(debug_visitor, OnSendCompressedFrame(42, HEADERS, _, _));
     EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(42, HEADERS, _));
-    EXPECT_CALL(visitor, OnHeaders(42, 0, false));
+    EXPECT_CALL(visitor, OnHeaders(42, false, 0, 0, false));
     EXPECT_CALL(visitor, OnControlFrameHeaderData(42, _, _))
           .WillRepeatedly(testing::Return(true));
 
diff --git a/net/spdy/spdy_headers_block_parser_test.cc b/net/spdy/spdy_headers_block_parser_test.cc
index d8cbe31..dc2cbb5 100644
--- a/net/spdy/spdy_headers_block_parser_test.cc
+++ b/net/spdy/spdy_headers_block_parser_test.cc
@@ -17,8 +17,6 @@
 using base::IntToString;
 using base::StringPiece;
 using std::string;
-using testing::ElementsAre;
-using testing::ElementsAreArray;
 
 // A mock the handler class to check that we parse out the correct headers
 // and call the callback methods when we should.
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index 0e8fdb0..574b76a 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -131,7 +131,7 @@
     NextProto,
     SpdyHttpStreamTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 // SpdyHttpStream::GetUploadProgress() should still work even before the
 // stream is initialized.
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index a68615f..edb39e9 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -726,9 +726,12 @@
         SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNOSSL),
         SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYSSL),
         SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN),
-        SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNOSSL),
-        SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYSSL),
-        SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNPN)));
+        SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYNOSSL),
+        SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYSSL),
+        SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYNPN),
+        SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYNOSSL),
+        SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYSSL),
+        SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYNPN)));
 
 // Verify HttpNetworkTransaction constructor.
 TEST_P(SpdyNetworkTransactionTest, Constructor) {
@@ -3576,7 +3579,7 @@
 }
 
 TEST_P(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
-  if (GetParam().protocol < kProtoSPDY4) {
+  if (GetParam().protocol < kProtoSPDY4MinimumVersion) {
     // Decompression failures are a stream error in SPDY3 and above.
     return;
   }
@@ -4433,7 +4436,8 @@
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
 
   std::vector<MockWrite> writes;
-  if (GetParam().protocol == kProtoSPDY4) {
+  if ((GetParam().protocol >= kProtoSPDY4MinimumVersion) &&
+      (GetParam().protocol <= kProtoSPDY4MaximumVersion)) {
     writes.push_back(
         MockWrite(ASYNC,
                   kHttp2ConnectionHeaderPrefix,
@@ -6599,7 +6603,9 @@
 INSTANTIATE_TEST_CASE_P(
     Spdy,
     SpdyNetworkTransactionTLSUsageCheckTest,
-    ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNPN)));
+    ::testing::Values(
+        SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYNPN),
+        SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYNPN)));
 
 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
   scoped_ptr<SSLSocketDataProvider> ssl_provider(
diff --git a/net/spdy/spdy_protocol.cc b/net/spdy/spdy_protocol.cc
index d300a15..bf33d43 100644
--- a/net/spdy/spdy_protocol.cc
+++ b/net/spdy/spdy_protocol.cc
@@ -372,9 +372,9 @@
       }
       */
 
-      // ENHANCE_YOUR_CALM is the last valid status code.
+      // HTTP_1_1_REQUIRED is the last valid status code.
       if (rst_stream_status_field >
-          SerializeRstStreamStatus(version, RST_STREAM_ENHANCE_YOUR_CALM)) {
+          SerializeRstStreamStatus(version, RST_STREAM_HTTP_1_1_REQUIRED)) {
         return false;
       }
 
@@ -436,6 +436,10 @@
           return RST_STREAM_CONNECT_ERROR;
         case 11:
           return RST_STREAM_ENHANCE_YOUR_CALM;
+        case 12:
+          return RST_STREAM_INADEQUATE_SECURITY;
+        case 13:
+          return RST_STREAM_HTTP_1_1_REQUIRED;
       }
       break;
   }
@@ -499,6 +503,10 @@
           return 10;
         case RST_STREAM_ENHANCE_YOUR_CALM:
           return 11;
+        case RST_STREAM_INADEQUATE_SECURITY:
+          return 12;
+        case RST_STREAM_HTTP_1_1_REQUIRED:
+          return 13;
         default:
           LOG(DFATAL) << "Unhandled RST_STREAM status "
                       << rst_stream_status;
@@ -589,6 +597,8 @@
           return GOAWAY_ENHANCE_YOUR_CALM;
         case 12:
           return GOAWAY_INADEQUATE_SECURITY;
+        case 13:
+          return GOAWAY_HTTP_1_1_REQUIRED;
       }
       break;
   }
@@ -666,6 +676,7 @@
         case GOAWAY_CONNECT_ERROR:
         case GOAWAY_ENHANCE_YOUR_CALM:
         case GOAWAY_INADEQUATE_SECURITY:
+        case GOAWAY_HTTP_1_1_REQUIRED:
           return 1;  // PROTOCOL_ERROR.
         default:
           LOG(DFATAL) << "Serializing unhandled GOAWAY status " << status;
@@ -700,6 +711,8 @@
           return 11;
         case GOAWAY_INADEQUATE_SECURITY:
           return 12;
+        case GOAWAY_HTTP_1_1_REQUIRED:
+          return 13;
         default:
           LOG(DFATAL) << "Serializing unhandled GOAWAY status " << status;
           return -1;
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h
index b3f71d4..b02c44f 100644
--- a/net/spdy/spdy_protocol.h
+++ b/net/spdy/spdy_protocol.h
@@ -397,7 +397,9 @@
   RST_STREAM_SETTINGS_TIMEOUT = 12,
   RST_STREAM_CONNECT_ERROR = 13,
   RST_STREAM_ENHANCE_YOUR_CALM = 14,
-  RST_STREAM_NUM_STATUS_CODES = 15
+  RST_STREAM_INADEQUATE_SECURITY = 15,
+  RST_STREAM_HTTP_1_1_REQUIRED = 16,
+  RST_STREAM_NUM_STATUS_CODES = 17
 };
 
 // Status codes for GOAWAY frames.
@@ -415,7 +417,8 @@
   GOAWAY_COMPRESSION_ERROR = 9,
   GOAWAY_CONNECT_ERROR = 10,
   GOAWAY_ENHANCE_YOUR_CALM = 11,
-  GOAWAY_INADEQUATE_SECURITY = 12
+  GOAWAY_INADEQUATE_SECURITY = 12,
+  GOAWAY_HTTP_1_1_REQUIRED = 13
 };
 
 // A SPDY priority is a number between 0 and 7 (inclusive).
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index 92e446e..ba5d867 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -143,7 +143,7 @@
     NextProto,
     SpdyProxyClientSocketTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 SpdyProxyClientSocketTest::SpdyProxyClientSocketTest()
     : spdy_util_(GetParam()),
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index d9a5108..08d838a 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -398,6 +398,10 @@
       return STATUS_CODE_CONNECT_ERROR;
     case RST_STREAM_ENHANCE_YOUR_CALM:
       return STATUS_CODE_ENHANCE_YOUR_CALM;
+    case RST_STREAM_INADEQUATE_SECURITY:
+      return STATUS_CODE_INADEQUATE_SECURITY;
+    case RST_STREAM_HTTP_1_1_REQUIRED:
+      return STATUS_CODE_HTTP_1_1_REQUIRED;
     default:
       NOTREACHED();
       return static_cast<SpdyProtocolErrorDetails>(-1);
@@ -721,7 +725,8 @@
   DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
   DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
 
-  if (protocol_ == kProtoSPDY4)
+  if ((protocol_ >= kProtoSPDY4MinimumVersion) &&
+      (protocol_ <= kProtoSPDY4MaximumVersion))
     send_connection_header_prefix_ = true;
 
   if (protocol_ >= kProtoSPDY31) {
@@ -741,7 +746,7 @@
   buffered_spdy_framer_->set_debug_visitor(this);
   UMA_HISTOGRAM_ENUMERATION(
       "Net.SpdyVersion2",
-      protocol_ - kProtoSPDYMinimumVersion,
+      protocol_ - kProtoSPDYHistogramOffset,
       kProtoSPDYMaximumVersion - kProtoSPDYMinimumVersion + 1);
 
   net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_INITIALIZED,
@@ -2205,11 +2210,7 @@
                               const SpdyHeaderBlock& headers) {
   CHECK(in_io_loop_);
 
-  if (GetProtocolVersion() >= SPDY4) {
-    DCHECK_EQ(0u, associated_stream_id);
-    OnHeaders(stream_id, fin, headers);
-    return;
-  }
+  DCHECK_LE(GetProtocolVersion(), SPDY3);
 
   base::Time response_time = base::Time::Now();
   base::TimeTicks recv_first_byte_time = time_func_();
@@ -2332,6 +2333,8 @@
 }
 
 void SpdySession::OnHeaders(SpdyStreamId stream_id,
+                            bool has_priority,
+                            SpdyPriority priority,
                             bool fin,
                             const SpdyHeaderBlock& headers) {
   CHECK(in_io_loop_);
@@ -2459,8 +2462,8 @@
       base::Bind(&NetLogSpdyPingCallback, unique_id, is_ack, "received"));
 
   // Send response to a PING from server.
-  if ((protocol_ >= kProtoSPDY4 && !is_ack) ||
-      (protocol_ < kProtoSPDY4 && unique_id % 2 == 0)) {
+  if ((protocol_ >= kProtoSPDY4MinimumVersion && !is_ack) ||
+      (protocol_ < kProtoSPDY4MinimumVersion && unique_id % 2 == 0)) {
     WritePingFrame(unique_id, true);
     return;
   }
@@ -2746,7 +2749,8 @@
   DCHECK(enable_sending_initial_data_);
 
   if (send_connection_header_prefix_) {
-    DCHECK_EQ(protocol_, kProtoSPDY4);
+    DCHECK_GE(protocol_, kProtoSPDY4MinimumVersion);
+    DCHECK_LE(protocol_, kProtoSPDY4MaximumVersion);
     scoped_ptr<SpdyFrame> connection_header_prefix_frame(
         new SpdyFrame(const_cast<char*>(kHttp2ConnectionHeaderPrefix),
                       kHttp2ConnectionHeaderPrefixSize,
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index ef2d8fe..862918b 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -105,6 +105,8 @@
   STATUS_CODE_SETTINGS_TIMEOUT = 32,
   STATUS_CODE_CONNECT_ERROR = 33,
   STATUS_CODE_ENHANCE_YOUR_CALM = 34,
+  STATUS_CODE_INADEQUATE_SECURITY = 35,
+  STATUS_CODE_HTTP_1_1_REQUIRED = 36,
 
   // SpdySession errors
   PROTOCOL_ERROR_UNEXPECTED_PING = 22,
@@ -116,7 +118,7 @@
   PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION = 28,
 
   // Next free value.
-  NUM_SPDY_PROTOCOL_ERROR_DETAILS = 35,
+  NUM_SPDY_PROTOCOL_ERROR_DETAILS = 37,
 };
 SpdyProtocolErrorDetails NET_EXPORT_PRIVATE
     MapFramerErrorToProtocolError(SpdyFramer::SpdyError error);
@@ -129,7 +131,7 @@
 // to be updated with new values, as do the mapping functions above.
 COMPILE_ASSERT(12 == SpdyFramer::LAST_ERROR,
                SpdyProtocolErrorDetails_SpdyErrors_mismatch);
-COMPILE_ASSERT(15 == RST_STREAM_NUM_STATUS_CODES,
+COMPILE_ASSERT(17 == RST_STREAM_NUM_STATUS_CODES,
                SpdyProtocolErrorDetails_RstStreamStatus_mismatch);
 
 // Splits pushed |headers| into request and response parts. Request headers are
@@ -844,6 +846,8 @@
                   bool fin,
                   const SpdyHeaderBlock& headers) override;
   void OnHeaders(SpdyStreamId stream_id,
+                 bool has_priority,
+                 SpdyPriority priority,
                  bool fin,
                  const SpdyHeaderBlock& headers) override;
   bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override;
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc
index fef27bf..fc38cc2 100644
--- a/net/spdy/spdy_session_pool_unittest.cc
+++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -52,7 +52,7 @@
     NextProto,
     SpdySessionPoolTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 // A delegate that opens a new session when it is closed.
 class SessionOpeningDelegate : public SpdyStream::Delegate {
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index c6447bf..02e0c74 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -182,7 +182,7 @@
     NextProto,
     SpdySessionTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 // Try to create a SPDY session that will fail during
 // initialization. Nothing should blow up.
@@ -1556,7 +1556,8 @@
           kSessionFlowControlStreamId,
           kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
   std::vector<MockWrite> writes;
-  if (GetParam() == kProtoSPDY4) {
+  if ((GetParam() >= kProtoSPDY4MinimumVersion) &&
+     (GetParam() <= kProtoSPDY4MaximumVersion)) {
     writes.push_back(
         MockWrite(ASYNC,
                   kHttp2ConnectionHeaderPrefix,
@@ -5019,6 +5020,10 @@
            MapRstStreamStatusToProtocolError(RST_STREAM_FRAME_SIZE_ERROR));
   CHECK_EQ(STATUS_CODE_ENHANCE_YOUR_CALM,
            MapRstStreamStatusToProtocolError(RST_STREAM_ENHANCE_YOUR_CALM));
+  CHECK_EQ(STATUS_CODE_INADEQUATE_SECURITY,
+           MapRstStreamStatusToProtocolError(RST_STREAM_INADEQUATE_SECURITY));
+  CHECK_EQ(STATUS_CODE_HTTP_1_1_REQUIRED,
+           MapRstStreamStatusToProtocolError(RST_STREAM_HTTP_1_1_REQUIRED));
 }
 
 TEST(MapNetErrorToGoAwayStatus, MapsValue) {
diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc
index a6926ab..96153bf 100644
--- a/net/spdy/spdy_stream_unittest.cc
+++ b/net/spdy/spdy_stream_unittest.cc
@@ -111,7 +111,7 @@
     NextProto,
     SpdyStreamTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
   GURL url(kStreamUrl);
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index baa3548..801d67d 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -57,7 +57,8 @@
   next_protos.push_back(kProtoDeprecatedSPDY2);
   next_protos.push_back(kProtoSPDY3);
   next_protos.push_back(kProtoSPDY31);
-  next_protos.push_back(kProtoSPDY4);
+  next_protos.push_back(kProtoSPDY4_14);
+  next_protos.push_back(kProtoSPDY4_15);
   next_protos.push_back(kProtoQUIC1SPDY3);
   return next_protos;
 }
@@ -229,8 +230,14 @@
                   bool fin,
                   const SpdyHeaderBlock& headers) override {}
   void OnHeaders(SpdyStreamId stream_id,
+                 bool has_priority,
+                 SpdyPriority priority,
                  bool fin,
-                 const SpdyHeaderBlock& headers) override {}
+                 const SpdyHeaderBlock& headers) override {
+    if (has_priority) {
+      priority_ = priority;
+    }
+  }
   void OnDataFrameHeader(SpdyStreamId stream_id,
                          size_t length,
                          bool fin) override {}
@@ -367,7 +374,6 @@
       force_spdy_over_ssl(false),
       force_spdy_always(false),
       use_alternate_protocols(false),
-      enable_websocket_over_spdy(false),
       net_log(NULL) {
   DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
 
@@ -401,7 +407,6 @@
       force_spdy_over_ssl(false),
       force_spdy_always(false),
       use_alternate_protocols(false),
-      enable_websocket_over_spdy(false),
       net_log(NULL) {
   DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
 }
@@ -461,7 +466,6 @@
   params.force_spdy_over_ssl = session_deps->force_spdy_over_ssl;
   params.force_spdy_always = session_deps->force_spdy_always;
   params.use_alternate_protocols = session_deps->use_alternate_protocols;
-  params.enable_websocket_over_spdy = session_deps->enable_websocket_over_spdy;
   params.net_log = session_deps->net_log;
   return params;
 }
@@ -786,6 +790,7 @@
       break;
     case HEADERS:
       frame = framer.CreateHeaders(header_info.id, header_info.control_flags,
+                                   header_info.priority,
                                    headers.get());
       break;
     default:
@@ -1103,7 +1108,7 @@
                                           RequestPriority priority,
                                           bool compressed,
                                           bool fin) const {
-  if (protocol_ < kProtoSPDY4) {
+  if (protocol_ < kProtoSPDY4MinimumVersion) {
     SpdySynStreamIR syn_stream(stream_id);
     syn_stream.set_name_value_block(block);
     syn_stream.set_priority(
@@ -1123,7 +1128,7 @@
 
 SpdyFrame* SpdyTestUtil::ConstructSpdyReply(int stream_id,
                                             const SpdyHeaderBlock& headers) {
-  if (protocol_ < kProtoSPDY4) {
+  if (protocol_ < kProtoSPDY4MinimumVersion) {
     SpdySynReplyIR syn_reply(stream_id);
     syn_reply.set_name_value_block(headers);
     return CreateFramer(false)->SerializeFrame(syn_reply);
@@ -1264,7 +1269,7 @@
 const char* SpdyTestUtil::GetHostKey() const {
   if (protocol_ < kProtoSPDY3)
     return "host";
-  if (protocol_ < kProtoSPDY4)
+  if (protocol_ < kProtoSPDY4MinimumVersion)
     return ":host";
   else
     return ":authority";
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index e91800d..b08657c 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -222,7 +222,6 @@
   bool force_spdy_over_ssl;
   bool force_spdy_always;
   bool use_alternate_protocols;
-  bool enable_websocket_over_spdy;
   NetLog* net_log;
 };
 
@@ -553,7 +552,9 @@
   NextProto protocol() const { return protocol_; }
   SpdyMajorVersion spdy_version() const { return spdy_version_; }
   bool is_spdy2() const { return protocol_ < kProtoSPDY3; }
-  bool include_version_header() const { return protocol_ < kProtoSPDY4; }
+  bool include_version_header() const {
+    return protocol_ < kProtoSPDY4MinimumVersion;
+  }
   scoped_ptr<SpdyFramer> CreateFramer(bool compressed) const;
 
   const char* GetMethodKey() const;
diff --git a/net/spdy/spdy_websocket_stream.cc b/net/spdy/spdy_websocket_stream.cc
deleted file mode 100644
index 54e668c..0000000
--- a/net/spdy/spdy_websocket_stream.cc
+++ /dev/null
@@ -1,130 +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 "net/spdy/spdy_websocket_stream.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/compiler_specific.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/spdy/spdy_framer.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/spdy/spdy_session.h"
-#include "net/spdy/spdy_stream.h"
-#include "url/gurl.h"
-
-namespace net {
-
-SpdyWebSocketStream::SpdyWebSocketStream(
-    const base::WeakPtr<SpdySession>& spdy_session, Delegate* delegate)
-    : spdy_session_(spdy_session),
-      pending_send_data_length_(0),
-      delegate_(delegate),
-      weak_ptr_factory_(this) {
-  DCHECK(spdy_session_.get());
-  DCHECK(delegate_);
-}
-
-SpdyWebSocketStream::~SpdyWebSocketStream() {
-  delegate_ = NULL;
-  Close();
-}
-
-int SpdyWebSocketStream::InitializeStream(const GURL& url,
-                                          RequestPriority request_priority,
-                                          const BoundNetLog& net_log) {
-  if (!spdy_session_)
-    return ERR_SOCKET_NOT_CONNECTED;
-
-  int rv = stream_request_.StartRequest(
-      SPDY_BIDIRECTIONAL_STREAM, spdy_session_, url, request_priority, net_log,
-      base::Bind(&SpdyWebSocketStream::OnSpdyStreamCreated,
-                 weak_ptr_factory_.GetWeakPtr()));
-
-  if (rv == OK) {
-    stream_ = stream_request_.ReleaseStream();
-    DCHECK(stream_.get());
-    stream_->SetDelegate(this);
-  }
-  return rv;
-}
-
-int SpdyWebSocketStream::SendRequest(scoped_ptr<SpdyHeaderBlock> headers) {
-  if (!stream_.get()) {
-    NOTREACHED();
-    return ERR_UNEXPECTED;
-  }
-  int result = stream_->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND);
-  if (result < OK && result != ERR_IO_PENDING)
-    Close();
-  return result;
-}
-
-int SpdyWebSocketStream::SendData(const char* data, int length) {
-  if (!stream_.get()) {
-    NOTREACHED();
-    return ERR_UNEXPECTED;
-  }
-  DCHECK_GE(length, 0);
-  pending_send_data_length_ = static_cast<size_t>(length);
-  scoped_refptr<IOBuffer> buf(new IOBuffer(length));
-  memcpy(buf->data(), data, length);
-  stream_->SendData(buf.get(), length, MORE_DATA_TO_SEND);
-  return ERR_IO_PENDING;
-}
-
-void SpdyWebSocketStream::Close() {
-  if (stream_.get()) {
-    stream_->Close();
-    DCHECK(!stream_.get());
-  }
-}
-
-void SpdyWebSocketStream::OnRequestHeadersSent() {
-  DCHECK(delegate_);
-  delegate_->OnSentSpdyHeaders();
-}
-
-SpdyResponseHeadersStatus SpdyWebSocketStream::OnResponseHeadersUpdated(
-    const SpdyHeaderBlock& response_headers) {
-  DCHECK(delegate_);
-  delegate_->OnSpdyResponseHeadersUpdated(response_headers);
-  return RESPONSE_HEADERS_ARE_COMPLETE;
-}
-
-void SpdyWebSocketStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) {
-  DCHECK(delegate_);
-  delegate_->OnReceivedSpdyData(buffer.Pass());
-}
-
-void SpdyWebSocketStream::OnDataSent() {
-  DCHECK(delegate_);
-  delegate_->OnSentSpdyData(pending_send_data_length_);
-  pending_send_data_length_ = 0;
-}
-
-void SpdyWebSocketStream::OnClose(int status) {
-  stream_.reset();
-
-  // Destruction without Close() call OnClose() with delegate_ being NULL.
-  if (!delegate_)
-    return;
-  Delegate* delegate = delegate_;
-  delegate_ = NULL;
-  delegate->OnCloseSpdyStream();
-}
-
-void SpdyWebSocketStream::OnSpdyStreamCreated(int result) {
-  DCHECK_NE(ERR_IO_PENDING, result);
-  if (result == OK) {
-    stream_ = stream_request_.ReleaseStream();
-    DCHECK(stream_.get());
-    stream_->SetDelegate(this);
-  }
-  DCHECK(delegate_);
-  delegate_->OnCreatedSpdyStream(result);
-}
-
-}  // namespace net
diff --git a/net/spdy/spdy_websocket_stream.h b/net/spdy/spdy_websocket_stream.h
deleted file mode 100644
index 854afbf..0000000
--- a/net/spdy/spdy_websocket_stream.h
+++ /dev/null
@@ -1,104 +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 NET_SPDY_SPDY_WEBSOCKET_STREAM_H_
-#define NET_SPDY_SPDY_WEBSOCKET_STREAM_H_
-
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "net/base/completion_callback.h"
-#include "net/base/request_priority.h"
-#include "net/spdy/spdy_framer.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_session.h"
-#include "net/spdy/spdy_stream.h"
-
-namespace net {
-
-// The SpdyWebSocketStream is a WebSocket-specific type of stream known to a
-// SpdySession. WebSocket's opening handshake is converted to SPDY's
-// SYN_STREAM/SYN_REPLY. WebSocket frames are encapsulated as SPDY data frames.
-class NET_EXPORT_PRIVATE SpdyWebSocketStream
-    : public SpdyStream::Delegate {
- public:
-  // Delegate handles asynchronous events.
-  class NET_EXPORT_PRIVATE Delegate {
-   public:
-    // Called when InitializeStream() finishes asynchronously. This delegate is
-    // called if InitializeStream() returns ERR_IO_PENDING. |status| indicates
-    // network error.
-    virtual void OnCreatedSpdyStream(int status) = 0;
-
-    // Called on corresponding to OnSendHeadersComplete() or SPDY's SYN frame
-    // has been sent.
-    virtual void OnSentSpdyHeaders() = 0;
-
-    // Called on corresponding to OnResponseHeadersUpdated() or
-    // SPDY's SYN_STREAM, SYN_REPLY, or HEADERS frames are
-    // received. This callback may be called multiple times as SPDY's
-    // delegate does.
-    virtual void OnSpdyResponseHeadersUpdated(
-        const SpdyHeaderBlock& response_headers) = 0;
-
-    // Called when data is sent.
-    virtual void OnSentSpdyData(size_t bytes_sent) = 0;
-
-    // Called when data is received.
-    virtual void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) = 0;
-
-    // Called when SpdyStream is closed.
-    virtual void OnCloseSpdyStream() = 0;
-
-   protected:
-    virtual ~Delegate() {}
-  };
-
-  SpdyWebSocketStream(const base::WeakPtr<SpdySession>& spdy_session,
-                      Delegate* delegate);
-  ~SpdyWebSocketStream() override;
-
-  // Initializes SPDY stream for the WebSocket.
-  // It might create SPDY stream asynchronously.  In this case, this method
-  // returns ERR_IO_PENDING and call OnCreatedSpdyStream delegate with result
-  // after completion. In other cases, delegate does not be called.
-  int InitializeStream(const GURL& url,
-                       RequestPriority request_priority,
-                       const BoundNetLog& stream_net_log);
-
-  int SendRequest(scoped_ptr<SpdyHeaderBlock> headers);
-  int SendData(const char* data, int length);
-  void Close();
-
-  // SpdyStream::Delegate
-  void OnRequestHeadersSent() override;
-  SpdyResponseHeadersStatus OnResponseHeadersUpdated(
-      const SpdyHeaderBlock& response_headers) override;
-  void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) override;
-  void OnDataSent() override;
-  void OnClose(int status) override;
-
- private:
-  friend class SpdyWebSocketStreamTest;
-  FRIEND_TEST_ALL_PREFIXES(SpdyWebSocketStreamTest, Basic);
-
-  void OnSpdyStreamCreated(int status);
-
-  SpdyStreamRequest stream_request_;
-  base::WeakPtr<SpdyStream> stream_;
-  const base::WeakPtr<SpdySession> spdy_session_;
-  size_t pending_send_data_length_;
-  Delegate* delegate_;
-
-  base::WeakPtrFactory<SpdyWebSocketStream> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStream);
-};
-
-}  // namespace net
-
-#endif  // NET_SPDY_SPDY_WEBSOCKET_STREAM_H_
diff --git a/net/spdy/spdy_websocket_stream_unittest.cc b/net/spdy/spdy_websocket_stream_unittest.cc
deleted file mode 100644
index fc54884..0000000
--- a/net/spdy/spdy_websocket_stream_unittest.cc
+++ /dev/null
@@ -1,669 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/spdy/spdy_websocket_stream.h"
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "net/base/completion_callback.h"
-#include "net/proxy/proxy_server.h"
-#include "net/socket/next_proto.h"
-#include "net/socket/ssl_client_socket.h"
-#include "net/spdy/spdy_http_utils.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/spdy/spdy_session.h"
-#include "net/spdy/spdy_websocket_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-struct SpdyWebSocketStreamEvent {
-  enum EventType {
-    EVENT_CREATED,
-    EVENT_SENT_HEADERS,
-    EVENT_RECEIVED_HEADER,
-    EVENT_SENT_DATA,
-    EVENT_RECEIVED_DATA,
-    EVENT_CLOSE,
-  };
-  SpdyWebSocketStreamEvent(EventType type,
-                           const SpdyHeaderBlock& headers,
-                           int result,
-                           const std::string& data)
-      : event_type(type),
-        headers(headers),
-        result(result),
-        data(data) {}
-
-  EventType event_type;
-  SpdyHeaderBlock headers;
-  int result;
-  std::string data;
-};
-
-class SpdyWebSocketStreamEventRecorder : public SpdyWebSocketStream::Delegate {
- public:
-  explicit SpdyWebSocketStreamEventRecorder(const CompletionCallback& callback)
-      : callback_(callback) {}
-  ~SpdyWebSocketStreamEventRecorder() override {}
-
-  typedef base::Callback<void(SpdyWebSocketStreamEvent*)> StreamEventCallback;
-
-  void SetOnCreated(const StreamEventCallback& callback) {
-    on_created_ = callback;
-  }
-  void SetOnSentHeaders(const StreamEventCallback& callback) {
-    on_sent_headers_ = callback;
-  }
-  void SetOnReceivedHeader(const StreamEventCallback& callback) {
-    on_received_header_ = callback;
-  }
-  void SetOnSentData(const StreamEventCallback& callback) {
-    on_sent_data_ = callback;
-  }
-  void SetOnReceivedData(const StreamEventCallback& callback) {
-    on_received_data_ = callback;
-  }
-  void SetOnClose(const StreamEventCallback& callback) {
-    on_close_ = callback;
-  }
-
-  void OnCreatedSpdyStream(int result) override {
-    events_.push_back(
-        SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_CREATED,
-                                 SpdyHeaderBlock(),
-                                 result,
-                                 std::string()));
-    if (!on_created_.is_null())
-      on_created_.Run(&events_.back());
-  }
-  void OnSentSpdyHeaders() override {
-    events_.push_back(
-        SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
-                                 SpdyHeaderBlock(),
-                                 OK,
-                                 std::string()));
-    if (!on_sent_data_.is_null())
-      on_sent_data_.Run(&events_.back());
-  }
-  void OnSpdyResponseHeadersUpdated(
-      const SpdyHeaderBlock& response_headers) override {
-    events_.push_back(
-        SpdyWebSocketStreamEvent(
-            SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
-            response_headers,
-            OK,
-            std::string()));
-    if (!on_received_header_.is_null())
-      on_received_header_.Run(&events_.back());
-  }
-  void OnSentSpdyData(size_t bytes_sent) override {
-    events_.push_back(
-        SpdyWebSocketStreamEvent(
-            SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
-            SpdyHeaderBlock(),
-            static_cast<int>(bytes_sent),
-            std::string()));
-    if (!on_sent_data_.is_null())
-      on_sent_data_.Run(&events_.back());
-  }
-  void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) override {
-    std::string buffer_data;
-    size_t buffer_len = 0;
-    if (buffer) {
-      buffer_len = buffer->GetRemainingSize();
-      buffer_data.append(buffer->GetRemainingData(), buffer_len);
-    }
-    events_.push_back(
-        SpdyWebSocketStreamEvent(
-            SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
-            SpdyHeaderBlock(),
-            buffer_len,
-            buffer_data));
-    if (!on_received_data_.is_null())
-      on_received_data_.Run(&events_.back());
-  }
-  void OnCloseSpdyStream() override {
-    events_.push_back(
-        SpdyWebSocketStreamEvent(
-            SpdyWebSocketStreamEvent::EVENT_CLOSE,
-            SpdyHeaderBlock(),
-            OK,
-            std::string()));
-    if (!on_close_.is_null())
-      on_close_.Run(&events_.back());
-    if (!callback_.is_null())
-      callback_.Run(OK);
-  }
-
-  const std::vector<SpdyWebSocketStreamEvent>& GetSeenEvents() const {
-    return events_;
-  }
-
- private:
-  std::vector<SpdyWebSocketStreamEvent> events_;
-  StreamEventCallback on_created_;
-  StreamEventCallback on_sent_headers_;
-  StreamEventCallback on_received_header_;
-  StreamEventCallback on_sent_data_;
-  StreamEventCallback on_received_data_;
-  StreamEventCallback on_close_;
-  CompletionCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStreamEventRecorder);
-};
-
-}  // namespace
-
-class SpdyWebSocketStreamTest
-    : public ::testing::Test,
-      public ::testing::WithParamInterface<NextProto> {
- public:
-  OrderedSocketData* data() { return data_.get(); }
-
-  void DoSendHelloFrame(SpdyWebSocketStreamEvent* event) {
-    // Record the actual stream_id.
-    created_stream_id_ = websocket_stream_->stream_->stream_id();
-    websocket_stream_->SendData(kMessageFrame, kMessageFrameLength);
-  }
-
-  void DoSendClosingFrame(SpdyWebSocketStreamEvent* event) {
-    websocket_stream_->SendData(kClosingFrame, kClosingFrameLength);
-  }
-
-  void DoClose(SpdyWebSocketStreamEvent* event) {
-    websocket_stream_->Close();
-  }
-
-  void DoSync(SpdyWebSocketStreamEvent* event) {
-    sync_callback_.callback().Run(OK);
-  }
-
- protected:
-  SpdyWebSocketStreamTest()
-      : spdy_util_(GetParam()),
-        spdy_settings_id_to_set_(SETTINGS_MAX_CONCURRENT_STREAMS),
-        spdy_settings_flags_to_set_(SETTINGS_FLAG_PLEASE_PERSIST),
-        spdy_settings_value_to_set_(1),
-        session_deps_(GetParam()),
-        stream_id_(0),
-        created_stream_id_(0) {}
-  virtual ~SpdyWebSocketStreamTest() {}
-
-  void SetUp() override {
-    host_port_pair_.set_host("example.com");
-    host_port_pair_.set_port(80);
-    spdy_session_key_ = SpdySessionKey(host_port_pair_,
-                                       ProxyServer::Direct(),
-                                       PRIVACY_MODE_DISABLED);
-
-    spdy_settings_to_send_[spdy_settings_id_to_set_] =
-        SettingsFlagsAndValue(
-            SETTINGS_FLAG_PERSISTED, spdy_settings_value_to_set_);
-  }
-
-  void TearDown() override { base::MessageLoop::current()->RunUntilIdle(); }
-
-  void Prepare(SpdyStreamId stream_id) {
-    stream_id_ = stream_id;
-
-    request_frame_.reset(spdy_util_.ConstructSpdyWebSocketSynStream(
-        stream_id_,
-        "/echo",
-        "example.com",
-        "http://example.com/wsdemo"));
-
-    response_frame_.reset(
-        spdy_util_.ConstructSpdyWebSocketSynReply(stream_id_));
-
-    message_frame_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
-        kMessageFrame,
-        kMessageFrameLength,
-        stream_id_,
-        false));
-
-    closing_frame_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
-        kClosingFrame,
-        kClosingFrameLength,
-        stream_id_,
-        false));
-
-    closing_frame_fin_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
-        kClosingFrame,
-        kClosingFrameLength,
-        stream_id_,
-        true));
-  }
-
-  void InitSession(MockRead* reads, size_t reads_count,
-                   MockWrite* writes, size_t writes_count) {
-    data_.reset(new OrderedSocketData(reads, reads_count,
-                                      writes, writes_count));
-    session_deps_.socket_factory->AddSocketDataProvider(data_.get());
-    http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
-    session_ = CreateInsecureSpdySession(
-        http_session_, spdy_session_key_, BoundNetLog());
-  }
-
-  void SendRequest() {
-    scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
-    spdy_util_.SetHeader("path", "/echo", headers.get());
-    spdy_util_.SetHeader("host", "example.com", headers.get());
-    spdy_util_.SetHeader("version", "WebSocket/13", headers.get());
-    spdy_util_.SetHeader("scheme", "ws", headers.get());
-    spdy_util_.SetHeader("origin", "http://example.com/wsdemo", headers.get());
-    websocket_stream_->SendRequest(headers.Pass());
-  }
-
-  SpdyWebSocketTestUtil spdy_util_;
-  SpdySettingsIds spdy_settings_id_to_set_;
-  SpdySettingsFlags spdy_settings_flags_to_set_;
-  uint32 spdy_settings_value_to_set_;
-  SettingsMap spdy_settings_to_send_;
-  SpdySessionDependencies session_deps_;
-  scoped_ptr<OrderedSocketData> data_;
-  scoped_refptr<HttpNetworkSession> http_session_;
-  base::WeakPtr<SpdySession> session_;
-  scoped_ptr<SpdyWebSocketStream> websocket_stream_;
-  SpdyStreamId stream_id_;
-  SpdyStreamId created_stream_id_;
-  scoped_ptr<SpdyFrame> request_frame_;
-  scoped_ptr<SpdyFrame> response_frame_;
-  scoped_ptr<SpdyFrame> message_frame_;
-  scoped_ptr<SpdyFrame> closing_frame_;
-  scoped_ptr<SpdyFrame> closing_frame_fin_;
-  HostPortPair host_port_pair_;
-  SpdySessionKey spdy_session_key_;
-  TestCompletionCallback completion_callback_;
-  TestCompletionCallback sync_callback_;
-
-  static const char kMessageFrame[];
-  static const char kClosingFrame[];
-  static const size_t kMessageFrameLength;
-  static const size_t kClosingFrameLength;
-};
-
-INSTANTIATE_TEST_CASE_P(
-    NextProto,
-    SpdyWebSocketStreamTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
-
-// TODO(toyoshim): Replace old framing data to new one, then use HEADERS and
-// data frames.
-const char SpdyWebSocketStreamTest::kMessageFrame[] = "\x81\x05hello";
-const char SpdyWebSocketStreamTest::kClosingFrame[] = "\x88\0";
-const size_t SpdyWebSocketStreamTest::kMessageFrameLength =
-    arraysize(SpdyWebSocketStreamTest::kMessageFrame) - 1;
-const size_t SpdyWebSocketStreamTest::kClosingFrameLength =
-    arraysize(SpdyWebSocketStreamTest::kClosingFrame) - 1;
-
-TEST_P(SpdyWebSocketStreamTest, Basic) {
-  Prepare(1);
-  MockWrite writes[] = {
-    CreateMockWrite(*request_frame_.get(), 1),
-    CreateMockWrite(*message_frame_.get(), 3),
-    CreateMockWrite(*closing_frame_.get(), 5)
-  };
-
-  MockRead reads[] = {
-    CreateMockRead(*response_frame_.get(), 2),
-    CreateMockRead(*message_frame_.get(), 4),
-    // Skip sequence 6 to notify closing has been sent.
-    CreateMockRead(*closing_frame_.get(), 7),
-    MockRead(SYNCHRONOUS, 0, 8)  // EOF cause OnCloseSpdyStream event.
-  };
-
-  InitSession(reads, arraysize(reads), writes, arraysize(writes));
-
-  SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
-  delegate.SetOnReceivedHeader(
-      base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
-                 base::Unretained(this)));
-  delegate.SetOnReceivedData(
-      base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
-                 base::Unretained(this)));
-
-  websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
-
-  BoundNetLog net_log;
-  GURL url("ws://example.com/echo");
-  ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
-
-  ASSERT_TRUE(websocket_stream_->stream_.get());
-
-  SendRequest();
-
-  completion_callback_.WaitForResult();
-
-  EXPECT_EQ(stream_id_, created_stream_id_);
-
-  websocket_stream_.reset();
-
-  const std::vector<SpdyWebSocketStreamEvent>& events =
-      delegate.GetSeenEvents();
-  ASSERT_EQ(7U, events.size());
-
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
-            events[0].event_type);
-  EXPECT_EQ(OK, events[0].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
-            events[1].event_type);
-  EXPECT_EQ(OK, events[1].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
-            events[2].event_type);
-  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
-            events[3].event_type);
-  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
-            events[4].event_type);
-  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[4].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
-            events[5].event_type);
-  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
-            events[6].event_type);
-  EXPECT_EQ(OK, events[6].result);
-
-  // EOF close SPDY session.
-  EXPECT_FALSE(
-      HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
-  EXPECT_TRUE(data()->at_read_eof());
-  EXPECT_TRUE(data()->at_write_eof());
-}
-
-// A SPDY websocket may still send it's close frame after
-// recieving a close with SPDY stream FIN.
-TEST_P(SpdyWebSocketStreamTest, RemoteCloseWithFin) {
-  Prepare(1);
-  MockWrite writes[] = {
-    CreateMockWrite(*request_frame_.get(), 1),
-    CreateMockWrite(*closing_frame_.get(), 4),
-  };
-  MockRead reads[] = {
-    CreateMockRead(*response_frame_.get(), 2),
-    CreateMockRead(*closing_frame_fin_.get(), 3),
-    MockRead(SYNCHRONOUS, 0, 5)  // EOF cause OnCloseSpdyStream event.
-  };
-  InitSession(reads, arraysize(reads), writes, arraysize(writes));
-
-  SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
-  delegate.SetOnReceivedData(
-      base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
-                 base::Unretained(this)));
-
-  websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
-  BoundNetLog net_log;
-  GURL url("ws://example.com/echo");
-  ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
-
-  SendRequest();
-  completion_callback_.WaitForResult();
-  websocket_stream_.reset();
-
-  const std::vector<SpdyWebSocketStreamEvent>& events =
-      delegate.GetSeenEvents();
-  EXPECT_EQ(5U, events.size());
-
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
-            events[0].event_type);
-  EXPECT_EQ(OK, events[0].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
-            events[1].event_type);
-  EXPECT_EQ(OK, events[1].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
-            events[2].event_type);
-  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[2].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
-            events[3].event_type);
-  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[3].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
-            events[4].event_type);
-  EXPECT_EQ(OK, events[4].result);
-
-  // EOF closes SPDY session.
-  EXPECT_FALSE(
-      HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
-  EXPECT_TRUE(data()->at_read_eof());
-  EXPECT_TRUE(data()->at_write_eof());
-}
-
-TEST_P(SpdyWebSocketStreamTest, DestructionBeforeClose) {
-  Prepare(1);
-  MockWrite writes[] = {
-    CreateMockWrite(*request_frame_.get(), 1),
-    CreateMockWrite(*message_frame_.get(), 3)
-  };
-
-  MockRead reads[] = {
-    CreateMockRead(*response_frame_.get(), 2),
-    CreateMockRead(*message_frame_.get(), 4),
-    MockRead(ASYNC, ERR_IO_PENDING, 5)
-  };
-
-  InitSession(reads, arraysize(reads), writes, arraysize(writes));
-
-  SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
-  delegate.SetOnReceivedHeader(
-      base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
-                 base::Unretained(this)));
-  delegate.SetOnReceivedData(
-      base::Bind(&SpdyWebSocketStreamTest::DoSync,
-                 base::Unretained(this)));
-
-  websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
-
-  BoundNetLog net_log;
-  GURL url("ws://example.com/echo");
-  ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
-
-  SendRequest();
-
-  sync_callback_.WaitForResult();
-
-  // WebSocketStream destruction remove its SPDY stream from the session.
-  EXPECT_TRUE(session_->IsStreamActive(stream_id_));
-  websocket_stream_.reset();
-  EXPECT_FALSE(session_->IsStreamActive(stream_id_));
-
-  const std::vector<SpdyWebSocketStreamEvent>& events =
-      delegate.GetSeenEvents();
-  ASSERT_GE(4U, events.size());
-
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
-            events[0].event_type);
-  EXPECT_EQ(OK, events[0].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
-            events[1].event_type);
-  EXPECT_EQ(OK, events[1].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
-            events[2].event_type);
-  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
-            events[3].event_type);
-  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
-
-  EXPECT_TRUE(
-      HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
-  EXPECT_TRUE(data()->at_read_eof());
-  EXPECT_TRUE(data()->at_write_eof());
-}
-
-TEST_P(SpdyWebSocketStreamTest, DestructionAfterExplicitClose) {
-  Prepare(1);
-  MockWrite writes[] = {
-    CreateMockWrite(*request_frame_.get(), 1),
-    CreateMockWrite(*message_frame_.get(), 3),
-    CreateMockWrite(*closing_frame_.get(), 5)
-  };
-
-  MockRead reads[] = {
-    CreateMockRead(*response_frame_.get(), 2),
-    CreateMockRead(*message_frame_.get(), 4),
-    MockRead(ASYNC, ERR_IO_PENDING, 6)
-  };
-
-  InitSession(reads, arraysize(reads), writes, arraysize(writes));
-
-  SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
-  delegate.SetOnReceivedHeader(
-      base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
-                 base::Unretained(this)));
-  delegate.SetOnReceivedData(
-      base::Bind(&SpdyWebSocketStreamTest::DoClose,
-                 base::Unretained(this)));
-
-  websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
-
-  BoundNetLog net_log;
-  GURL url("ws://example.com/echo");
-  ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
-
-  SendRequest();
-
-  completion_callback_.WaitForResult();
-
-  // SPDY stream has already been removed from the session by Close().
-  EXPECT_FALSE(session_->IsStreamActive(stream_id_));
-  websocket_stream_.reset();
-
-  const std::vector<SpdyWebSocketStreamEvent>& events =
-      delegate.GetSeenEvents();
-  ASSERT_EQ(5U, events.size());
-
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
-            events[0].event_type);
-  EXPECT_EQ(OK, events[0].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
-            events[1].event_type);
-  EXPECT_EQ(OK, events[1].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
-            events[2].event_type);
-  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
-            events[3].event_type);
-  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE, events[4].event_type);
-
-  EXPECT_TRUE(
-      HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
-}
-
-TEST_P(SpdyWebSocketStreamTest, IOPending) {
-  Prepare(1);
-  scoped_ptr<SpdyFrame> settings_frame(
-      spdy_util_.ConstructSpdySettings(spdy_settings_to_send_));
-  scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
-  MockWrite writes[] = {
-    CreateMockWrite(*settings_ack, 1),
-    CreateMockWrite(*request_frame_.get(), 2),
-    CreateMockWrite(*message_frame_.get(), 4),
-    CreateMockWrite(*closing_frame_.get(), 6)
-  };
-
-  MockRead reads[] = {
-    CreateMockRead(*settings_frame.get(), 0),
-    CreateMockRead(*response_frame_.get(), 3),
-    CreateMockRead(*message_frame_.get(), 5),
-    CreateMockRead(*closing_frame_.get(), 7),
-    MockRead(SYNCHRONOUS, 0, 8)  // EOF cause OnCloseSpdyStream event.
-  };
-
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
-  http_session_ =
-      SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
-
-  session_ = CreateInsecureSpdySession(
-      http_session_, spdy_session_key_, BoundNetLog());
-
-  // Create a dummy WebSocketStream which cause ERR_IO_PENDING to another
-  // WebSocketStream under test.
-  SpdyWebSocketStreamEventRecorder block_delegate((CompletionCallback()));
-
-  scoped_ptr<SpdyWebSocketStream> block_stream(
-      new SpdyWebSocketStream(session_, &block_delegate));
-  BoundNetLog block_net_log;
-  GURL block_url("ws://example.com/block");
-  ASSERT_EQ(OK,
-            block_stream->InitializeStream(block_url, HIGHEST, block_net_log));
-
-  data.RunFor(1);
-
-  // Create a WebSocketStream under test.
-  SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
-  delegate.SetOnCreated(
-      base::Bind(&SpdyWebSocketStreamTest::DoSync,
-                 base::Unretained(this)));
-  delegate.SetOnReceivedHeader(
-      base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
-                 base::Unretained(this)));
-  delegate.SetOnReceivedData(
-      base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
-                 base::Unretained(this)));
-
-  websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
-  BoundNetLog net_log;
-  GURL url("ws://example.com/echo");
-  ASSERT_EQ(ERR_IO_PENDING, websocket_stream_->InitializeStream(
-      url, HIGHEST, net_log));
-
-  // Delete the fist stream to allow create the second stream.
-  block_stream.reset();
-  ASSERT_EQ(OK, sync_callback_.WaitForResult());
-
-  SendRequest();
-
-  data.RunFor(8);
-  completion_callback_.WaitForResult();
-
-  websocket_stream_.reset();
-
-  const std::vector<SpdyWebSocketStreamEvent>& block_events =
-      block_delegate.GetSeenEvents();
-  ASSERT_EQ(0U, block_events.size());
-
-  const std::vector<SpdyWebSocketStreamEvent>& events =
-      delegate.GetSeenEvents();
-  ASSERT_EQ(8U, events.size());
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CREATED,
-            events[0].event_type);
-  EXPECT_EQ(0, events[0].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
-            events[1].event_type);
-  EXPECT_EQ(OK, events[1].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
-            events[2].event_type);
-  EXPECT_EQ(OK, events[2].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
-            events[3].event_type);
-  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
-            events[4].event_type);
-  EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[4].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
-            events[5].event_type);
-  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
-            events[6].event_type);
-  EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[6].result);
-  EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
-            events[7].event_type);
-  EXPECT_EQ(OK, events[7].result);
-
-  // EOF close SPDY session.
-  EXPECT_FALSE(
-      HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
-  EXPECT_TRUE(data.at_read_eof());
-  EXPECT_TRUE(data.at_write_eof());
-}
-
-}  // namespace net
diff --git a/net/spdy/spdy_websocket_test_util.cc b/net/spdy/spdy_websocket_test_util.cc
deleted file mode 100644
index b1ef81b..0000000
--- a/net/spdy/spdy_websocket_test_util.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/spdy/spdy_websocket_test_util.h"
-
-#include "net/spdy/buffered_spdy_framer.h"
-#include "net/spdy/spdy_http_utils.h"
-
-namespace net {
-
-const bool kDefaultCompressed = false;
-
-SpdyWebSocketTestUtil::SpdyWebSocketTestUtil(
-    NextProto protocol) : spdy_util_(protocol) {}
-
-std::string SpdyWebSocketTestUtil::GetHeader(const SpdyHeaderBlock& headers,
-                                             const std::string& key) const {
-  SpdyHeaderBlock::const_iterator it = headers.find(GetHeaderKey(key));
-  return (it == headers.end()) ? "" : it->second;
-}
-
-void SpdyWebSocketTestUtil::SetHeader(
-    const std::string& key,
-    const std::string& value,
-    SpdyHeaderBlock* headers) const {
-  (*headers)[GetHeaderKey(key)] = value;
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketSynStream(
-    int stream_id,
-    const char* path,
-    const char* host,
-    const char* origin) {
-  scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
-  SetHeader("path", path, headers.get());
-  SetHeader("host", host, headers.get());
-  SetHeader("version", "WebSocket/13", headers.get());
-  SetHeader("scheme", "ws", headers.get());
-  SetHeader("origin", origin, headers.get());
-  return spdy_util_.ConstructSpdySyn(
-      stream_id, *headers, HIGHEST, false, false);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketSynReply(
-    int stream_id) {
-  SpdyHeaderBlock block;
-  SetHeader("status", "101", &block);
-  return spdy_util_.ConstructSpdyReply(stream_id, block);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketHandshakeRequestFrame(
-    scoped_ptr<SpdyHeaderBlock> headers,
-    SpdyStreamId stream_id,
-    RequestPriority request_priority) {
-  return spdy_util_.ConstructSpdySyn(
-      stream_id, *headers, request_priority, kDefaultCompressed, false);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketHandshakeResponseFrame(
-    scoped_ptr<SpdyHeaderBlock> headers,
-    SpdyStreamId stream_id,
-    RequestPriority request_priority) {
-  return spdy_util_.ConstructSpdyReply(stream_id, *headers);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketHeadersFrame(
-    int stream_id,
-    const char* length,
-    bool fin) {
-  scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
-  SetHeader("opcode", "1", headers.get());  // text frame
-  SetHeader("length", length, headers.get());
-  SetHeader("fin", fin ? "1" : "0", headers.get());
-  return spdy_util_.ConstructSpdySyn(stream_id, *headers, LOWEST, false, false);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketDataFrame(
-    const char* data,
-    int len,
-    SpdyStreamId stream_id,
-    bool fin) {
-
-  // Construct SPDY data frame.
-  BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
-  return framer.CreateDataFrame(
-      stream_id,
-      data,
-      len,
-      fin ? DATA_FLAG_FIN : DATA_FLAG_NONE);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdySettings(
-    const SettingsMap& settings) const {
-  return spdy_util_.ConstructSpdySettings(settings);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdySettingsAck() const {
-  return spdy_util_.ConstructSpdySettingsAck();
-}
-
-SpdyMajorVersion SpdyWebSocketTestUtil::spdy_version() const {
-  return spdy_util_.spdy_version();
-}
-
-std::string SpdyWebSocketTestUtil::GetHeaderKey(
-    const std::string& key) const {
-  return (spdy_util_.is_spdy2() ? "" : ":") + key;
-}
-
-}  // namespace net
diff --git a/net/spdy/spdy_websocket_test_util.h b/net/spdy/spdy_websocket_test_util.h
deleted file mode 100644
index 14c8c02..0000000
--- a/net/spdy/spdy_websocket_test_util.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_SPDY_SPDY_WEBSOCKET_TEST_UTIL_H_
-#define NET_SPDY_SPDY_WEBSOCKET_TEST_UTIL_H_
-
-#include "net/base/request_priority.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/spdy/spdy_test_util_common.h"
-
-namespace net {
-
-class SpdyWebSocketTestUtil {
- public:
-  explicit SpdyWebSocketTestUtil(NextProto protocol);
-
-  // Returns the value corresponding to the given key (passed through
-  // GetHeaderKey()), or the empty string if none exists.
-  std::string GetHeader(const SpdyHeaderBlock& headers,
-                        const std::string& key) const;
-
-  // Adds the given key/value pair to |headers|, passing the key
-  // through GetHeaderKey().
-  void SetHeader(const std::string& key,
-                 const std::string& value,
-                 SpdyHeaderBlock* headers) const;
-
-  // Constructs a standard SPDY SYN_STREAM frame for WebSocket over
-  // SPDY opening handshake.
-  SpdyFrame* ConstructSpdyWebSocketSynStream(int stream_id,
-                                             const char* path,
-                                             const char* host,
-                                             const char* origin);
-
-  // Constructs a standard SPDY SYN_REPLY packet to match the
-  // WebSocket over SPDY opening handshake.
-  SpdyFrame* ConstructSpdyWebSocketSynReply(int stream_id);
-
-  // Constructs a WebSocket over SPDY handshake request packet.
-  SpdyFrame* ConstructSpdyWebSocketHandshakeRequestFrame(
-      scoped_ptr<SpdyHeaderBlock> headers,
-      SpdyStreamId stream_id,
-      RequestPriority request_priority);
-
-  // Constructs a WebSocket over SPDY handshake response packet.
-  SpdyFrame* ConstructSpdyWebSocketHandshakeResponseFrame(
-      scoped_ptr<SpdyHeaderBlock> headers,
-      SpdyStreamId stream_id,
-      RequestPriority request_priority);
-
-  // Constructs a SPDY HEADERS frame for a WebSocket frame over SPDY.
-  SpdyFrame* ConstructSpdyWebSocketHeadersFrame(int stream_id,
-                                                const char* length,
-                                                bool fin);
-
-  // Constructs a WebSocket over SPDY data packet.
-  SpdyFrame* ConstructSpdyWebSocketDataFrame(const char* data,
-                                             int len,
-                                             SpdyStreamId stream_id,
-                                             bool fin);
-
-  // Forwards to |spdy_util_|.
-  SpdyFrame* ConstructSpdySettings(const SettingsMap& settings) const;
-  SpdyFrame* ConstructSpdySettingsAck() const;
-  SpdyMajorVersion spdy_version() const;
-
- private:
-  // Modify the header key based on the SPDY version and return it.
-  std::string GetHeaderKey(const std::string& key) const;
-
-  SpdyTestUtil spdy_util_;
-};
-
-}  // namespace net
-
-#endif  // NET_SPDY_SPDY_WEBSOCKET_TEST_UTIL_H_
diff --git a/net/ssl/ssl_cipher_suite_names.h b/net/ssl/ssl_cipher_suite_names.h
index 29c03a1..4e02fc6 100644
--- a/net/ssl/ssl_cipher_suite_names.h
+++ b/net/ssl/ssl_cipher_suite_names.h
@@ -55,7 +55,7 @@
 // Currently, this function follows these criteria:
 // 1) Only uses forward secure key exchanges
 // 2) Only uses AEADs
-NET_EXPORT_PRIVATE bool IsSecureTLSCipherSuite(uint16 cipher_suite);
+NET_EXPORT bool IsSecureTLSCipherSuite(uint16 cipher_suite);
 
 }  // namespace net
 
diff --git a/net/test/embedded_test_server/http_request.cc b/net/test/embedded_test_server/http_request.cc
index 3acb550..3156e51 100644
--- a/net/test/embedded_test_server/http_request.cc
+++ b/net/test/embedded_test_server/http_request.cc
@@ -83,8 +83,10 @@
 
   // Parse request's the first header line.
   // Request main main header, eg. GET /foobar.html HTTP/1.1
+  std::string request_headers;
   {
     const std::string header_line = ShiftLine();
+    http_request_->all_headers += header_line + "\r\n";
     std::vector<std::string> header_line_tokens;
     base::SplitString(header_line, ' ', &header_line_tokens);
     DCHECK_EQ(3u, header_line_tokens.size());
@@ -111,6 +113,7 @@
       if (header_line.empty())
         break;
 
+      http_request_->all_headers += header_line + "\r\n";
       if (header_line[0] == ' ' || header_line[0] == '\t') {
         // Continuation of the previous multi-line header.
         std::string header_value =
diff --git a/net/test/embedded_test_server/http_request.h b/net/test/embedded_test_server/http_request.h
index cb9144b..fcbf54c 100644
--- a/net/test/embedded_test_server/http_request.h
+++ b/net/test/embedded_test_server/http_request.h
@@ -36,6 +36,7 @@
   std::string relative_url;  // Starts with '/'. Example: "/test?query=foo"
   HttpMethod method;
   std::string method_string;
+  std::string all_headers;
   std::map<std::string, std::string> headers;
   std::string content;
   bool has_content;
diff --git a/net/test/embedded_test_server/http_request_unittest.cc b/net/test/embedded_test_server/http_request_unittest.cc
index 1006e4e..56121bb 100644
--- a/net/test/embedded_test_server/http_request_unittest.cc
+++ b/net/test/embedded_test_server/http_request_unittest.cc
@@ -44,6 +44,14 @@
     EXPECT_EQ(1u, request->headers.count("Multi-line-header"));
     EXPECT_EQ(1u, request->headers.count("Content-Length"));
 
+    const char kExpectedAllHeaders[] =
+        "POST /foobar.html HTTP/1.1\r\n"
+        "Host: localhost:1234\r\n"
+        "Multi-line-header: abcd\r\n"
+        " efgh\r\n"
+        " ijkl\r\n"
+        "Content-Length: 10\r\n";
+    EXPECT_EQ(kExpectedAllHeaders, request->all_headers);
     EXPECT_EQ("localhost:1234", request->headers["Host"]);
     EXPECT_EQ("abcd efgh ijkl", request->headers["Multi-line-header"]);
     EXPECT_EQ("10", request->headers["Content-Length"]);
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
index 0e23c7a..0c586f2 100644
--- a/net/test/spawned_test_server/base_test_server.cc
+++ b/net/test/spawned_test_server/base_test_server.cc
@@ -101,6 +101,7 @@
       tls_intolerance_type(TLS_INTOLERANCE_ALERT),
       fallback_scsv_enabled(false),
       staple_ocsp_response(false),
+      ocsp_server_unavailable(false),
       enable_npn(false),
       disable_session_cache(false) {
 }
@@ -118,6 +119,7 @@
       tls_intolerance_type(TLS_INTOLERANCE_ALERT),
       fallback_scsv_enabled(false),
       staple_ocsp_response(false),
+      ocsp_server_unavailable(false),
       enable_npn(false),
       disable_session_cache(false) {
 }
@@ -476,6 +478,10 @@
     }
     if (ssl_options_.staple_ocsp_response)
       arguments->Set("staple-ocsp-response", base::Value::CreateNullValue());
+    if (ssl_options_.ocsp_server_unavailable) {
+      arguments->Set("ocsp-server-unavailable",
+                     base::Value::CreateNullValue());
+    }
     if (ssl_options_.enable_npn)
       arguments->Set("enable-npn", base::Value::CreateNullValue());
     if (ssl_options_.disable_session_cache)
diff --git a/net/test/spawned_test_server/base_test_server.h b/net/test/spawned_test_server/base_test_server.h
index 45ea1ce..73ac855 100644
--- a/net/test/spawned_test_server/base_test_server.h
+++ b/net/test/spawned_test_server/base_test_server.h
@@ -201,6 +201,10 @@
     // Whether to staple the OCSP response.
     bool staple_ocsp_response;
 
+    // Whether to make the OCSP server unavailable. This does not affect the
+    // stapled OCSP response.
+    bool ocsp_server_unavailable;
+
     // Whether to enable NPN support.
     bool enable_npn;
 
diff --git a/net/test/url_request/url_request_mock_http_job.cc b/net/test/url_request/url_request_mock_http_job.cc
index 5542ac7..ede87cf 100644
--- a/net/test/url_request/url_request_mock_http_job.cc
+++ b/net/test/url_request/url_request_mock_http_job.cc
@@ -5,24 +5,35 @@
 #include "net/test/url_request/url_request_mock_http_job.h"
 
 #include "base/files/file_util.h"
+#include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner_util.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
 #include "net/base/filename_util.h"
+#include "net/base/net_errors.h"
+#include "net/base/url_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_request_filter.h"
 #include "net/url_request/url_request_interceptor.h"
 
+namespace net {
+
+namespace {
+
 const char kMockHostname[] = "mock.http";
 const base::FilePath::CharType kMockHeaderFileSuffix[] =
     FILE_PATH_LITERAL(".mock-http-headers");
 
-namespace net {
-
-namespace {
+// String names of failure phases matching FailurePhase enum.
+const char* kFailurePhase[] {
+  "start",      // START
+  "readasync",  // READ_ASYNC
+  "readsync",   // READ_SYNC
+};
 
 class MockJobInterceptor : public net::URLRequestInterceptor {
  public:
@@ -119,6 +130,22 @@
 }
 
 // static
+GURL URLRequestMockHTTPJob::GetMockUrlWithFailure(const base::FilePath& path,
+                                                  FailurePhase phase,
+                                                  int net_error) {
+  COMPILE_ASSERT(arraysize(kFailurePhase) == MAX_FAILURE_PHASE,
+                 kFailurePhase_must_match_FailurePhase_enum);
+  DCHECK_GE(phase, START);
+  DCHECK_LE(phase, READ_SYNC);
+  std::string url(GetMockUrl(path).spec());
+  url.append("?");
+  url.append(kFailurePhase[phase]);
+  url.append("=");
+  url.append(base::IntToString(net_error));
+  return GURL(url);
+}
+
+// static
 scoped_ptr<net::URLRequestInterceptor> URLRequestMockHTTPJob::CreateInterceptor(
     const base::FilePath& base_path,
     const scoped_refptr<base::SequencedWorkerPool>& worker_pool) {
@@ -163,23 +190,72 @@
 
 // Public virtual version.
 void URLRequestMockHTTPJob::Start() {
+  if (MaybeReportErrorOnPhase(START))
+    return;
   base::PostTaskAndReplyWithResult(
       task_runner_.get(),
       FROM_HERE,
       base::Bind(&DoFileIO, file_path_),
-      base::Bind(&URLRequestMockHTTPJob::GetRawHeaders,
+      base::Bind(&URLRequestMockHTTPJob::SetHeadersAndStart,
                  weak_ptr_factory_.GetWeakPtr()));
 }
 
-void URLRequestMockHTTPJob::GetRawHeaders(std::string raw_headers) {
-  // Handle CRLF line-endings.
-  ReplaceSubstringsAfterOffset(&raw_headers, 0, "\r\n", "\n");
-  // ParseRawHeaders expects \0 to end each header line.
-  ReplaceSubstringsAfterOffset(&raw_headers, 0, "\n", std::string("\0", 1));
+// Public virtual version.
+bool URLRequestMockHTTPJob::ReadRawData(IOBuffer* buf,
+                                        int buf_size,
+                                        int* bytes_read) {
+  if (MaybeReportErrorOnPhase(READ_SYNC))
+    return false;
+  if (MaybeReportErrorOnPhase(READ_ASYNC))
+    return false;
+  return URLRequestFileJob::ReadRawData(buf, buf_size, bytes_read);
+}
+
+void URLRequestMockHTTPJob::SetHeadersAndStart(const std::string& raw_headers) {
+  if (MaybeReportErrorOnPhase(START))
+    return;
   raw_headers_ = raw_headers;
+  // Handle CRLF line-endings.
+  ReplaceSubstringsAfterOffset(&raw_headers_, 0, "\r\n", "\n");
+  // ParseRawHeaders expects \0 to end each header line.
+  ReplaceSubstringsAfterOffset(&raw_headers_, 0, "\n", std::string("\0", 1));
   URLRequestFileJob::Start();
 }
 
+bool URLRequestMockHTTPJob::MaybeReportErrorOnPhase(
+    FailurePhase current_phase) {
+  DCHECK_GE(current_phase, START);
+  DCHECK_LE(current_phase, READ_SYNC);
+  std::string phase_key(kFailurePhase[current_phase]);
+  std::string phase_error_string;
+  if (!GetValueForKeyInQuery(request_->url(), phase_key, &phase_error_string))
+    return false;
+
+  int net_error;
+  if (!base::StringToInt(phase_error_string, &net_error))
+    return false;
+
+  if (net_error != net::ERR_IO_PENDING &&
+      (current_phase == START || current_phase == READ_SYNC)) {
+    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, net_error));
+    return true;
+  }
+
+  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
+
+  if (current_phase != READ_ASYNC)
+    return true;
+
+  base::MessageLoopProxy::current()->PostTask(
+      FROM_HERE,
+      base::Bind(
+          &URLRequestMockHTTPJob::NotifyDone,
+          weak_ptr_factory_.GetWeakPtr(),
+          net::URLRequestStatus(net::URLRequestStatus::FAILED, net_error)));
+
+  return true;
+}
+
 // Private const version.
 void URLRequestMockHTTPJob::GetResponseInfoConst(
     net::HttpResponseInfo* info) const {
diff --git a/net/test/url_request/url_request_mock_http_job.h b/net/test/url_request/url_request_mock_http_job.h
index 1a01a30..6eb3c72 100644
--- a/net/test/url_request/url_request_mock_http_job.h
+++ b/net/test/url_request/url_request_mock_http_job.h
@@ -28,6 +28,13 @@
 
 class URLRequestMockHTTPJob : public URLRequestFileJob {
  public:
+  enum FailurePhase {
+    START = 0,
+    READ_ASYNC = 1,
+    READ_SYNC = 2,
+    MAX_FAILURE_PHASE = 3,
+  };
+
   // Note that all file IO is done using |worker_pool|.
   URLRequestMockHTTPJob(URLRequest* request,
                         NetworkDelegate* network_delegate,
@@ -35,6 +42,7 @@
                         const scoped_refptr<base::TaskRunner>& task_runner);
 
   void Start() override;
+  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
   bool GetMimeType(std::string* mime_type) const override;
   int GetResponseCode() const override;
   bool GetCharset(std::string* charset) override;
@@ -57,6 +65,13 @@
   // construct a mock URL.
   static GURL GetMockUrl(const base::FilePath& path);
 
+  // Given the path to a file relative to the path passed to AddUrlHandler(),
+  // construct a mock URL that reports |net_error| at given |phase| of the
+  // request. Reporting |net_error| ERR_IO_PENDING results in a hung request.
+  static GURL GetMockUrlWithFailure(const base::FilePath& path,
+                                    FailurePhase phase,
+                                    int net_error);
+
   // Returns a URLRequestJobFactory::ProtocolHandler that serves
   // URLRequestMockHTTPJob's responding like an HTTP server. |base_path| is the
   // file path leading to the root of the directory to use as the root of the
@@ -77,7 +92,13 @@
 
  private:
   void GetResponseInfoConst(HttpResponseInfo* info) const;
-  void GetRawHeaders(std::string raw_headers);
+  void SetHeadersAndStart(const std::string& raw_headers);
+  // Checks query part of request url, and reports an error if it matches.
+  // Error is parsed out from the query and is reported synchronously.
+  // Reporting ERR_IO_PENDING results in a hung request.
+  // The "readasync" error is posted asynchronously.
+  bool MaybeReportErrorOnPhase(FailurePhase phase);
+
   std::string raw_headers_;
   const scoped_refptr<base::TaskRunner> task_runner_;
 
diff --git a/net/tools/flip_server/spdy_interface.cc b/net/tools/flip_server/spdy_interface.cc
index 297045d..22da7db 100644
--- a/net/tools/flip_server/spdy_interface.cc
+++ b/net/tools/flip_server/spdy_interface.cc
@@ -285,6 +285,8 @@
 }
 
 void SpdySM::OnHeaders(SpdyStreamId stream_id,
+                       bool has_priority,
+                       SpdyPriority priority,
                        bool fin,
                        const SpdyHeaderBlock& headers) {
   VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnHeaders(" << stream_id << ")";
diff --git a/net/tools/flip_server/spdy_interface.h b/net/tools/flip_server/spdy_interface.h
index de53e87..15cf0e9 100644
--- a/net/tools/flip_server/spdy_interface.h
+++ b/net/tools/flip_server/spdy_interface.h
@@ -81,6 +81,8 @@
 
   // Called after all the header data for HEADERS control frame is received.
   void OnHeaders(SpdyStreamId stream_id,
+                 bool has_priority,
+                 SpdyPriority priority,
                  bool fin,
                  const SpdyHeaderBlock& headers) override;
 
diff --git a/net/tools/flip_server/spdy_interface_test.cc b/net/tools/flip_server/spdy_interface_test.cc
index 9e66d0c..09909e2 100644
--- a/net/tools/flip_server/spdy_interface_test.cc
+++ b/net/tools/flip_server/spdy_interface_test.cc
@@ -52,7 +52,12 @@
                     bool,
                     const SpdyHeaderBlock&));
   MOCK_METHOD3(OnSynReply, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
-  MOCK_METHOD3(OnHeaders, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
+  MOCK_METHOD5(OnHeaders,
+               void(SpdyStreamId,
+                    bool,
+                    SpdyPriority,
+                    bool,
+                    const SpdyHeaderBlock&));
   MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId, size_t, bool));
   MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId,
                                        const char*,
@@ -471,8 +476,9 @@
       EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
           .WillOnce(SaveArg<2>(&actual_header_block));
     } else {
-      EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
-          .WillOnce(SaveArg<2>(&actual_header_block));
+      EXPECT_CALL(*spdy_framer_visitor_,
+                  OnHeaders(stream_id, false, 0, false, _))
+          .WillOnce(SaveArg<4>(&actual_header_block));
     }
     EXPECT_CALL(checkpoint, Call(0));
     EXPECT_CALL(*spdy_framer_visitor_,
@@ -522,8 +528,8 @@
           .WillOnce(SaveArg<2>(&actual_header_block));
     } else {
       EXPECT_CALL(*spdy_framer_visitor_,
-                  OnHeaders(stream_id, false, _))
-          .WillOnce(SaveArg<2>(&actual_header_block));
+                  OnHeaders(stream_id, false, 0, false, _))
+          .WillOnce(SaveArg<4>(&actual_header_block));
     }
     EXPECT_CALL(checkpoint, Call(0));
     EXPECT_CALL(*spdy_framer_visitor_,
@@ -641,8 +647,9 @@
       EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
           .WillOnce(SaveArg<2>(&actual_header_block));
     } else {
-      EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
-          .WillOnce(SaveArg<2>(&actual_header_block));
+      EXPECT_CALL(*spdy_framer_visitor_,
+                  OnHeaders(stream_id, false, 0, false, _))
+          .WillOnce(SaveArg<4>(&actual_header_block));
     }
   }
 
@@ -677,8 +684,9 @@
       EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
           .WillOnce(SaveArg<2>(&actual_header_block));
     } else {
-      EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
-          .WillOnce(SaveArg<2>(&actual_header_block));
+      EXPECT_CALL(*spdy_framer_visitor_,
+                  OnHeaders(stream_id, false, 0, false, _))
+          .WillOnce(SaveArg<4>(&actual_header_block));
     }
   }
 
@@ -854,8 +862,9 @@
       EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
           .WillOnce(SaveArg<2>(&actual_header_block));
     } else {
-      EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
-          .WillOnce(SaveArg<2>(&actual_header_block));
+      EXPECT_CALL(*spdy_framer_visitor_,
+                  OnHeaders(stream_id, false, 0, false, _))
+          .WillOnce(SaveArg<4>(&actual_header_block));
     }
     EXPECT_CALL(checkpoint, Call(0));
     EXPECT_CALL(*spdy_framer_visitor_,
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 55e2d88..1fb3e79 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -924,7 +924,7 @@
   // Client tries to request twice the server's max initial window, and the
   // server limits it to the max.
   client_config_.SetInitialCongestionWindowToSend(2 * kMaxInitialWindow);
-  client_config_.SetInitialRoundTripTimeUsToSend(1000);
+  client_config_.SetInitialRoundTripTimeUsToSend(20000);
 
   ASSERT_TRUE(Initialize());
   client_->client()->WaitForCryptoHandshakeConfirmed();
@@ -949,9 +949,9 @@
   EXPECT_EQ(GetParam().use_pacing, server_sent_packet_manager.using_pacing());
   EXPECT_EQ(GetParam().use_pacing, client_sent_packet_manager.using_pacing());
 
-  // The client *should* set the intitial RTT.
-  EXPECT_EQ(1000u, client_sent_packet_manager.GetRttStats()->initial_rtt_us());
-  EXPECT_EQ(1000u, server_sent_packet_manager.GetRttStats()->initial_rtt_us());
+  // The client *should* set the intitial RTT, but it's increased to 10ms.
+  EXPECT_EQ(20000u, client_sent_packet_manager.GetRttStats()->initial_rtt_us());
+  EXPECT_EQ(20000u, server_sent_packet_manager.GetRttStats()->initial_rtt_us());
 
   // Now use the negotiated limits with packet loss.
   SetPacketLossPercentage(30);
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index 0dcbd25..93de5ca 100755
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -1976,6 +1976,7 @@
     if self.options.server_type == SERVER_HTTP:
       if self.options.https:
         pem_cert_and_key = None
+        ocsp_der = None
         if self.options.cert_and_key_file:
           if not os.path.isfile(self.options.cert_and_key_file):
             raise testserver_base.OptionError(
@@ -1988,7 +1989,6 @@
           print ('OCSP server started on %s:%d...' %
               (host, self.__ocsp_server.server_port))
 
-          ocsp_der = None
           ocsp_state = None
 
           if self.options.ocsp == 'ok':
@@ -2012,7 +2012,11 @@
               ocsp_state = ocsp_state,
               serial = self.options.cert_serial)
 
-          self.__ocsp_server.ocsp_response = ocsp_der
+          if self.options.ocsp_server_unavailable:
+            # SEQUENCE containing ENUMERATED with value 3 (tryLater).
+            self.__ocsp_server.ocsp_response = '30030a0103'.decode('hex')
+          else:
+            self.__ocsp_server.ocsp_response = ocsp_der
 
         for ca_cert in self.options.ssl_client_ca:
           if not os.path.isfile(ca_cert):
@@ -2021,8 +2025,8 @@
                 ' exiting...')
 
         stapled_ocsp_response = None
-        if self.__ocsp_server and self.options.staple_ocsp_response:
-          stapled_ocsp_response = self.__ocsp_server.ocsp_response
+        if self.options.staple_ocsp_response:
+          stapled_ocsp_response = ocsp_der
 
         server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key,
                              self.options.ssl_client_auth,
@@ -2269,6 +2273,12 @@
     self.option_parser.add_option('--ws-basic-auth', action='store_true',
                                   dest='ws_basic_auth',
                                   help='Enable basic-auth for WebSocket')
+    self.option_parser.add_option('--ocsp-server-unavailable',
+                                  dest='ocsp_server_unavailable',
+                                  default=False, action='store_true',
+                                  help='If set, the OCSP server will return '
+                                  'a tryLater status rather than the actual '
+                                  'OCSP response.')
 
 
 if __name__ == '__main__':
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index b18aa0a..4c307fd 100644
--- a/net/udp/udp_socket_win.cc
+++ b/net/udp/udp_socket_win.cc
@@ -630,7 +630,7 @@
 
 int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
                                    IPEndPoint* address) {
-  DCHECK(!core_->read_iobuffer_);
+  DCHECK(!core_->read_iobuffer_.get());
   SockaddrStorage& storage = core_->recv_addr_storage_;
   storage.addr_len = sizeof(storage.addr_storage);
 
@@ -670,7 +670,7 @@
 
 int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len,
                                  const IPEndPoint* address) {
-  DCHECK(!core_->write_iobuffer_);
+  DCHECK(!core_->write_iobuffer_.get());
   SockaddrStorage storage;
   struct sockaddr* addr = storage.addr;
   // Convert address.
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 666bd03..04c190c 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -351,6 +351,8 @@
       http_network_session_params_.trusted_spdy_proxy;
   network_session_params.next_protos = http_network_session_params_.next_protos;
   network_session_params.enable_quic = http_network_session_params_.enable_quic;
+  network_session_params.quic_connection_options =
+      http_network_session_params_.quic_connection_options;
 
   HttpTransactionFactory* http_transaction_factory = NULL;
   if (http_cache_enabled_) {
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index 9053372..a7d9d7b 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -27,6 +27,7 @@
 #include "net/dns/host_resolver.h"
 #include "net/proxy/proxy_config_service.h"
 #include "net/proxy/proxy_service.h"
+#include "net/quic/quic_protocol.h"
 #include "net/socket/next_proto.h"
 
 namespace net {
@@ -72,6 +73,7 @@
     std::string trusted_spdy_proxy;
     bool use_alternate_protocols;
     bool enable_quic;
+    QuicTagVector quic_connection_options;
   };
 
   URLRequestContextBuilder();
@@ -162,6 +164,12 @@
   void SetSpdyAndQuicEnabled(bool spdy_enabled,
                              bool quic_enabled);
 
+  void set_quic_connection_options(
+      const QuicTagVector& quic_connection_options) {
+    http_network_session_params_.quic_connection_options =
+        quic_connection_options;
+  }
+
   void set_throttling_enabled(bool throttling_enabled) {
     throttling_enabled_ = throttling_enabled;
   }
diff --git a/net/url_request/url_request_file_job_unittest.cc b/net/url_request/url_request_file_job_unittest.cc
index f4d7f7a..23ded74 100644
--- a/net/url_request/url_request_file_job_unittest.cc
+++ b/net/url_request/url_request_file_job_unittest.cc
@@ -82,6 +82,19 @@
     return job;
   }
 
+  net::URLRequestJob* MaybeInterceptRedirect(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate,
+      const GURL& location) const override {
+    return nullptr;
+  }
+
+  net::URLRequestJob* MaybeInterceptResponse(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const override {
+    return nullptr;
+  }
+
   bool IsHandledProtocol(const std::string& scheme) const override {
     return scheme == "file";
   }
diff --git a/net/url_request/url_request_intercepting_job_factory.cc b/net/url_request/url_request_intercepting_job_factory.cc
index 43789e1..ea2d1f2 100644
--- a/net/url_request/url_request_intercepting_job_factory.cc
+++ b/net/url_request/url_request_intercepting_job_factory.cc
@@ -32,6 +32,33 @@
       scheme, request, network_delegate);
 }
 
+URLRequestJob* URLRequestInterceptingJobFactory::MaybeInterceptRedirect(
+    URLRequest* request,
+    NetworkDelegate* network_delegate,
+    const GURL& location) const {
+  DCHECK(CalledOnValidThread());
+  URLRequestJob* job = interceptor_->MaybeInterceptRedirect(request,
+                                                            network_delegate,
+                                                            location);
+  if (job)
+    return job;
+  return job_factory_->MaybeInterceptRedirect(request,
+                                              network_delegate,
+                                              location);
+}
+
+URLRequestJob* URLRequestInterceptingJobFactory::MaybeInterceptResponse(
+    URLRequest* request,
+    NetworkDelegate* network_delegate) const {
+  DCHECK(CalledOnValidThread());
+  URLRequestJob* job = interceptor_->MaybeInterceptResponse(request,
+                                                            network_delegate);
+  if (job)
+    return job;
+  return job_factory_->MaybeInterceptResponse(request,
+                                              network_delegate);
+}
+
 bool URLRequestInterceptingJobFactory::IsHandledProtocol(
     const std::string& scheme) const {
   return job_factory_->IsHandledProtocol(scheme);
diff --git a/net/url_request/url_request_intercepting_job_factory.h b/net/url_request/url_request_intercepting_job_factory.h
index 857dbf4..056b385 100644
--- a/net/url_request/url_request_intercepting_job_factory.h
+++ b/net/url_request/url_request_intercepting_job_factory.h
@@ -42,6 +42,16 @@
       const std::string& scheme,
       URLRequest* request,
       NetworkDelegate* network_delegate) const override;
+
+  URLRequestJob* MaybeInterceptRedirect(
+      URLRequest* request,
+      NetworkDelegate* network_delegate,
+      const GURL& location) const override;
+
+  URLRequestJob* MaybeInterceptResponse(
+      URLRequest* request,
+      NetworkDelegate* network_delegate) const override;
+
   bool IsHandledProtocol(const std::string& scheme) const override;
   bool IsHandledURL(const GURL& url) const override;
   bool IsSafeRedirectTarget(const GURL& location) const override;
diff --git a/net/url_request/url_request_interceptor.cc b/net/url_request/url_request_interceptor.cc
index bcd0fd5..b93611b 100644
--- a/net/url_request/url_request_interceptor.cc
+++ b/net/url_request/url_request_interceptor.cc
@@ -12,4 +12,16 @@
 URLRequestInterceptor::~URLRequestInterceptor() {
 }
 
+URLRequestJob* URLRequestInterceptor::MaybeInterceptRedirect(
+    URLRequest* request,
+    NetworkDelegate* network_delegate,
+    const GURL& location) const {
+  return nullptr;
+}
+
+URLRequestJob* URLRequestInterceptor::MaybeInterceptResponse(
+    URLRequest* request, NetworkDelegate* network_delegate) const {
+  return nullptr;
+}
+
 }  // namespace net
diff --git a/net/url_request/url_request_interceptor.h b/net/url_request/url_request_interceptor.h
index 682368d..f7d5275 100644
--- a/net/url_request/url_request_interceptor.h
+++ b/net/url_request/url_request_interceptor.h
@@ -8,6 +8,8 @@
 #include "base/macros.h"
 #include "net/base/net_export.h"
 
+class GURL;
+
 namespace net {
 
 class URLRequest;
@@ -28,6 +30,20 @@
   virtual URLRequestJob* MaybeInterceptRequest(
       URLRequest* request, NetworkDelegate* network_delegate) const = 0;
 
+  // Returns a URLRequestJob to handle |request|, if the interceptor wants to
+  // take over the handling of the request after a redirect is received,
+  // instead of using the default ProtocolHandler. Otherwise, returns NULL.
+  virtual URLRequestJob* MaybeInterceptRedirect(
+      URLRequest* request,
+      NetworkDelegate* network_delegate,
+      const GURL& location) const;
+
+  // Returns a URLRequestJob to handle |request, if the interceptor wants to
+  // take over the handling of the request after a response has started,
+  // instead of using the default ProtocolHandler. Otherwise, returns NULL.
+  virtual URLRequestJob* MaybeInterceptResponse(
+      URLRequest* request, NetworkDelegate* network_delegate) const;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(URLRequestInterceptor);
 };
diff --git a/net/url_request/url_request_job_factory.h b/net/url_request/url_request_job_factory.h
index d4cc49e..96f218a 100644
--- a/net/url_request/url_request_job_factory.h
+++ b/net/url_request/url_request_job_factory.h
@@ -47,6 +47,15 @@
       URLRequest* request,
       NetworkDelegate* network_delegate) const = 0;
 
+  virtual URLRequestJob* MaybeInterceptRedirect(
+      URLRequest* request,
+      NetworkDelegate* network_delegate,
+      const GURL& location) const = 0;
+
+  virtual URLRequestJob* MaybeInterceptResponse(
+      URLRequest* request,
+      NetworkDelegate* network_delegate) const = 0;
+
   virtual bool IsHandledProtocol(const std::string& scheme) const = 0;
 
   virtual bool IsHandledURL(const GURL& url) const = 0;
diff --git a/net/url_request/url_request_job_factory_impl.cc b/net/url_request/url_request_job_factory_impl.cc
index 57e775b..264a7a1 100644
--- a/net/url_request/url_request_job_factory_impl.cc
+++ b/net/url_request/url_request_job_factory_impl.cc
@@ -63,6 +63,19 @@
   return it->second->MaybeCreateJob(request, network_delegate);
 }
 
+URLRequestJob* URLRequestJobFactoryImpl::MaybeInterceptRedirect(
+    URLRequest* request,
+    NetworkDelegate* network_delegate,
+    const GURL& location) const {
+  return nullptr;
+}
+
+URLRequestJob* URLRequestJobFactoryImpl::MaybeInterceptResponse(
+    URLRequest* request,
+    NetworkDelegate* network_delegate) const {
+  return nullptr;
+}
+
 bool URLRequestJobFactoryImpl::IsHandledProtocol(
     const std::string& scheme) const {
   DCHECK(CalledOnValidThread());
diff --git a/net/url_request/url_request_job_factory_impl.h b/net/url_request/url_request_job_factory_impl.h
index 695661e..8d1d8d9 100644
--- a/net/url_request/url_request_job_factory_impl.h
+++ b/net/url_request/url_request_job_factory_impl.h
@@ -33,6 +33,16 @@
       const std::string& scheme,
       URLRequest* request,
       NetworkDelegate* network_delegate) const override;
+
+  URLRequestJob* MaybeInterceptRedirect(
+      URLRequest* request,
+      NetworkDelegate* network_delegate,
+      const GURL& location) const override;
+
+  URLRequestJob* MaybeInterceptResponse(
+      URLRequest* request,
+      NetworkDelegate* network_delegate) const override;
+
   bool IsHandledProtocol(const std::string& scheme) const override;
   bool IsHandledURL(const GURL& url) const override;
   bool IsSafeRedirectTarget(const GURL& location) const override;
diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc
index 0fe557b..6fcff22 100644
--- a/net/url_request/url_request_job_manager.cc
+++ b/net/url_request/url_request_job_manager.cc
@@ -128,6 +128,13 @@
     if (job)
       return job;
   }
+
+  URLRequestJob* job =
+      request->context()->job_factory()->MaybeInterceptRedirect(
+          request, network_delegate, location);
+  if (job)
+    return job;
+
   return NULL;
 }
 
@@ -154,6 +161,13 @@
     if (job)
       return job;
   }
+
+  URLRequestJob* job =
+      request->context()->job_factory()->MaybeInterceptResponse(
+          request, network_delegate);
+  if (job)
+    return job;
+
   return NULL;
 }
 
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index 82d8579..8f70ee7 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -317,11 +317,14 @@
       blocked_set_cookie_count_(0),
       set_cookie_count_(0),
       observed_before_proxy_headers_sent_callbacks_(0),
+      before_send_headers_count_(0),
+      headers_received_count_(0),
       has_load_timing_info_before_redirect_(false),
       has_load_timing_info_before_auth_(false),
       can_access_files_(true),
       can_throttle_requests_(true),
-      cancel_request_with_policy_violating_referrer_(false) {
+      cancel_request_with_policy_violating_referrer_(false),
+      will_be_intercepted_on_next_error_(false) {
 }
 
 TestNetworkDelegate::~TestNetworkDelegate() {
@@ -386,7 +389,7 @@
   next_states_[req_id] =
       kStageSendHeaders |
       kStageCompletedError;  // request canceled by delegate
-
+  before_send_headers_count_++;
   return OK;
 }
 
@@ -406,9 +409,11 @@
   event_order_[req_id] += "OnSendHeaders\n";
   EXPECT_TRUE(next_states_[req_id] & kStageSendHeaders) <<
       event_order_[req_id];
-  next_states_[req_id] =
-      kStageHeadersReceived |
-      kStageCompletedError;
+  if (!will_be_intercepted_on_next_error_)
+    next_states_[req_id] = kStageHeadersReceived | kStageCompletedError;
+  else
+    next_states_[req_id] = kStageResponseStarted;
+  will_be_intercepted_on_next_error_ = false;
 }
 
 int TestNetworkDelegate::OnHeadersReceived(
@@ -445,7 +450,7 @@
     if (!allowed_unsafe_redirect_url_.is_empty())
       *allowed_unsafe_redirect_url = allowed_unsafe_redirect_url_;
   }
-
+  headers_received_count_++;
   return OK;
 }
 
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h
index 5784931..1289db7 100644
--- a/net/url_request/url_request_test_util.h
+++ b/net/url_request/url_request_test_util.h
@@ -275,12 +275,18 @@
   int observed_before_proxy_headers_sent_callbacks() const {
     return observed_before_proxy_headers_sent_callbacks_;
   }
+  int before_send_headers_count() const { return before_send_headers_count_; }
+  int headers_received_count() const { return headers_received_count_; }
 
   // Last observed proxy in proxy header sent callback.
   HostPortPair last_observed_proxy() {
     return last_observed_proxy_;
   }
 
+  void set_can_be_intercepted_on_error(bool can_be_intercepted_on_error) {
+    will_be_intercepted_on_next_error_ = can_be_intercepted_on_error;
+  }
+
  protected:
   // NetworkDelegate:
   int OnBeforeURLRequest(URLRequest* request,
@@ -343,6 +349,8 @@
   int blocked_set_cookie_count_;
   int set_cookie_count_;
   int observed_before_proxy_headers_sent_callbacks_;
+  int before_send_headers_count_;
+  int headers_received_count_;
   // Last observed proxy in before proxy header sent callback.
   HostPortPair last_observed_proxy_;
 
@@ -365,6 +373,7 @@
   bool can_access_files_;  // true by default
   bool can_throttle_requests_;  // true by default
   bool cancel_request_with_policy_violating_referrer_;  // false by default
+  bool will_be_intercepted_on_next_error_;
 };
 
 // Overrides the host used by the LocalHttpTestServer in
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 139b6f3..2aeecc6 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -72,6 +72,8 @@
 #include "net/url_request/static_http_user_agent_settings.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_http_job.h"
+#include "net/url_request/url_request_intercepting_job_factory.h"
+#include "net/url_request/url_request_interceptor.h"
 #include "net/url_request/url_request_job_factory_impl.h"
 #include "net/url_request/url_request_redirect_job.h"
 #include "net/url_request/url_request_test_job.h"
@@ -607,31 +609,52 @@
   URLRequestTest() : default_context_(true) {
     default_context_.set_network_delegate(&default_network_delegate_);
     default_context_.set_net_log(&net_log_);
-    job_factory_.SetProtocolHandler("data", new DataProtocolHandler);
-#if !defined(DISABLE_FILE_SUPPORT)
-    job_factory_.SetProtocolHandler(
-        "file", new FileProtocolHandler(base::MessageLoopProxy::current()));
-#endif
-    default_context_.set_job_factory(&job_factory_);
-    default_context_.Init();
+    job_factory_impl_ = new URLRequestJobFactoryImpl();
+    job_factory_.reset(job_factory_impl_);
   }
+
   ~URLRequestTest() override {
     // URLRequestJobs may post clean-up tasks on destruction.
     base::RunLoop().RunUntilIdle();
   }
 
+  virtual void SetUp() {
+    SetUpFactory();
+    default_context_.set_job_factory(job_factory_.get());
+    default_context_.Init();
+    PlatformTest::SetUp();
+  }
+
+  virtual void SetUpFactory() {
+    job_factory_impl_->SetProtocolHandler("data", new DataProtocolHandler);
+#if !defined(DISABLE_FILE_SUPPORT)
+    job_factory_impl_->SetProtocolHandler(
+        "file", new FileProtocolHandler(base::MessageLoopProxy::current()));
+#endif
+  }
+
+  TestNetworkDelegate* default_network_delegate() {
+    return &default_network_delegate_;
+  }
+
+  const TestURLRequestContext& default_context() const {
+    return default_context_;
+  }
+
+
   // Adds the TestJobInterceptor to the default context.
   TestJobInterceptor* AddTestInterceptor() {
     TestJobInterceptor* protocol_handler_ = new TestJobInterceptor();
-    job_factory_.SetProtocolHandler("http", NULL);
-    job_factory_.SetProtocolHandler("http", protocol_handler_);
+    job_factory_impl_->SetProtocolHandler("http", NULL);
+    job_factory_impl_->SetProtocolHandler("http", protocol_handler_);
     return protocol_handler_;
   }
 
  protected:
   CapturingNetLog net_log_;
   TestNetworkDelegate default_network_delegate_;  // Must outlive URLRequest.
-  URLRequestJobFactoryImpl job_factory_;
+  URLRequestJobFactoryImpl* job_factory_impl_;
+  scoped_ptr<URLRequestJobFactory> job_factory_;
   TestURLRequestContext default_context_;
 };
 
@@ -1574,29 +1597,570 @@
   EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
 }
 
-LoadTimingInfo RunLoadTimingTest(const LoadTimingInfo& job_load_timing,
-                                 URLRequestContext* context) {
-  TestInterceptor interceptor;
-  interceptor.intercept_main_request_ = true;
-  interceptor.main_request_load_timing_info_ = job_load_timing;
+// An Interceptor for use with interceptor tests.
+class MockURLRequestInterceptor : public URLRequestInterceptor {
+ public:
+  // Static getters for canned response header and data strings.
+  static std::string ok_data() {
+    return URLRequestTestJob::test_data_1();
+  }
+
+  static std::string ok_headers() {
+    return URLRequestTestJob::test_headers();
+  }
+
+  static std::string redirect_data() {
+    return std::string();
+  }
+
+  static std::string redirect_headers() {
+    return URLRequestTestJob::test_redirect_headers();
+  }
+
+  static std::string error_data() {
+    return std::string("ohhh nooooo mr. bill!");
+  }
+
+  static std::string error_headers() {
+    return URLRequestTestJob::test_error_headers();
+  }
+
+  MockURLRequestInterceptor()
+      : intercept_main_request_(false), restart_main_request_(false),
+        cancel_main_request_(false), cancel_then_restart_main_request_(false),
+        simulate_main_network_error_(false),
+        intercept_redirect_(false), cancel_redirect_request_(false),
+        intercept_final_response_(false), cancel_final_request_(false),
+        use_url_request_http_job_(false),
+        did_intercept_main_(false), did_restart_main_(false),
+        did_cancel_main_(false), did_cancel_then_restart_main_(false),
+        did_simulate_error_main_(false),
+        did_intercept_redirect_(false), did_cancel_redirect_(false),
+        did_intercept_final_(false), did_cancel_final_(false) {
+  }
+
+  ~MockURLRequestInterceptor() override {
+  }
+
+  // URLRequestInterceptor implementation:
+  URLRequestJob* MaybeInterceptRequest(
+      URLRequest* request,
+      NetworkDelegate* network_delegate) const override {
+    if (restart_main_request_) {
+      restart_main_request_ = false;
+      did_restart_main_ = true;
+      return new RestartTestJob(request, network_delegate);
+    }
+    if (cancel_main_request_) {
+      cancel_main_request_ = false;
+      did_cancel_main_ = true;
+      return new CancelTestJob(request, network_delegate);
+    }
+    if (cancel_then_restart_main_request_) {
+      cancel_then_restart_main_request_ = false;
+      did_cancel_then_restart_main_ = true;
+      return new CancelThenRestartTestJob(request, network_delegate);
+    }
+    if (simulate_main_network_error_) {
+      simulate_main_network_error_ = false;
+      did_simulate_error_main_ = true;
+      if (use_url_request_http_job_) {
+        return URLRequestHttpJob::Factory(request, network_delegate, "http");
+      }
+      // This job will result in error since the requested URL is not one of the
+      // URLs supported by these tests.
+      return new URLRequestTestJob(request, network_delegate, true);
+    }
+    if (!intercept_main_request_)
+      return nullptr;
+    intercept_main_request_ = false;
+    did_intercept_main_ = true;
+    URLRequestTestJob* job =  new URLRequestTestJob(request,
+                                                    network_delegate,
+                                                    main_headers_,
+                                                    main_data_,
+                                                    true);
+    job->set_load_timing_info(main_request_load_timing_info_);
+    return job;
+  }
+
+  URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
+                                        NetworkDelegate* network_delegate,
+                                        const GURL& location) const override {
+    if (cancel_redirect_request_) {
+      cancel_redirect_request_ = false;
+      did_cancel_redirect_ = true;
+      return new CancelTestJob(request, network_delegate);
+    }
+    if (!intercept_redirect_)
+      return nullptr;
+    intercept_redirect_ = false;
+    did_intercept_redirect_ = true;
+    if (use_url_request_http_job_) {
+      return URLRequestHttpJob::Factory(request, network_delegate, "http");
+    }
+    return new URLRequestTestJob(request,
+                                 network_delegate,
+                                 redirect_headers_,
+                                 redirect_data_,
+                                 true);
+  }
+
+  URLRequestJob* MaybeInterceptResponse(
+      URLRequest* request,
+      NetworkDelegate* network_delegate) const override {
+    if (cancel_final_request_) {
+      cancel_final_request_ = false;
+      did_cancel_final_ = true;
+      return new CancelTestJob(request, network_delegate);
+    }
+    if (!intercept_final_response_)
+      return nullptr;
+    intercept_final_response_ = false;
+    did_intercept_final_ = true;
+    if (use_url_request_http_job_) {
+      return URLRequestHttpJob::Factory(request, network_delegate, "http");
+    }
+    return new URLRequestTestJob(request,
+                                 network_delegate,
+                                 final_headers_,
+                                 final_data_,
+                                 true);
+  }
+
+  void set_intercept_main_request(bool intercept_main_request) {
+    intercept_main_request_ = intercept_main_request;
+  }
+
+  void set_main_headers(const std::string& main_headers) {
+    main_headers_ = main_headers;
+  }
+
+  void set_main_data(const std::string& main_data) {
+    main_data_ = main_data;
+  }
+
+  void set_main_request_load_timing_info(
+      const LoadTimingInfo& main_request_load_timing_info) {
+    main_request_load_timing_info_ = main_request_load_timing_info;
+  }
+
+  void set_restart_main_request(bool restart_main_request) {
+    restart_main_request_ = restart_main_request;
+  }
+
+  void set_cancel_main_request(bool cancel_main_request) {
+    cancel_main_request_ = cancel_main_request;
+  }
+
+  void set_cancel_then_restart_main_request(
+      bool cancel_then_restart_main_request) {
+    cancel_then_restart_main_request_ = cancel_then_restart_main_request;
+  }
+
+  void set_simulate_main_network_error(bool simulate_main_network_error) {
+    simulate_main_network_error_ = simulate_main_network_error;
+  }
+
+  void set_intercept_redirect(bool intercept_redirect) {
+    intercept_redirect_ = intercept_redirect;
+  }
+
+  void set_redirect_headers(const std::string& redirect_headers) {
+    redirect_headers_ = redirect_headers;
+  }
+
+  void set_redirect_data(const std::string& redirect_data) {
+    redirect_data_ = redirect_data;
+  }
+
+  void set_cancel_redirect_request(bool cancel_redirect_request) {
+    cancel_redirect_request_ = cancel_redirect_request;
+  }
+
+  void set_intercept_final_response(bool intercept_final_response) {
+    intercept_final_response_ = intercept_final_response;
+  }
+
+  void set_final_headers(const std::string& final_headers) {
+    final_headers_ = final_headers;
+  }
+
+  void set_final_data(const std::string& final_data) {
+    final_data_ = final_data;
+  }
+
+  void set_cancel_final_request(bool cancel_final_request) {
+    cancel_final_request_ = cancel_final_request;
+  }
+
+  void set_use_url_request_http_job(bool use_url_request_http_job) {
+    use_url_request_http_job_ = use_url_request_http_job;
+  }
+
+  bool did_intercept_main() const {
+    return did_intercept_main_;
+  }
+
+  bool did_restart_main() const {
+    return did_restart_main_;
+  }
+
+  bool did_cancel_main() const {
+    return did_cancel_main_;
+  }
+
+  bool did_cancel_then_restart_main() const {
+    return did_cancel_then_restart_main_;
+  }
+
+  bool did_simulate_error_main() const {
+    return did_simulate_error_main_;
+  }
+
+  bool did_intercept_redirect() const {
+    return did_intercept_redirect_;
+  }
+
+  bool did_cancel_redirect() const {
+    return did_cancel_redirect_;
+  }
+
+  bool did_intercept_final() const {
+    return did_intercept_final_;
+  }
+
+  bool did_cancel_final() const {
+    return did_cancel_final_;
+  }
+
+ private:
+  // Indicate whether to intercept the main request, and if so specify the
+  // response to return and the LoadTimingInfo to use.
+  mutable bool intercept_main_request_;
+  mutable std::string main_headers_;
+  mutable std::string main_data_;
+  mutable LoadTimingInfo main_request_load_timing_info_;
+
+  // These indicate actions that can be taken within MaybeInterceptRequest.
+  mutable bool restart_main_request_;
+  mutable bool cancel_main_request_;
+  mutable bool cancel_then_restart_main_request_;
+  mutable bool simulate_main_network_error_;
+
+  // Indicate whether to intercept redirects, and if so specify the response to
+  // return.
+  mutable bool intercept_redirect_;
+  mutable std::string redirect_headers_;
+  mutable std::string redirect_data_;
+
+  // Cancel the request within MaybeInterceptRedirect.
+  mutable bool cancel_redirect_request_;
+
+  // Indicate whether to intercept the final response, and if so specify the
+  // response to return.
+  mutable bool intercept_final_response_;
+  mutable std::string final_headers_;
+  mutable std::string final_data_;
+
+  // Cancel the final request within MaybeInterceptResponse.
+  mutable bool cancel_final_request_;
+
+  // Instruct the interceptor to use a real URLRequestHTTPJob.
+  mutable bool use_url_request_http_job_;
+
+  // These indicate if the interceptor did something or not.
+  mutable bool did_intercept_main_;
+  mutable bool did_restart_main_;
+  mutable bool did_cancel_main_;
+  mutable bool did_cancel_then_restart_main_;
+  mutable bool did_simulate_error_main_;
+  mutable bool did_intercept_redirect_;
+  mutable bool did_cancel_redirect_;
+  mutable bool did_intercept_final_;
+  mutable bool did_cancel_final_;
+};
+
+// Inherit PlatformTest since we require the autorelease pool on Mac OS X.
+class URLRequestInterceptorTest : public URLRequestTest {
+ public:
+  URLRequestInterceptorTest() : URLRequestTest(), interceptor_(NULL) {
+  }
+
+  ~URLRequestInterceptorTest() override {
+    // URLRequestJobs may post clean-up tasks on destruction.
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void SetUpFactory() override {
+    interceptor_ = new MockURLRequestInterceptor();
+    job_factory_.reset(new URLRequestInterceptingJobFactory(
+        job_factory_.Pass(), make_scoped_ptr(interceptor_)));
+  }
+
+  MockURLRequestInterceptor* interceptor() const {
+    return interceptor_;
+  }
+
+ private:
+  MockURLRequestInterceptor* interceptor_;
+};
+
+TEST_F(URLRequestInterceptorTest, Intercept) {
+  // Intercept the main request and respond with a simple response.
+  interceptor()->set_intercept_main_request(true);
+  interceptor()->set_main_headers(MockURLRequestInterceptor::ok_headers());
+  interceptor()->set_main_data(MockURLRequestInterceptor::ok_data());
   TestDelegate d;
-  scoped_ptr<URLRequest> req(context->CreateRequest(
-      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+  base::SupportsUserData::Data* user_data0 = new base::SupportsUserData::Data();
+  base::SupportsUserData::Data* user_data1 = new base::SupportsUserData::Data();
+  base::SupportsUserData::Data* user_data2 = new base::SupportsUserData::Data();
+  req->SetUserData(nullptr, user_data0);
+  req->SetUserData(&user_data1, user_data1);
+  req->SetUserData(&user_data2, user_data2);
+  req->set_method("GET");
   req->Start();
   base::RunLoop().Run();
 
-  LoadTimingInfo resulting_load_timing;
-  req->GetLoadTimingInfo(&resulting_load_timing);
+  // Make sure we can retrieve our specific user data.
+  EXPECT_EQ(user_data0, req->GetUserData(nullptr));
+  EXPECT_EQ(user_data1, req->GetUserData(&user_data1));
+  EXPECT_EQ(user_data2, req->GetUserData(&user_data2));
 
-  // None of these should be modified by the URLRequest.
-  EXPECT_EQ(job_load_timing.socket_reused, resulting_load_timing.socket_reused);
-  EXPECT_EQ(job_load_timing.socket_log_id, resulting_load_timing.socket_log_id);
-  EXPECT_EQ(job_load_timing.send_start, resulting_load_timing.send_start);
-  EXPECT_EQ(job_load_timing.send_end, resulting_load_timing.send_end);
-  EXPECT_EQ(job_load_timing.receive_headers_end,
-            resulting_load_timing.receive_headers_end);
+  // Check that we got one good response.
+  EXPECT_TRUE(req->status().is_success());
+  EXPECT_EQ(200, req->response_headers()->response_code());
+  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
+  EXPECT_EQ(1, d.response_started_count());
+  EXPECT_EQ(0, d.received_redirect_count());
+}
 
-  return resulting_load_timing;
+TEST_F(URLRequestInterceptorTest, InterceptRedirect) {
+  // Intercept the main request and respond with a redirect.
+  interceptor()->set_intercept_main_request(true);
+  interceptor()->set_main_headers(
+      MockURLRequestInterceptor::redirect_headers());
+  interceptor()->set_main_data(MockURLRequestInterceptor::redirect_data());
+
+  // Intercept that redirect and respond with a final OK response.
+  interceptor()->set_intercept_redirect(true);
+  interceptor()->set_redirect_headers(MockURLRequestInterceptor::ok_headers());
+  interceptor()->set_redirect_data(MockURLRequestInterceptor::ok_data());
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+  req->set_method("GET");
+  req->Start();
+  base::RunLoop().Run();
+
+  // Check that the interceptor got called as expected.
+  EXPECT_TRUE(interceptor()->did_intercept_main());
+  EXPECT_TRUE(interceptor()->did_intercept_redirect());
+
+  // Check that we got one good response.
+  EXPECT_TRUE(req->status().is_success());
+  if (req->status().is_success())
+    EXPECT_EQ(200, req->response_headers()->response_code());
+
+  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
+  EXPECT_EQ(1, d.response_started_count());
+  EXPECT_EQ(0, d.received_redirect_count());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptServerError) {
+  // Intercept the main request to generate a server error response.
+  interceptor()->set_intercept_main_request(true);
+  interceptor()->set_main_headers(MockURLRequestInterceptor::error_headers());
+  interceptor()->set_main_data(MockURLRequestInterceptor::error_data());
+
+  // Intercept that error and respond with an OK response.
+  interceptor()->set_intercept_final_response(true);
+  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+  req->set_method("GET");
+  req->Start();
+  base::RunLoop().Run();
+
+  // Check that the interceptor got called as expected.
+  EXPECT_TRUE(interceptor()->did_intercept_main());
+  EXPECT_TRUE(interceptor()->did_intercept_final());
+
+  // Check that we got one good response.
+  EXPECT_TRUE(req->status().is_success());
+  EXPECT_EQ(200, req->response_headers()->response_code());
+  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
+  EXPECT_EQ(1, d.response_started_count());
+  EXPECT_EQ(0, d.received_redirect_count());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptNetworkError) {
+  // Intercept the main request to simulate a network error.
+  interceptor()->set_simulate_main_network_error(true);
+
+  // Intercept that error and respond with an OK response.
+  interceptor()->set_intercept_final_response(true);
+  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+  req->set_method("GET");
+  req->Start();
+  base::RunLoop().Run();
+
+  // Check that the interceptor got called as expected.
+  EXPECT_TRUE(interceptor()->did_simulate_error_main());
+  EXPECT_TRUE(interceptor()->did_intercept_final());
+
+  // Check that we received one good response.
+  EXPECT_TRUE(req->status().is_success());
+  EXPECT_EQ(200, req->response_headers()->response_code());
+  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
+  EXPECT_EQ(1, d.response_started_count());
+  EXPECT_EQ(0, d.received_redirect_count());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptRestartRequired) {
+  // Restart the main request.
+  interceptor()->set_restart_main_request(true);
+
+  // then intercept the new main request and respond with an OK response
+  interceptor()->set_intercept_main_request(true);
+  interceptor()->set_main_headers(MockURLRequestInterceptor::ok_headers());
+  interceptor()->set_main_data(MockURLRequestInterceptor::ok_data());
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+  req->set_method("GET");
+  req->Start();
+  base::RunLoop().Run();
+
+  // Check that the interceptor got called as expected.
+  EXPECT_TRUE(interceptor()->did_restart_main());
+  EXPECT_TRUE(interceptor()->did_intercept_main());
+
+  // Check that we received one good response.
+  EXPECT_TRUE(req->status().is_success());
+  if (req->status().is_success())
+    EXPECT_EQ(200, req->response_headers()->response_code());
+
+  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
+  EXPECT_EQ(1, d.response_started_count());
+  EXPECT_EQ(0, d.received_redirect_count());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelMain) {
+  // Intercept the main request and cancel from within the restarted job.
+  interceptor()->set_cancel_main_request(true);
+
+  // Set up to intercept the final response and override it with an OK response.
+  interceptor()->set_intercept_final_response(true);
+  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+  req->set_method("GET");
+  req->Start();
+  base::RunLoop().Run();
+
+  // Check that the interceptor got called as expected.
+  EXPECT_TRUE(interceptor()->did_cancel_main());
+  EXPECT_FALSE(interceptor()->did_intercept_final());
+
+  // Check that we see a canceled request.
+  EXPECT_FALSE(req->status().is_success());
+  EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelRedirect) {
+  // Intercept the main request and respond with a redirect.
+  interceptor()->set_intercept_main_request(true);
+  interceptor()->set_main_headers(
+      MockURLRequestInterceptor::redirect_headers());
+  interceptor()->set_main_data(MockURLRequestInterceptor::redirect_data());
+
+  // Intercept the redirect and cancel from within that job.
+  interceptor()->set_cancel_redirect_request(true);
+
+  // Set up to intercept the final response and override it with an OK response.
+  interceptor()->set_intercept_final_response(true);
+  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+  req->set_method("GET");
+  req->Start();
+  base::RunLoop().Run();
+
+  // Check that the interceptor got called as expected.
+  EXPECT_TRUE(interceptor()->did_intercept_main());
+  EXPECT_TRUE(interceptor()->did_cancel_redirect());
+  EXPECT_FALSE(interceptor()->did_intercept_final());
+
+  // Check that we see a canceled request.
+  EXPECT_FALSE(req->status().is_success());
+  EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelFinal) {
+  // Intercept the main request to simulate a network error.
+  interceptor()->set_simulate_main_network_error(true);
+
+  // Set up to intercept final the response and cancel from within that job.
+  interceptor()->set_cancel_final_request(true);
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+  req->set_method("GET");
+  req->Start();
+  base::RunLoop().Run();
+
+  // Check that the interceptor got called as expected.
+  EXPECT_TRUE(interceptor()->did_simulate_error_main());
+  EXPECT_TRUE(interceptor()->did_cancel_final());
+
+  // Check that we see a canceled request.
+  EXPECT_FALSE(req->status().is_success());
+  EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelInRestart) {
+  // Intercept the main request and cancel then restart from within that job.
+  interceptor()->set_cancel_then_restart_main_request(true);
+
+  // Set up to intercept the final response and override it with an OK response.
+  interceptor()->set_intercept_final_response(true);
+  interceptor()->set_final_headers(TestInterceptor::ok_headers());
+  interceptor()->set_final_data(TestInterceptor::ok_data());
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+  req->set_method("GET");
+  req->Start();
+  base::RunLoop().Run();
+
+  // Check that the interceptor got called as expected.
+  EXPECT_TRUE(interceptor()->did_cancel_then_restart_main());
+  EXPECT_FALSE(interceptor()->did_intercept_final());
+
+  // Check that we see a canceled request.
+  EXPECT_FALSE(req->status().is_success());
+  EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
 }
 
 // "Normal" LoadTimingInfo as returned by a job.  Everything is in order, not
@@ -1649,14 +2213,41 @@
   return load_timing;
 }
 
+LoadTimingInfo RunURLRequestInterceptorLoadTimingTest(
+    const LoadTimingInfo& job_load_timing,
+    const URLRequestContext& context,
+    MockURLRequestInterceptor* interceptor) {
+  interceptor->set_intercept_main_request(true);
+  interceptor->set_main_request_load_timing_info(job_load_timing);
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(context.CreateRequest(
+      GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+  req->Start();
+  base::RunLoop().Run();
+
+  LoadTimingInfo resulting_load_timing;
+  req->GetLoadTimingInfo(&resulting_load_timing);
+
+  // None of these should be modified by the URLRequest.
+  EXPECT_EQ(job_load_timing.socket_reused, resulting_load_timing.socket_reused);
+  EXPECT_EQ(job_load_timing.socket_log_id, resulting_load_timing.socket_log_id);
+  EXPECT_EQ(job_load_timing.send_start, resulting_load_timing.send_start);
+  EXPECT_EQ(job_load_timing.send_end, resulting_load_timing.send_end);
+  EXPECT_EQ(job_load_timing.receive_headers_end,
+            resulting_load_timing.receive_headers_end);
+
+  return resulting_load_timing;
+}
+
 // Basic test that the intercept + load timing tests work.
-TEST_F(URLRequestTest, InterceptLoadTiming) {
+TEST_F(URLRequestInterceptorTest, InterceptLoadTiming) {
   base::TimeTicks now = base::TimeTicks::Now();
   LoadTimingInfo job_load_timing =
       NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_DNS_TIMES, false);
 
   LoadTimingInfo load_timing_result =
-      RunLoadTimingTest(job_load_timing, &default_context_);
+      RunURLRequestInterceptorLoadTimingTest(
+          job_load_timing, default_context(), interceptor());
 
   // Nothing should have been changed by the URLRequest.
   EXPECT_EQ(job_load_timing.proxy_resolve_start,
@@ -1681,13 +2272,14 @@
 }
 
 // Another basic test, with proxy and SSL times, but no DNS times.
-TEST_F(URLRequestTest, InterceptLoadTimingProxy) {
+TEST_F(URLRequestInterceptorTest, InterceptLoadTimingProxy) {
   base::TimeTicks now = base::TimeTicks::Now();
   LoadTimingInfo job_load_timing =
       NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_SSL_TIMES, true);
 
   LoadTimingInfo load_timing_result =
-      RunLoadTimingTest(job_load_timing, &default_context_);
+      RunURLRequestInterceptorLoadTimingTest(
+          job_load_timing, default_context(), interceptor());
 
   // Nothing should have been changed by the URLRequest.
   EXPECT_EQ(job_load_timing.proxy_resolve_start,
@@ -1718,7 +2310,7 @@
 // reused in this test (May be a preconnect).
 //
 // To mix things up from the test above, assumes DNS times but no SSL times.
-TEST_F(URLRequestTest, InterceptLoadTimingEarlyProxyResolution) {
+TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyProxyResolution) {
   base::TimeTicks now = base::TimeTicks::Now();
   LoadTimingInfo job_load_timing =
       NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_DNS_TIMES, true);
@@ -1732,7 +2324,8 @@
       now - base::TimeDelta::FromDays(1);
 
   LoadTimingInfo load_timing_result =
-      RunLoadTimingTest(job_load_timing, &default_context_);
+      RunURLRequestInterceptorLoadTimingTest(
+          job_load_timing, default_context(), interceptor());
 
   // Proxy times, connect times, and DNS times should all be replaced with
   // request_start.
@@ -1755,14 +2348,16 @@
 }
 
 // Same as above, but in the reused case.
-TEST_F(URLRequestTest, InterceptLoadTimingEarlyProxyResolutionReused) {
+TEST_F(URLRequestInterceptorTest,
+       InterceptLoadTimingEarlyProxyResolutionReused) {
   base::TimeTicks now = base::TimeTicks::Now();
   LoadTimingInfo job_load_timing = NormalLoadTimingInfoReused(now, true);
   job_load_timing.proxy_resolve_start = now - base::TimeDelta::FromDays(4);
   job_load_timing.proxy_resolve_end = now - base::TimeDelta::FromDays(3);
 
   LoadTimingInfo load_timing_result =
-      RunLoadTimingTest(job_load_timing, &default_context_);
+      RunURLRequestInterceptorLoadTimingTest(
+          job_load_timing, default_context(), interceptor());
 
   // Proxy times and connect times should all be replaced with request_start.
   EXPECT_EQ(load_timing_result.request_start,
@@ -1779,7 +2374,7 @@
 // not considered reused in this test (May be a preconnect).
 //
 // To mix things up, the request has SSL times, but no DNS times.
-TEST_F(URLRequestTest, InterceptLoadTimingEarlyConnect) {
+TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyConnect) {
   base::TimeTicks now = base::TimeTicks::Now();
   LoadTimingInfo job_load_timing =
       NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_SSL_TIMES, false);
@@ -1791,7 +2386,8 @@
       now - base::TimeDelta::FromDays(4);
 
   LoadTimingInfo load_timing_result =
-      RunLoadTimingTest(job_load_timing, &default_context_);
+      RunURLRequestInterceptorLoadTimingTest(
+          job_load_timing, default_context(), interceptor());
 
   // Connect times, and SSL times should be replaced with request_start.
   EXPECT_EQ(load_timing_result.request_start,
@@ -1813,7 +2409,7 @@
 // test (May be a preconnect).
 //
 // In this test, there are no SSL or DNS times.
-TEST_F(URLRequestTest, InterceptLoadTimingEarlyConnectWithProxy) {
+TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyConnectWithProxy) {
   base::TimeTicks now = base::TimeTicks::Now();
   LoadTimingInfo job_load_timing =
       NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY, true);
@@ -1823,7 +2419,8 @@
       now - base::TimeDelta::FromDays(2);
 
   LoadTimingInfo load_timing_result =
-      RunLoadTimingTest(job_load_timing, &default_context_);
+      RunURLRequestInterceptorLoadTimingTest(
+          job_load_timing, default_context(), interceptor());
 
   // Connect times should be replaced with proxy_resolve_end.
   EXPECT_EQ(load_timing_result.proxy_resolve_end,
@@ -2665,6 +3262,11 @@
     return is_success;
   }
 
+  LocalHttpTestServer* test_server() {
+    return &test_server_;
+  }
+
+ protected:
   LocalHttpTestServer test_server_;
 };
 
@@ -5166,7 +5768,7 @@
   EXPECT_FALSE(data_protocol_handler.IsSafeRedirectTarget(data_url));
 
   // Test URLRequestJobFactoryImpl::IsSafeRedirectTarget().
-  EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(data_url));
+  EXPECT_FALSE(job_factory_->IsSafeRedirectTarget(data_url));
 }
 
 #if !defined(DISABLE_FILE_SUPPORT)
@@ -5177,7 +5779,7 @@
   EXPECT_FALSE(file_protocol_handler.IsSafeRedirectTarget(file_url));
 
   // Test URLRequestJobFactoryImpl::IsSafeRedirectTarget().
-  EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(file_url));
+  EXPECT_FALSE(job_factory_->IsSafeRedirectTarget(file_url));
 }
 
 TEST_F(URLRequestTestHTTP, RestrictFileRedirects) {
@@ -6446,6 +7048,124 @@
   EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, req->status().error());
 }
 
+class URLRequestInterceptorTestHTTP : public URLRequestTestHTTP {
+ public:
+  // TODO(bengr): Merge this with the URLRequestInterceptorHTTPTest fixture,
+  // ideally remove the dependency on URLRequestTestJob, and maybe move these
+  // tests into the factory tests.
+  URLRequestInterceptorTestHTTP() : URLRequestTestHTTP(), interceptor_(NULL) {
+  }
+
+  void SetUpFactory() override {
+    interceptor_ = new MockURLRequestInterceptor();
+    job_factory_.reset(new URLRequestInterceptingJobFactory(
+        job_factory_.Pass(), make_scoped_ptr(interceptor_)));
+  }
+
+  MockURLRequestInterceptor* interceptor() const {
+    return interceptor_;
+  }
+
+ private:
+  MockURLRequestInterceptor* interceptor_;
+};
+
+TEST_F(URLRequestInterceptorTestHTTP,
+       NetworkDelegateNotificationOnRedirectIntercept) {
+  interceptor()->set_intercept_redirect(true);
+  interceptor()->set_redirect_headers(MockURLRequestInterceptor::ok_headers());
+  interceptor()->set_redirect_data(MockURLRequestInterceptor::ok_data());
+
+  ASSERT_TRUE(test_server()->Start());
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      test_server()->GetURL("files/redirect-test.html"), DEFAULT_PRIORITY,
+      &d, nullptr));
+  req->Start();
+  base::RunLoop().Run();
+
+  EXPECT_TRUE(interceptor()->did_intercept_redirect());
+  // Check we got one good response
+  EXPECT_TRUE(req->status().is_success());
+  if (req->status().is_success())
+    EXPECT_EQ(200, req->response_headers()->response_code());
+
+  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
+  EXPECT_EQ(1, d.response_started_count());
+  EXPECT_EQ(0, d.received_redirect_count());
+
+  EXPECT_EQ(1, default_network_delegate()->created_requests());
+  EXPECT_EQ(1, default_network_delegate()->before_send_headers_count());
+  EXPECT_EQ(1, default_network_delegate()->headers_received_count());
+}
+
+TEST_F(URLRequestInterceptorTestHTTP,
+       NetworkDelegateNotificationOnErrorIntercept) {
+  // Intercept that error and respond with an OK response.
+  interceptor()->set_intercept_final_response(true);
+  interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+  interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
+  default_network_delegate()->set_can_be_intercepted_on_error(true);
+
+  ASSERT_TRUE(test_server()->Start());
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      test_server()->GetURL("files/two-content-lengths.html"), DEFAULT_PRIORITY,
+      &d, nullptr));
+  req->set_method("GET");
+  req->Start();
+  base::RunLoop().Run();
+
+  EXPECT_TRUE(interceptor()->did_intercept_final());
+
+  // Check we received one good response.
+  EXPECT_TRUE(req->status().is_success());
+  if (req->status().is_success())
+    EXPECT_EQ(200, req->response_headers()->response_code());
+  EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
+  EXPECT_EQ(1, d.response_started_count());
+  EXPECT_EQ(0, d.received_redirect_count());
+
+  EXPECT_EQ(1, default_network_delegate()->created_requests());
+  EXPECT_EQ(1, default_network_delegate()->before_send_headers_count());
+  EXPECT_EQ(0, default_network_delegate()->headers_received_count());
+}
+
+TEST_F(URLRequestInterceptorTestHTTP,
+       NetworkDelegateNotificationOnResponseIntercept) {
+  // Intercept that error and respond with an OK response.
+  interceptor()->set_intercept_final_response(true);
+
+  // Intercept with a real URLRequestHttpJob.
+  interceptor()->set_use_url_request_http_job(true);
+
+  ASSERT_TRUE(test_server()->Start());
+
+  TestDelegate d;
+  scoped_ptr<URLRequest> req(default_context().CreateRequest(
+      test_server()->GetURL("files/simple.html"), DEFAULT_PRIORITY,
+      &d, nullptr));
+  req->set_method("GET");
+  req->Start();
+  base::RunLoop().Run();
+
+  EXPECT_TRUE(interceptor()->did_intercept_final());
+
+  // Check we received one good response.
+  EXPECT_TRUE(req->status().is_success());
+  if (req->status().is_success())
+    EXPECT_EQ(200, req->response_headers()->response_code());
+  EXPECT_EQ("hello", d.data_received());
+  EXPECT_EQ(1, d.response_started_count());
+  EXPECT_EQ(0, d.received_redirect_count());
+
+  EXPECT_EQ(1, default_network_delegate()->created_requests());
+  EXPECT_EQ(2, default_network_delegate()->before_send_headers_count());
+  EXPECT_EQ(2, default_network_delegate()->headers_received_count());
+}
+
 class HTTPSRequestTest : public testing::Test {
  public:
   HTTPSRequestTest() : default_context_(true) {
@@ -7590,7 +8310,7 @@
 }
 
 static bool SystemSupportsOCSP() {
-#if defined(USE_OPENSSL)
+#if defined(USE_OPENSSL_CERTS)
   // http://crbug.com/117478 - OpenSSL does not support OCSP.
   return false;
 #elif defined(OS_WIN)
@@ -7603,6 +8323,16 @@
 #endif
 }
 
+static bool SystemSupportsOCSPStapling() {
+#if defined(USE_NSS)
+  return true;
+#elif defined(OS_WIN)
+  return base::win::GetVersion() >= base::win::VERSION_VISTA;
+#else
+  return false;
+#endif
+}
+
 TEST_F(HTTPSOCSPTest, Valid) {
   if (!SystemSupportsOCSP()) {
     LOG(WARNING) << "Skipping test because system doesn't support OCSP";
@@ -7666,6 +8396,51 @@
   EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
 }
 
+TEST_F(HTTPSOCSPTest, ValidStapled) {
+  if (!SystemSupportsOCSPStapling()) {
+    LOG(WARNING)
+        << "Skipping test because system doesn't support OCSP stapling";
+    return;
+  }
+
+  SpawnedTestServer::SSLOptions ssl_options(
+      SpawnedTestServer::SSLOptions::CERT_AUTO);
+  ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_OK;
+  ssl_options.staple_ocsp_response = true;
+  ssl_options.ocsp_server_unavailable = true;
+
+  CertStatus cert_status;
+  DoConnection(ssl_options, &cert_status);
+
+  EXPECT_EQ(0u, cert_status & CERT_STATUS_ALL_ERRORS);
+
+  EXPECT_EQ(SystemUsesChromiumEVMetadata(),
+            static_cast<bool>(cert_status & CERT_STATUS_IS_EV));
+
+  EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
+}
+
+TEST_F(HTTPSOCSPTest, RevokedStapled) {
+  if (!SystemSupportsOCSPStapling()) {
+    LOG(WARNING)
+        << "Skipping test because system doesn't support OCSP stapling";
+    return;
+  }
+
+  SpawnedTestServer::SSLOptions ssl_options(
+      SpawnedTestServer::SSLOptions::CERT_AUTO);
+  ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_REVOKED;
+  ssl_options.staple_ocsp_response = true;
+  ssl_options.ocsp_server_unavailable = true;
+
+  CertStatus cert_status;
+  DoConnection(ssl_options, &cert_status);
+
+  EXPECT_EQ(CERT_STATUS_REVOKED, cert_status & CERT_STATUS_ALL_ERRORS);
+  EXPECT_FALSE(cert_status & CERT_STATUS_IS_EV);
+  EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
+}
+
 class HTTPSHardFailTest : public HTTPSOCSPTest {
  protected:
   void SetupContext(URLRequestContext* context) override {
@@ -7677,7 +8452,6 @@
   }
 };
 
-
 TEST_F(HTTPSHardFailTest, FailsOnOCSPInvalid) {
   if (!SystemSupportsOCSP()) {
     LOG(WARNING) << "Skipping test because system doesn't support OCSP";
diff --git a/net/websockets/PRESUBMIT.py b/net/websockets/PRESUBMIT.py
deleted file mode 100644
index 1da441c..0000000
--- a/net/websockets/PRESUBMIT.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Chromium presubmit script for src/net/websockets.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details on the presubmit API built into gcl.
-"""
-
-
-# TODO(ricea): Remove this once the old implementation has been removed and the
-# list of files in the README file is no longer needed.
-def _CheckReadMeComplete(input_api, output_api):
-  """Verifies that any new files have been added to the README file.
-
-  Checks that if any source files were added in this CL, that they were
-  also added to the README file. We do not warn about pre-existing
-  errors, as that would be annoying.
-
-  Args:
-      input_api: The InputApi object provided by the presubmit framework.
-      output_api: The OutputApi object provided by the framework.
-
-  Returns:
-      A list of zero or more PresubmitPromptWarning objects.
-  """
-  # None passed to AffectedSourceFiles means "use the default filter", which
-  # does what we want, ie. returns files in the CL with filenames that look like
-  # source code.
-  added_source_filenames = set(input_api.basename(af.LocalPath())
-                               for af in input_api.AffectedSourceFiles(None)
-                               if af.Action().startswith('A'))
-  if not added_source_filenames:
-    return []
-  readme = input_api.AffectedSourceFiles(
-      lambda af: af.LocalPath().endswith('/README'))
-  if not readme:
-    return [output_api.PresubmitPromptWarning(
-        'One or more files were added to net/websockets without being added\n'
-        'to net/websockets/README.\n', added_source_filenames)]
-  readme_added_filenames = set(line.strip() for line in readme[0].NewContents()
-                               if line.strip() in added_source_filenames)
-  if readme_added_filenames < added_source_filenames:
-    return [output_api.PresubmitPromptWarning(
-        'One or more files added to net/websockets but not found in the README '
-        'file.\n', added_source_filenames - readme_added_filenames)]
-  else:
-    return []
-
-
-def CheckChangeOnUpload(input_api, output_api):
-  return _CheckReadMeComplete(input_api, output_api)
-
-
-def CheckChangeOnCommit(input_api, output_api):
-  return _CheckReadMeComplete(input_api, output_api)
diff --git a/net/websockets/README b/net/websockets/README
deleted file mode 100644
index efe7a59..0000000
--- a/net/websockets/README
+++ /dev/null
@@ -1,91 +0,0 @@
-This directory contains files related to Chromium's WebSocket
-implementation. See http://www.websocket.org/ for an explanation of WebSockets.
-
-As of April 2013, the contents of this directory are in a transitional state,
-and contain parts of two different WebSocket implementations.
-
-The following files are part of the legacy implementation. The legacy
-implementation performs WebSocket framing within Blink and presents a
-low-level socket-like interface to the renderer process. It is described in the
-design doc at
-https://docs.google.com/a/google.com/document/d/1_R6YjCIrm4kikJ3YeapcOU2Keqr3lVUPd-OeaIJ93qQ/preview
-
-websocket_handshake_handler_test.cc
-websocket_handshake_handler_spdy_test.cc
-websocket_job.cc
-websocket_job.h
-websocket_job_test.cc
-websocket_net_log_params.cc
-websocket_net_log_params.h
-websocket_net_log_params_test.cc
-websocket_throttle.cc
-websocket_throttle.h
-websocket_throttle_test.cc
-
-The following files are part of the new implementation. The new implementation
-performs framing and implements protocol semantics in the browser process, and
-presents a high-level interface to the renderer process similar to a
-multiplexing proxy. This is the default implementation from M38.
-
-websocket_basic_handshake_stream.cc
-websocket_basic_handshake_stream.h
-websocket_basic_stream.cc
-websocket_basic_stream.h
-websocket_basic_stream_test.cc
-websocket_channel.cc
-websocket_channel.h
-websocket_channel_test.cc
-websocket_deflate_predictor.h
-websocket_deflate_predictor_impl.cc
-websocket_deflate_predictor_impl.h
-websocket_deflate_predictor_impl_test.cc
-websocket_deflate_stream.cc
-websocket_deflate_stream.h
-websocket_deflate_stream_test.cc
-websocket_deflater.cc
-websocket_deflater.h
-websocket_deflater_test.cc
-websocket_errors.cc
-websocket_errors.h
-websocket_errors_test.cc
-websocket_event_interface.h
-websocket_extension.cc
-websocket_extension.h
-websocket_extension_parser.cc
-websocket_extension_parser.h
-websocket_extension_parser_test.cc
-websocket_frame.cc
-websocket_frame.h
-websocket_frame_parser.cc
-websocket_frame_parser.h
-websocket_frame_parser_test.cc
-websocket_frame_test.cc
-websocket_frame_perftest.cc
-websocket_handshake_stream_base.h
-websocket_handshake_stream_create_helper.cc
-websocket_handshake_stream_create_helper.h
-websocket_handshake_stream_create_helper_test.cc
-websocket_handshake_request_info.cc
-websocket_handshake_request_info.h
-websocket_handshake_response_info.cc
-websocket_handshake_response_info.h
-websocket_inflater.cc
-websocket_inflater.h
-websocket_inflater_test.cc
-websocket_mux.h
-websocket_stream.cc
-websocket_stream.h
-websocket_stream_test.cc
-websocket_test_util.cc
-websocket_test_util.h
-
-These files are shared between the old and new implementations.
-
-websocket_handshake_constants.cc
-websocket_handshake_constants.h
-websocket_handshake_handler.cc
-websocket_handshake_handler.h
-
-A pre-submit check helps us keep this README file up-to-date:
-
-PRESUBMIT.py
diff --git a/net/websockets/websocket_channel.cc b/net/websockets/websocket_channel.cc
index 598b5e6..30abb2db 100644
--- a/net/websockets/websocket_channel.cc
+++ b/net/websockets/websocket_channel.cc
@@ -44,9 +44,16 @@
 const int kDefaultSendQuotaLowWaterMark = 1 << 16;
 const int kDefaultSendQuotaHighWaterMark = 1 << 17;
 const size_t kWebSocketCloseCodeLength = 2;
-// This timeout is based on TCPMaximumSegmentLifetime * 2 from
-// MainThreadWebSocketChannel.cpp in Blink.
-const int kClosingHandshakeTimeoutSeconds = 2 * 2 * 60;
+// Timeout for waiting for the server to acknowledge a closing handshake.
+const int kClosingHandshakeTimeoutSeconds = 60;
+// We wait for the server to close the underlying connection as recommended in
+// https://tools.ietf.org/html/rfc6455#section-7.1.1
+// We don't use 2MSL since there're server implementations that don't follow
+// the recommendation and wait for the client to close the underlying
+// connection. It leads to unnecessarily long time before CloseEvent
+// invocation. We want to avoid this rather than strictly following the spec
+// recommendation.
+const int kUnderlyingConnectionCloseTimeoutSeconds = 2;
 
 typedef WebSocketEventInterface::ChannelState ChannelState;
 const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
@@ -296,7 +303,10 @@
       send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark),
       current_send_quota_(0),
       current_receive_quota_(0),
-      timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)),
+      closing_handshake_timeout_(base::TimeDelta::FromSeconds(
+          kClosingHandshakeTimeoutSeconds)),
+      underlying_connection_close_timeout_(base::TimeDelta::FromSeconds(
+          kUnderlyingConnectionCloseTimeoutSeconds)),
       has_received_close_frame_(false),
       received_close_code_(0),
       state_(FRESHLY_CONSTRUCTED),
@@ -312,7 +322,7 @@
   stream_.reset();
   // The timer may have a callback pointing back to us, so stop it just in case
   // someone decides to run the event loop from their destructor.
-  timer_.Stop();
+  close_timer_.Stop();
 }
 
 void WebSocketChannel::SendAddChannelRequest(
@@ -478,6 +488,15 @@
     NOTREACHED() << "StartClosingHandshake() called in state " << state_;
     return;
   }
+
+  DCHECK(!close_timer_.IsRunning());
+  // This use of base::Unretained() is safe because we stop the timer in the
+  // destructor.
+  close_timer_.Start(
+      FROM_HERE,
+      closing_handshake_timeout_,
+      base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this)));
+
   // Javascript actually only permits 1000 and 3000-4999, but the implementation
   // itself may produce different codes. The length of |reason| is also checked
   // by Javascript.
@@ -513,7 +532,12 @@
 
 void WebSocketChannel::SetClosingHandshakeTimeoutForTesting(
     base::TimeDelta delay) {
-  timeout_ = delay;
+  closing_handshake_timeout_ = delay;
+}
+
+void WebSocketChannel::SetUnderlyingConnectionCloseTimeoutForTesting(
+    base::TimeDelta delay) {
+  underlying_connection_close_timeout_ = delay;
 }
 
 void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator(
@@ -839,10 +863,20 @@
       switch (state_) {
         case CONNECTED:
           SetState(RECV_CLOSED);
+
           if (SendClose(code, reason) == CHANNEL_DELETED)
             return CHANNEL_DELETED;
           DCHECK_EQ(RECV_CLOSED, state_);
+
           SetState(CLOSE_WAIT);
+          DCHECK(!close_timer_.IsRunning());
+          // This use of base::Unretained() is safe because we stop the timer
+          // in the destructor.
+          close_timer_.Start(
+              FROM_HERE,
+              underlying_connection_close_timeout_,
+              base::Bind(
+                  &WebSocketChannel::CloseTimeout, base::Unretained(this)));
 
           if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED)
             return CHANNEL_DELETED;
@@ -853,6 +887,16 @@
 
         case SEND_CLOSED:
           SetState(CLOSE_WAIT);
+          DCHECK(close_timer_.IsRunning());
+          close_timer_.Stop();
+          // This use of base::Unretained() is safe because we stop the timer
+          // in the destructor.
+          close_timer_.Start(
+              FROM_HERE,
+              underlying_connection_close_timeout_,
+              base::Bind(
+                  &WebSocketChannel::CloseTimeout, base::Unretained(this)));
+
           // From RFC6455 section 7.1.5: "Each endpoint
           // will see the status code sent by the other end as _The WebSocket
           // Connection Close Code_."
@@ -1027,12 +1071,6 @@
     std::copy(
         reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength);
   }
-  // This use of base::Unretained() is safe because we stop the timer in the
-  // destructor.
-  timer_.Start(
-      FROM_HERE,
-      timeout_,
-      base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this)));
   if (SendFrameFromIOBuffer(
           true, WebSocketFrameHeader::kOpCodeClose, body, size) ==
       CHANNEL_DELETED)
diff --git a/net/websockets/websocket_channel.h b/net/websockets/websocket_channel.h
index 59e50a1..4df6a62 100644
--- a/net/websockets/websocket_channel.h
+++ b/net/websockets/websocket_channel.h
@@ -110,6 +110,11 @@
   // set it to a very small value for testing purposes.
   void SetClosingHandshakeTimeoutForTesting(base::TimeDelta delay);
 
+  // The default timout for the underlying connection close is a sensible value
+  // (see kUnderlyingConnectionCloseTimeoutSeconds in websocket_channel.cc).
+  // However, we can set it to a very small value for testing purposes.
+  void SetUnderlyingConnectionCloseTimeoutForTesting(base::TimeDelta delay);
+
   // Called when the stream starts the WebSocket Opening Handshake.
   // This method is public for testing.
   void OnStartOpeningHandshake(
@@ -371,10 +376,14 @@
   uint64 current_receive_quota_;
 
   // Timer for the closing handshake.
-  base::OneShotTimer<WebSocketChannel> timer_;
+  base::OneShotTimer<WebSocketChannel> close_timer_;
 
   // Timeout for the closing handshake.
-  base::TimeDelta timeout_;
+  base::TimeDelta closing_handshake_timeout_;
+
+  // Timeout for the underlying connection close after completion of closing
+  // handshake.
+  base::TimeDelta underlying_connection_close_timeout_;
 
   // Storage for the status code and reason from the time the Close frame
   // arrives until the connection is closed and they are passed to
diff --git a/net/websockets/websocket_channel_test.cc b/net/websockets/websocket_channel_test.cc
index f814f10..d5ec3da 100644
--- a/net/websockets/websocket_channel_test.cc
+++ b/net/websockets/websocket_channel_test.cc
@@ -127,6 +127,8 @@
 // kDefaultSendQuotaLowWaterMark change.
 const size_t kDefaultQuotaRefreshTrigger = (1 << 16) + 1;
 
+const int kVeryBigTimeoutMillis = 60 * 60 * 24 * 1000;
+
 // TestTimeouts::tiny_timeout() is 100ms! I could run halfway around the world
 // in that time! I would like my tests to run a bit quicker.
 const int kVeryTinyTimeoutMillis = 1;
@@ -2145,6 +2147,8 @@
   // was fired by the behaviour of the WebSocketChannel object.
   channel_->SetClosingHandshakeTimeoutForTesting(
       TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
+  channel_->SetUnderlyingConnectionCloseTimeoutForTesting(
+      TimeDelta::FromMilliseconds(kVeryBigTimeoutMillis));
   channel_->StartClosingHandshake(kWebSocketNormalClosure, "");
   checkpoint.Call(1);
   completion.WaitForResult();
@@ -2175,6 +2179,8 @@
   }
   CreateChannelAndConnectSuccessfully();
   channel_->SetClosingHandshakeTimeoutForTesting(
+      TimeDelta::FromMilliseconds(kVeryBigTimeoutMillis));
+  channel_->SetUnderlyingConnectionCloseTimeoutForTesting(
       TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
   checkpoint.Call(1);
   completion.WaitForResult();
@@ -3304,6 +3310,8 @@
     channel_->SendFlowControl(kPlentyOfQuota);
     channel_->SetClosingHandshakeTimeoutForTesting(
         TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
+    channel_->SetUnderlyingConnectionCloseTimeoutForTesting(
+        TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
     connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
   }
 };
diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc
index 6324710..6bcc230 100644
--- a/net/websockets/websocket_handshake_handler.cc
+++ b/net/websockets/websocket_handshake_handler.cc
@@ -4,346 +4,12 @@
 
 #include "net/websockets/websocket_handshake_handler.h"
 
-#include <limits>
-
 #include "base/base64.h"
+#include "base/logging.h"
 #include "base/sha1.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_tokenizer.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_util.h"
 #include "net/websockets/websocket_handshake_constants.h"
-#include "url/gurl.h"
 
 namespace net {
-namespace {
-
-const int kVersionHeaderValueForRFC6455 = 13;
-
-// Splits |handshake_message| into Status-Line or Request-Line (including CRLF)
-// and headers (excluding 2nd CRLF of double CRLFs at the end of a handshake
-// response).
-void ParseHandshakeHeader(
-    const char* handshake_message, int len,
-    std::string* request_line,
-    std::string* headers) {
-  size_t i = base::StringPiece(handshake_message, len).find_first_of("\r\n");
-  if (i == base::StringPiece::npos) {
-    *request_line = std::string(handshake_message, len);
-    *headers = "";
-    return;
-  }
-  // |request_line| includes \r\n.
-  *request_line = std::string(handshake_message, i + 2);
-
-  int header_len = len - (i + 2) - 2;
-  if (header_len > 0) {
-    // |handshake_message| includes trailing \r\n\r\n.
-    // |headers| doesn't include 2nd \r\n.
-    *headers = std::string(handshake_message + i + 2, header_len);
-  } else {
-    *headers = "";
-  }
-}
-
-void FetchHeaders(const std::string& headers,
-                  const char* const headers_to_get[],
-                  size_t headers_to_get_len,
-                  std::vector<std::string>* values) {
-  net::HttpUtil::HeadersIterator iter(headers.begin(), headers.end(), "\r\n");
-  while (iter.GetNext()) {
-    for (size_t i = 0; i < headers_to_get_len; i++) {
-      if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(),
-                               headers_to_get[i])) {
-        values->push_back(iter.values());
-      }
-    }
-  }
-}
-
-bool GetHeaderName(std::string::const_iterator line_begin,
-                   std::string::const_iterator line_end,
-                   std::string::const_iterator* name_begin,
-                   std::string::const_iterator* name_end) {
-  std::string::const_iterator colon = std::find(line_begin, line_end, ':');
-  if (colon == line_end) {
-    return false;
-  }
-  *name_begin = line_begin;
-  *name_end = colon;
-  if (*name_begin == *name_end || net::HttpUtil::IsLWS(**name_begin))
-    return false;
-  net::HttpUtil::TrimLWS(name_begin, name_end);
-  return true;
-}
-
-// Similar to HttpUtil::StripHeaders, but it preserves malformed headers, that
-// is, lines that are not formatted as "<name>: <value>\r\n".
-std::string FilterHeaders(
-    const std::string& headers,
-    const char* const headers_to_remove[],
-    size_t headers_to_remove_len) {
-  std::string filtered_headers;
-
-  base::StringTokenizer lines(headers.begin(), headers.end(), "\r\n");
-  while (lines.GetNext()) {
-    std::string::const_iterator line_begin = lines.token_begin();
-    std::string::const_iterator line_end = lines.token_end();
-    std::string::const_iterator name_begin;
-    std::string::const_iterator name_end;
-    bool should_remove = false;
-    if (GetHeaderName(line_begin, line_end, &name_begin, &name_end)) {
-      for (size_t i = 0; i < headers_to_remove_len; ++i) {
-        if (LowerCaseEqualsASCII(name_begin, name_end, headers_to_remove[i])) {
-          should_remove = true;
-          break;
-        }
-      }
-    }
-    if (!should_remove) {
-      filtered_headers.append(line_begin, line_end);
-      filtered_headers.append("\r\n");
-    }
-  }
-  return filtered_headers;
-}
-
-bool CheckVersionInRequest(const std::string& request_headers) {
-  std::vector<std::string> values;
-  const char* const headers_to_get[1] = {
-    websockets::kSecWebSocketVersionLowercase};
-  FetchHeaders(request_headers, headers_to_get, 1, &values);
-  DCHECK_LE(values.size(), 1U);
-  if (values.empty())
-    return false;
-
-  int version;
-  bool conversion_success = base::StringToInt(values[0], &version);
-  if (!conversion_success)
-    return false;
-
-  return version == kVersionHeaderValueForRFC6455;
-}
-
-// Append a header to a string. Equivalent to
-//   response_message += header + ": " + value + "\r\n"
-// but avoids unnecessary allocations and copies.
-void AppendHeader(const base::StringPiece& header,
-                  const base::StringPiece& value,
-                  std::string* response_message) {
-  static const char kColonSpace[] = ": ";
-  const size_t kColonSpaceSize = sizeof(kColonSpace) - 1;
-  static const char kCrNl[] = "\r\n";
-  const size_t kCrNlSize = sizeof(kCrNl) - 1;
-
-  size_t extra_size =
-      header.size() + kColonSpaceSize + value.size() + kCrNlSize;
-  response_message->reserve(response_message->size() + extra_size);
-  response_message->append(header.begin(), header.end());
-  response_message->append(kColonSpace, kColonSpace + kColonSpaceSize);
-  response_message->append(value.begin(), value.end());
-  response_message->append(kCrNl, kCrNl + kCrNlSize);
-}
-
-}  // namespace
-
-WebSocketHandshakeRequestHandler::WebSocketHandshakeRequestHandler()
-    : original_length_(0),
-      raw_length_(0) {}
-
-bool WebSocketHandshakeRequestHandler::ParseRequest(
-    const char* data, int length) {
-  DCHECK_GT(length, 0);
-  std::string input(data, length);
-  int input_header_length =
-      HttpUtil::LocateEndOfHeaders(input.data(), input.size(), 0);
-  if (input_header_length <= 0)
-    return false;
-
-  ParseHandshakeHeader(input.data(),
-                       input_header_length,
-                       &request_line_,
-                       &headers_);
-
-  if (!CheckVersionInRequest(headers_)) {
-    NOTREACHED();
-    return false;
-  }
-
-  original_length_ = input_header_length;
-  return true;
-}
-
-size_t WebSocketHandshakeRequestHandler::original_length() const {
-  return original_length_;
-}
-
-void WebSocketHandshakeRequestHandler::AppendHeaderIfMissing(
-    const std::string& name, const std::string& value) {
-  DCHECK(!headers_.empty());
-  HttpUtil::AppendHeaderIfMissing(name.c_str(), value, &headers_);
-}
-
-void WebSocketHandshakeRequestHandler::RemoveHeaders(
-    const char* const headers_to_remove[],
-    size_t headers_to_remove_len) {
-  DCHECK(!headers_.empty());
-  headers_ = FilterHeaders(
-      headers_, headers_to_remove, headers_to_remove_len);
-}
-
-HttpRequestInfo WebSocketHandshakeRequestHandler::GetRequestInfo(
-    const GURL& url, std::string* challenge) {
-  HttpRequestInfo request_info;
-  request_info.url = url;
-  size_t method_end = base::StringPiece(request_line_).find_first_of(" ");
-  if (method_end != base::StringPiece::npos)
-    request_info.method = std::string(request_line_.data(), method_end);
-
-  request_info.extra_headers.Clear();
-  request_info.extra_headers.AddHeadersFromString(headers_);
-
-  request_info.extra_headers.RemoveHeader(websockets::kUpgrade);
-  request_info.extra_headers.RemoveHeader(HttpRequestHeaders::kConnection);
-
-  std::string key;
-  bool header_present = request_info.extra_headers.GetHeader(
-      websockets::kSecWebSocketKey, &key);
-  DCHECK(header_present);
-  request_info.extra_headers.RemoveHeader(websockets::kSecWebSocketKey);
-  *challenge = key;
-  return request_info;
-}
-
-bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock(
-    const GURL& url,
-    SpdyHeaderBlock* headers,
-    std::string* challenge,
-    int spdy_protocol_version) {
-  // Construct opening handshake request headers as a SPDY header block.
-  // For details, see WebSocket Layering over SPDY/3 Draft 8.
-  if (spdy_protocol_version <= 2) {
-    (*headers)["path"] = url.path();
-    (*headers)["version"] = "WebSocket/13";
-    (*headers)["scheme"] = url.scheme();
-  } else {
-    (*headers)[":path"] = url.path();
-    (*headers)[":version"] = "WebSocket/13";
-    (*headers)[":scheme"] = url.scheme();
-  }
-
-  HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n");
-  while (iter.GetNext()) {
-    if (LowerCaseEqualsASCII(iter.name_begin(),
-                             iter.name_end(),
-                             websockets::kUpgradeLowercase) ||
-        LowerCaseEqualsASCII(
-            iter.name_begin(), iter.name_end(), "connection") ||
-        LowerCaseEqualsASCII(iter.name_begin(),
-                             iter.name_end(),
-                             websockets::kSecWebSocketVersionLowercase)) {
-      // These headers must be ignored.
-      continue;
-    } else if (LowerCaseEqualsASCII(iter.name_begin(),
-                                    iter.name_end(),
-                                    websockets::kSecWebSocketKeyLowercase)) {
-      *challenge = iter.values();
-      // Sec-WebSocket-Key is not sent to the server.
-      continue;
-    } else if (LowerCaseEqualsASCII(
-                   iter.name_begin(), iter.name_end(), "host") ||
-               LowerCaseEqualsASCII(
-                   iter.name_begin(), iter.name_end(), "origin") ||
-               LowerCaseEqualsASCII(
-                   iter.name_begin(),
-                   iter.name_end(),
-                   websockets::kSecWebSocketProtocolLowercase) ||
-               LowerCaseEqualsASCII(
-                   iter.name_begin(),
-                   iter.name_end(),
-                   websockets::kSecWebSocketExtensionsLowercase)) {
-      // TODO(toyoshim): Some WebSocket extensions may not be compatible with
-      // SPDY. We should omit them from a Sec-WebSocket-Extension header.
-      std::string name;
-      if (spdy_protocol_version <= 2)
-        name = base::StringToLowerASCII(iter.name());
-      else
-        name = ":" + base::StringToLowerASCII(iter.name());
-      (*headers)[name] = iter.values();
-      continue;
-    }
-    // Others should be sent out to |headers|.
-    std::string name = base::StringToLowerASCII(iter.name());
-    SpdyHeaderBlock::iterator found = headers->find(name);
-    if (found == headers->end()) {
-      (*headers)[name] = iter.values();
-    } else {
-      // For now, websocket doesn't use multiple headers, but follows to http.
-      found->second.append(1, '\0');  // +=() doesn't append 0's
-      found->second.append(iter.values());
-    }
-  }
-
-  return true;
-}
-
-std::string WebSocketHandshakeRequestHandler::GetRawRequest() {
-  DCHECK(!request_line_.empty());
-  DCHECK(!headers_.empty());
-
-  std::string raw_request = request_line_ + headers_ + "\r\n";
-  raw_length_ = raw_request.size();
-  return raw_request;
-}
-
-size_t WebSocketHandshakeRequestHandler::raw_length() const {
-  DCHECK_GT(raw_length_, 0);
-  return raw_length_;
-}
-
-WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler()
-    : original_header_length_(0) {}
-
-WebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {}
-
-size_t WebSocketHandshakeResponseHandler::ParseRawResponse(
-    const char* data, int length) {
-  DCHECK_GT(length, 0);
-  if (HasResponse()) {
-    DCHECK(!status_line_.empty());
-    // headers_ might be empty for wrong response from server.
-
-    return 0;
-  }
-
-  size_t old_original_length = original_.size();
-
-  original_.append(data, length);
-  // TODO(ukai): fail fast when response gives wrong status code.
-  original_header_length_ = HttpUtil::LocateEndOfHeaders(
-      original_.data(), original_.size(), 0);
-  if (!HasResponse())
-    return length;
-
-  ParseHandshakeHeader(original_.data(),
-                       original_header_length_,
-                       &status_line_,
-                       &headers_);
-  int header_size = status_line_.size() + headers_.size();
-  DCHECK_GE(original_header_length_, header_size);
-  header_separator_ = std::string(original_.data() + header_size,
-                                  original_header_length_ - header_size);
-  return original_header_length_ - old_original_length;
-}
-
-bool WebSocketHandshakeResponseHandler::HasResponse() const {
-  return original_header_length_ > 0 &&
-      static_cast<size_t>(original_header_length_) <= original_.size();
-}
 
 void ComputeSecWebSocketAccept(const std::string& key,
                                std::string* accept) {
@@ -354,145 +20,4 @@
   base::Base64Encode(hash, accept);
 }
 
-bool WebSocketHandshakeResponseHandler::ParseResponseInfo(
-    const HttpResponseInfo& response_info,
-    const std::string& challenge) {
-  if (!response_info.headers.get())
-    return false;
-
-  // TODO(ricea): Eliminate all the reallocations and string copies.
-  std::string response_message;
-  response_message = response_info.headers->GetStatusLine();
-  response_message += "\r\n";
-
-  AppendHeader(websockets::kUpgrade,
-               websockets::kWebSocketLowercase,
-               &response_message);
-
-  AppendHeader(
-      HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message);
-
-  std::string websocket_accept;
-  ComputeSecWebSocketAccept(challenge, &websocket_accept);
-  AppendHeader(
-      websockets::kSecWebSocketAccept, websocket_accept, &response_message);
-
-  void* iter = NULL;
-  std::string name;
-  std::string value;
-  while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) {
-    AppendHeader(name, value, &response_message);
-  }
-  response_message += "\r\n";
-
-  return ParseRawResponse(response_message.data(),
-                          response_message.size()) == response_message.size();
-}
-
-bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock(
-    const SpdyHeaderBlock& headers,
-    const std::string& challenge,
-    int spdy_protocol_version) {
-  SpdyHeaderBlock::const_iterator status;
-  if (spdy_protocol_version <= 2)
-    status = headers.find("status");
-  else
-    status = headers.find(":status");
-  if (status == headers.end())
-    return false;
-
-  std::string hash =
-      base::SHA1HashString(challenge + websockets::kWebSocketGuid);
-  std::string websocket_accept;
-  base::Base64Encode(hash, &websocket_accept);
-
-  std::string response_message = base::StringPrintf(
-      "%s %s\r\n", websockets::kHttpProtocolVersion, status->second.c_str());
-
-  AppendHeader(
-      websockets::kUpgrade, websockets::kWebSocketLowercase, &response_message);
-  AppendHeader(
-      HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message);
-  AppendHeader(
-      websockets::kSecWebSocketAccept, websocket_accept, &response_message);
-
-  for (SpdyHeaderBlock::const_iterator iter = headers.begin();
-       iter != headers.end();
-       ++iter) {
-    // For each value, if the server sends a NUL-separated list of values,
-    // we separate that back out into individual headers for each value
-    // in the list.
-    if ((spdy_protocol_version <= 2 &&
-         LowerCaseEqualsASCII(iter->first, "status")) ||
-        (spdy_protocol_version >= 3 &&
-         LowerCaseEqualsASCII(iter->first, ":status"))) {
-      // The status value is already handled as the first line of
-      // |response_message|. Just skip here.
-      continue;
-    }
-    const std::string& value = iter->second;
-    size_t start = 0;
-    size_t end = 0;
-    do {
-      end = value.find('\0', start);
-      std::string tval;
-      if (end != std::string::npos)
-        tval = value.substr(start, (end - start));
-      else
-        tval = value.substr(start);
-      if (spdy_protocol_version >= 3 &&
-          (LowerCaseEqualsASCII(iter->first,
-                                websockets::kSecWebSocketProtocolSpdy3) ||
-           LowerCaseEqualsASCII(iter->first,
-                                websockets::kSecWebSocketExtensionsSpdy3)))
-        AppendHeader(iter->first.substr(1), tval, &response_message);
-      else
-        AppendHeader(iter->first, tval, &response_message);
-      start = end + 1;
-    } while (end != std::string::npos);
-  }
-  response_message += "\r\n";
-
-  return ParseRawResponse(response_message.data(),
-                          response_message.size()) == response_message.size();
-}
-
-void WebSocketHandshakeResponseHandler::GetHeaders(
-    const char* const headers_to_get[],
-    size_t headers_to_get_len,
-    std::vector<std::string>* values) {
-  DCHECK(HasResponse());
-  DCHECK(!status_line_.empty());
-  // headers_ might be empty for wrong response from server.
-  if (headers_.empty())
-    return;
-
-  FetchHeaders(headers_, headers_to_get, headers_to_get_len, values);
-}
-
-void WebSocketHandshakeResponseHandler::RemoveHeaders(
-    const char* const headers_to_remove[],
-    size_t headers_to_remove_len) {
-  DCHECK(HasResponse());
-  DCHECK(!status_line_.empty());
-  // headers_ might be empty for wrong response from server.
-  if (headers_.empty())
-    return;
-
-  headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len);
-}
-
-std::string WebSocketHandshakeResponseHandler::GetRawResponse() const {
-  DCHECK(HasResponse());
-  return original_.substr(0, original_header_length_);
-}
-
-std::string WebSocketHandshakeResponseHandler::GetResponse() {
-  DCHECK(HasResponse());
-  DCHECK(!status_line_.empty());
-  // headers_ might be empty for wrong response from server.
-
-  return status_line_ + headers_ + header_separator_;
-}
-
 }  // namespace net
diff --git a/net/websockets/websocket_handshake_handler.h b/net/websockets/websocket_handshake_handler.h
index 73af66d..c65e6d9 100644
--- a/net/websockets/websocket_handshake_handler.h
+++ b/net/websockets/websocket_handshake_handler.h
@@ -1,124 +1,19 @@
 // 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.
-//
-// WebSocketHandshake*Handler handles WebSocket handshake request message
-// from WebKit renderer process, and WebSocket handshake response message
-// from WebSocket server.
-// It modifies messages for the following reason:
-// - We don't trust WebKit renderer process, so we'll not expose HttpOnly
-//   cookies to the renderer process, so handles HttpOnly cookies in
-//   browser process.
-//
+
 #ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
 #define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
 
 #include <string>
-#include <vector>
-
-#include "net/base/net_export.h"
-#include "net/http/http_request_info.h"
-#include "net/http/http_response_info.h"
-#include "net/spdy/spdy_header_block.h"
 
 namespace net {
 
+// Given a WebSocket handshake challenge, compute the correct response.
+// TODO(ricea): There should probably be a test for this.
 void ComputeSecWebSocketAccept(const std::string& key,
                                std::string* accept);
 
-class NET_EXPORT_PRIVATE WebSocketHandshakeRequestHandler {
- public:
-  WebSocketHandshakeRequestHandler();
-  ~WebSocketHandshakeRequestHandler() {}
-
-  // Parses WebSocket handshake request from renderer process.
-  // It assumes a WebSocket handshake request message is given at once, and
-  // no other data is added to the request message.
-  bool ParseRequest(const char* data, int length);
-
-  size_t original_length() const;
-
-  // Appends the header value pair for |name| and |value|, if |name| doesn't
-  // exist.
-  void AppendHeaderIfMissing(const std::string& name,
-                             const std::string& value);
-  // Removes the headers that matches (case insensitive).
-  void RemoveHeaders(const char* const headers_to_remove[],
-                     size_t headers_to_remove_len);
-
-  // Gets request info to open WebSocket connection and fills challenge data in
-  // |challenge|.
-  HttpRequestInfo GetRequestInfo(const GURL& url, std::string* challenge);
-  // Gets request as SpdyHeaderBlock.
-  // Also, fills challenge data in |challenge|.
-  bool GetRequestHeaderBlock(const GURL& url,
-                             SpdyHeaderBlock* headers,
-                             std::string* challenge,
-                             int spdy_protocol_version);
-  // Gets WebSocket handshake raw request message to open WebSocket
-  // connection.
-  std::string GetRawRequest();
-  // Calling raw_length is valid only after GetRawRequest() call.
-  size_t raw_length() const;
-
- private:
-  std::string request_line_;
-  std::string headers_;
-  int original_length_;
-  int raw_length_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeRequestHandler);
-};
-
-class NET_EXPORT_PRIVATE WebSocketHandshakeResponseHandler {
- public:
-  WebSocketHandshakeResponseHandler();
-  ~WebSocketHandshakeResponseHandler();
-
-  // Parses WebSocket handshake response from WebSocket server.
-  // Returns number of bytes in |data| used for WebSocket handshake response
-  // message.  If it already got whole WebSocket handshake response message,
-  // returns zero.  In other words, [data + returned value, data + length) will
-  // be WebSocket frame data after handshake response message.
-  // TODO(ukai): fail fast when response gives wrong status code.
-  size_t ParseRawResponse(const char* data, int length);
-  // Returns true if it already parses full handshake response message.
-  bool HasResponse() const;
-  // Parses WebSocket handshake response info given as HttpResponseInfo.
-  bool ParseResponseInfo(const HttpResponseInfo& response_info,
-                         const std::string& challenge);
-  // Parses WebSocket handshake response as SpdyHeaderBlock.
-  bool ParseResponseHeaderBlock(const SpdyHeaderBlock& headers,
-                                const std::string& challenge,
-                                int spdy_protocol_version);
-
-  // Gets the headers value.
-  void GetHeaders(const char* const headers_to_get[],
-                  size_t headers_to_get_len,
-                  std::vector<std::string>* values);
-  // Removes the headers that matches (case insensitive).
-  void RemoveHeaders(const char* const headers_to_remove[],
-                     size_t headers_to_remove_len);
-
-  // Gets raw WebSocket handshake response received from WebSocket server.
-  std::string GetRawResponse() const;
-
-  // Gets WebSocket handshake response message sent to renderer process.
-  std::string GetResponse();
-
- private:
-  // Original bytes input by using ParseRawResponse().
-  std::string original_;
-  // Number of bytes actually used for the handshake response in |original_|.
-  int original_header_length_;
-
-  std::string status_line_;
-  std::string headers_;
-  std::string header_separator_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeResponseHandler);
-};
-
 }  // namespace net
 
 #endif  // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
diff --git a/net/websockets/websocket_handshake_handler_spdy_test.cc b/net/websockets/websocket_handshake_handler_spdy_test.cc
deleted file mode 100644
index 064bdcf..0000000
--- a/net/websockets/websocket_handshake_handler_spdy_test.cc
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/websockets/websocket_handshake_handler.h"
-
-#include <string>
-
-#include "net/socket/next_proto.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_websocket_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace net {
-
-namespace {
-
-class WebSocketHandshakeHandlerSpdyTest
-    : public ::testing::Test,
-      public ::testing::WithParamInterface<NextProto> {
- protected:
-  WebSocketHandshakeHandlerSpdyTest() : spdy_util_(GetParam()) {}
-
-  SpdyWebSocketTestUtil spdy_util_;
-};
-
-INSTANTIATE_TEST_CASE_P(
-    NextProto,
-    WebSocketHandshakeHandlerSpdyTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
-
-TEST_P(WebSocketHandshakeHandlerSpdyTest, RequestResponse) {
-  WebSocketHandshakeRequestHandler request_handler;
-
-  static const char kHandshakeRequestMessage[] =
-      "GET /demo HTTP/1.1\r\n"
-      "Host: example.com\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
-      "Origin: http://example.com\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n"
-      "Sec-WebSocket-Extensions: foo\r\n"
-      "Sec-WebSocket-Version: 13\r\n"
-      "\r\n";
-
-  EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage,
-                                           strlen(kHandshakeRequestMessage)));
-
-  GURL url("ws://example.com/demo");
-  std::string challenge;
-  SpdyHeaderBlock headers;
-  ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url,
-                                                    &headers,
-                                                    &challenge,
-                                                    spdy_util_.spdy_version()));
-
-  EXPECT_EQ(url.path(), spdy_util_.GetHeader(headers, "path"));
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "upgrade").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "Upgrade").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "connection").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "Connection").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Key").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-websocket-key").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Version").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-webSocket-version").empty());
-  EXPECT_EQ("example.com", spdy_util_.GetHeader(headers, "host"));
-  EXPECT_EQ("http://example.com", spdy_util_.GetHeader(headers, "origin"));
-  EXPECT_EQ("sample", spdy_util_.GetHeader(headers, "sec-websocket-protocol"));
-  EXPECT_EQ("foo", spdy_util_.GetHeader(headers, "sec-websocket-extensions"));
-  EXPECT_EQ("ws", spdy_util_.GetHeader(headers, "scheme"));
-  EXPECT_EQ("WebSocket/13", spdy_util_.GetHeader(headers, "version"));
-
-  static const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ==";
-
-  EXPECT_EQ(expected_challenge, challenge);
-
-  headers.clear();
-
-  spdy_util_.SetHeader("status", "101 Switching Protocols", &headers);
-  spdy_util_.SetHeader("sec-websocket-protocol", "sample", &headers);
-  spdy_util_.SetHeader("sec-websocket-extensions", "foo", &headers);
-
-  WebSocketHandshakeResponseHandler response_handler;
-  EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(
-      headers, challenge, spdy_util_.spdy_version()));
-  EXPECT_TRUE(response_handler.HasResponse());
-
-  // Note that order of sec-websocket-* is sensitive with hash_map order.
-  static const char kHandshakeResponseExpectedMessage[] =
-      "HTTP/1.1 101 Switching Protocols\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
-      "sec-websocket-extensions: foo\r\n"
-      "sec-websocket-protocol: sample\r\n"
-      "\r\n";
-
-  EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse());
-}
-
-TEST_P(WebSocketHandshakeHandlerSpdyTest, RequestResponseWithCookies) {
-  WebSocketHandshakeRequestHandler request_handler;
-
-  // Note that websocket won't use multiple headers in request now.
-  static const char kHandshakeRequestMessage[] =
-      "GET /demo HTTP/1.1\r\n"
-      "Host: example.com\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
-      "Origin: http://example.com\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n"
-      "Sec-WebSocket-Extensions: foo\r\n"
-      "Sec-WebSocket-Version: 13\r\n"
-      "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n"
-      "\r\n";
-
-  EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage,
-                                           strlen(kHandshakeRequestMessage)));
-
-  GURL url("ws://example.com/demo");
-  std::string challenge;
-  SpdyHeaderBlock headers;
-  ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url,
-                                                    &headers,
-                                                    &challenge,
-                                                    spdy_util_.spdy_version()));
-
-  EXPECT_EQ(url.path(), spdy_util_.GetHeader(headers, "path"));
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "upgrade").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "Upgrade").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "connection").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "Connection").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Key").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-websocket-key").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Version").empty());
-  EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-webSocket-version").empty());
-  EXPECT_EQ("example.com", spdy_util_.GetHeader(headers, "host"));
-  EXPECT_EQ("http://example.com", spdy_util_.GetHeader(headers, "origin"));
-  EXPECT_EQ("sample", spdy_util_.GetHeader(headers, "sec-websocket-protocol"));
-  EXPECT_EQ("foo", spdy_util_.GetHeader(headers, "sec-websocket-extensions"));
-  EXPECT_EQ("ws", spdy_util_.GetHeader(headers, "scheme"));
-  EXPECT_EQ("WebSocket/13", spdy_util_.GetHeader(headers, "version"));
-  EXPECT_EQ("WK-websocket-test=1; WK-websocket-test-httponly=1",
-            headers["cookie"]);
-
-  const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ==";
-
-  EXPECT_EQ(expected_challenge, challenge);
-
-  headers.clear();
-
-  spdy_util_.SetHeader("status", "101 Switching Protocols", &headers);
-  spdy_util_.SetHeader("sec-websocket-protocol", "sample", &headers);
-  spdy_util_.SetHeader("sec-websocket-extensions", "foo", &headers);
-  std::string cookie = "WK-websocket-test=1";
-  cookie.append(1, '\0');
-  cookie += "WK-websocket-test-httponly=1; HttpOnly";
-  headers["set-cookie"] = cookie;
-
-
-  WebSocketHandshakeResponseHandler response_handler;
-  EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(
-      headers, challenge, spdy_util_.spdy_version()));
-  EXPECT_TRUE(response_handler.HasResponse());
-
-  // Note that order of sec-websocket-* is sensitive with hash_map order.
-  static const char kHandshakeResponseExpectedMessage[] =
-      "HTTP/1.1 101 Switching Protocols\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
-      "sec-websocket-extensions: foo\r\n"
-      "sec-websocket-protocol: sample\r\n"
-      "set-cookie: WK-websocket-test=1\r\n"
-      "set-cookie: WK-websocket-test-httponly=1; HttpOnly\r\n"
-      "\r\n";
-
-  EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse());
-}
-
-}  // namespace
-
-}  // namespace net
diff --git a/net/websockets/websocket_handshake_handler_test.cc b/net/websockets/websocket_handshake_handler_test.cc
index e59a982..8eff571 100644
--- a/net/websockets/websocket_handshake_handler_test.cc
+++ b/net/websockets/websocket_handshake_handler_test.cc
@@ -4,238 +4,14 @@
 
 #include "net/websockets/websocket_handshake_handler.h"
 
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_util.h"
-#include "url/gurl.h"
-
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace {
-
-const char* const kCookieHeaders[] = {
-  "cookie", "cookie2"
-};
-
-const char* const kSetCookieHeaders[] = {
-  "set-cookie", "set-cookie2"
-};
-
-}  // namespace
-
 namespace net {
 
-TEST(WebSocketHandshakeRequestHandlerTest, SimpleRequest) {
-  WebSocketHandshakeRequestHandler handler;
+namespace {
 
-  static const char kHandshakeRequestMessage[] =
-      "GET /demo HTTP/1.1\r\n"
-      "Host: example.com\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
-      "Sec-WebSocket-Origin: http://example.com\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n"
-      "Sec-WebSocket-Version: 13\r\n"
-      "\r\n";
+// TODO(ricea): Put a test for ComputeSecWebSocketAccept() here.
 
-  EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage,
-                                   strlen(kHandshakeRequestMessage)));
-
-  handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
-
-  EXPECT_EQ(kHandshakeRequestMessage, handler.GetRawRequest());
-}
-
-TEST(WebSocketHandshakeRequestHandlerTest, ReplaceRequestCookies) {
-  WebSocketHandshakeRequestHandler handler;
-
-  static const char kHandshakeRequestMessage[] =
-      "GET /demo HTTP/1.1\r\n"
-      "Host: example.com\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
-      "Sec-WebSocket-Origin: http://example.com\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n"
-      "Sec-WebSocket-Version: 13\r\n"
-      "Cookie: WK-websocket-test=1\r\n"
-      "\r\n";
-
-  EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage,
-                                   strlen(kHandshakeRequestMessage)));
-
-  handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
-
-  handler.AppendHeaderIfMissing("Cookie",
-                                "WK-websocket-test=1; "
-                                "WK-websocket-test-httponly=1");
-
-  static const char kHandshakeRequestExpectedMessage[] =
-      "GET /demo HTTP/1.1\r\n"
-      "Host: example.com\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
-      "Sec-WebSocket-Origin: http://example.com\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n"
-      "Sec-WebSocket-Version: 13\r\n"
-      "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n"
-      "\r\n";
-
-  EXPECT_EQ(kHandshakeRequestExpectedMessage, handler.GetRawRequest());
-}
-
-TEST(WebSocketHandshakeResponseHandlerTest, SimpleResponse) {
-  WebSocketHandshakeResponseHandler handler;
-
-  static const char kHandshakeResponseMessage[] =
-      "HTTP/1.1 101 Switching Protocols\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n"
-      "\r\n";
-
-  EXPECT_EQ(strlen(kHandshakeResponseMessage),
-            handler.ParseRawResponse(kHandshakeResponseMessage,
-                                     strlen(kHandshakeResponseMessage)));
-  EXPECT_TRUE(handler.HasResponse());
-
-  handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
-
-  EXPECT_EQ(kHandshakeResponseMessage, handler.GetResponse());
-}
-
-TEST(WebSocketHandshakeResponseHandlerTest, ReplaceResponseCookies) {
-  WebSocketHandshakeResponseHandler handler;
-
-  static const char kHandshakeResponseMessage[] =
-      "HTTP/1.1 101 Switching Protocols\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n"
-      "Set-Cookie: WK-websocket-test-1\r\n"
-      "Set-Cookie: WK-websocket-test-httponly=1; HttpOnly\r\n"
-      "\r\n";
-
-  EXPECT_EQ(strlen(kHandshakeResponseMessage),
-            handler.ParseRawResponse(kHandshakeResponseMessage,
-                                     strlen(kHandshakeResponseMessage)));
-  EXPECT_TRUE(handler.HasResponse());
-  std::vector<std::string> cookies;
-  handler.GetHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders), &cookies);
-  ASSERT_EQ(2U, cookies.size());
-  EXPECT_EQ("WK-websocket-test-1", cookies[0]);
-  EXPECT_EQ("WK-websocket-test-httponly=1; HttpOnly", cookies[1]);
-  handler.RemoveHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders));
-
-  static const char kHandshakeResponseExpectedMessage[] =
-      "HTTP/1.1 101 Switching Protocols\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n"
-      "\r\n";
-
-  EXPECT_EQ(kHandshakeResponseExpectedMessage, handler.GetResponse());
-}
-
-TEST(WebSocketHandshakeResponseHandlerTest, BadResponse) {
-  WebSocketHandshakeResponseHandler handler;
-
-  static const char kBadMessage[] = "\n\n\r\net-Location: w";
-  EXPECT_EQ(2U, handler.ParseRawResponse(kBadMessage, strlen(kBadMessage)));
-  EXPECT_TRUE(handler.HasResponse());
-  EXPECT_EQ("\n\n", handler.GetResponse());
-}
-
-TEST(WebSocketHandshakeResponseHandlerTest, BadResponse2) {
-  WebSocketHandshakeResponseHandler handler;
-
-  static const char kBadMessage[] = "\n\r\n\r\net-Location: w";
-  EXPECT_EQ(3U, handler.ParseRawResponse(kBadMessage, strlen(kBadMessage)));
-  EXPECT_TRUE(handler.HasResponse());
-  EXPECT_EQ("\n\r\n", handler.GetResponse());
-}
-
-TEST(WebSocketHandshakeHandlerTest, HttpRequestResponse) {
-  WebSocketHandshakeRequestHandler request_handler;
-
-  static const char kHandshakeRequestMessage[] =
-      "GET /demo HTTP/1.1\r\n"
-      "Host: example.com\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
-      "Sec-WebSocket-Origin: http://example.com\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n"
-      "Sec-WebSocket-Version: 13\r\n"
-      "\r\n";
-
-  EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage,
-                                           strlen(kHandshakeRequestMessage)));
-
-  GURL url("ws://example.com/demo");
-  std::string challenge;
-  const HttpRequestInfo& request_info =
-      request_handler.GetRequestInfo(url, &challenge);
-
-  EXPECT_EQ(url, request_info.url);
-  EXPECT_EQ("GET", request_info.method);
-  EXPECT_FALSE(request_info.extra_headers.HasHeader("Upgrade"));
-  EXPECT_FALSE(request_info.extra_headers.HasHeader("Connection"));
-  EXPECT_FALSE(request_info.extra_headers.HasHeader("Sec-WebSocket-Key"));
-  std::string value;
-  EXPECT_TRUE(request_info.extra_headers.GetHeader("Host", &value));
-  EXPECT_EQ("example.com", value);
-  EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Origin",
-                                                   &value));
-  EXPECT_EQ("http://example.com", value);
-  EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Protocol",
-                                                   &value));
-  EXPECT_EQ("sample", value);
-
-  EXPECT_EQ("dGhlIHNhbXBsZSBub25jZQ==", challenge);
-
-  static const char kHandshakeResponseHeader[] =
-      "HTTP/1.1 101 Switching Protocols\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n";
-
-  std::string raw_headers =
-      HttpUtil::AssembleRawHeaders(kHandshakeResponseHeader,
-                                   strlen(kHandshakeResponseHeader));
-  HttpResponseInfo response_info;
-  response_info.headers = new HttpResponseHeaders(raw_headers);
-
-  EXPECT_TRUE(StartsWithASCII(response_info.headers->GetStatusLine(),
-                              "HTTP/1.1 101 ", false));
-  EXPECT_FALSE(response_info.headers->HasHeader("Upgrade"));
-  EXPECT_FALSE(response_info.headers->HasHeader("Connection"));
-  EXPECT_FALSE(response_info.headers->HasHeader("Sec-WebSocket-Accept"));
-  EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Protocol",
-                                                    "sample"));
-
-  WebSocketHandshakeResponseHandler response_handler;
-
-  EXPECT_TRUE(response_handler.ParseResponseInfo(response_info, challenge));
-  EXPECT_TRUE(response_handler.HasResponse());
-
-  static const char kHandshakeResponseExpectedMessage[] =
-      "HTTP/1.1 101 Switching Protocols\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
-      "Sec-WebSocket-Protocol: sample\r\n"
-      "\r\n";
-
-  EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse());
-}
+}  // namespace
 
 }  // namespace net
diff --git a/net/websockets/websocket_job.cc b/net/websockets/websocket_job.cc
deleted file mode 100644
index eb653fa..0000000
--- a/net/websockets/websocket_job.cc
+++ /dev/null
@@ -1,693 +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 "net/websockets/websocket_job.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/cookies/cookie_store.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_transaction_factory.h"
-#include "net/http/http_util.h"
-#include "net/spdy/spdy_session.h"
-#include "net/spdy/spdy_session_pool.h"
-#include "net/url_request/url_request_context.h"
-#include "net/websockets/websocket_handshake_handler.h"
-#include "net/websockets/websocket_net_log_params.h"
-#include "net/websockets/websocket_throttle.h"
-#include "url/gurl.h"
-
-static const int kMaxPendingSendAllowed = 32768;  // 32 kilobytes.
-
-namespace {
-
-// lower-case header names.
-const char* const kCookieHeaders[] = {
-  "cookie", "cookie2"
-};
-const char* const kSetCookieHeaders[] = {
-  "set-cookie", "set-cookie2"
-};
-
-net::SocketStreamJob* WebSocketJobFactory(
-    const GURL& url, net::SocketStream::Delegate* delegate,
-    net::URLRequestContext* context, net::CookieStore* cookie_store) {
-  net::WebSocketJob* job = new net::WebSocketJob(delegate);
-  job->InitSocketStream(new net::SocketStream(url, job, context, cookie_store));
-  return job;
-}
-
-class WebSocketJobInitSingleton {
- private:
-  friend struct base::DefaultLazyInstanceTraits<WebSocketJobInitSingleton>;
-  WebSocketJobInitSingleton() {
-    net::SocketStreamJob::RegisterProtocolFactory("ws", WebSocketJobFactory);
-    net::SocketStreamJob::RegisterProtocolFactory("wss", WebSocketJobFactory);
-  }
-};
-
-static base::LazyInstance<WebSocketJobInitSingleton> g_websocket_job_init =
-    LAZY_INSTANCE_INITIALIZER;
-
-}  // anonymous namespace
-
-namespace net {
-
-// static
-void WebSocketJob::EnsureInit() {
-  g_websocket_job_init.Get();
-}
-
-WebSocketJob::WebSocketJob(SocketStream::Delegate* delegate)
-    : delegate_(delegate),
-      state_(INITIALIZED),
-      waiting_(false),
-      handshake_request_(new WebSocketHandshakeRequestHandler),
-      handshake_response_(new WebSocketHandshakeResponseHandler),
-      started_to_send_handshake_request_(false),
-      handshake_request_sent_(0),
-      response_cookies_save_index_(0),
-      spdy_protocol_version_(0),
-      save_next_cookie_running_(false),
-      callback_pending_(false),
-      weak_ptr_factory_(this),
-      weak_ptr_factory_for_send_pending_(this) {
-}
-
-WebSocketJob::~WebSocketJob() {
-  DCHECK_EQ(CLOSED, state_);
-  DCHECK(!delegate_);
-  DCHECK(!socket_.get());
-}
-
-void WebSocketJob::Connect() {
-  DCHECK(socket_.get());
-  DCHECK_EQ(state_, INITIALIZED);
-  state_ = CONNECTING;
-  socket_->Connect();
-}
-
-bool WebSocketJob::SendData(const char* data, int len) {
-  switch (state_) {
-    case INITIALIZED:
-      return false;
-
-    case CONNECTING:
-      return SendHandshakeRequest(data, len);
-
-    case OPEN:
-      {
-        scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(len);
-        memcpy(buffer->data(), data, len);
-        if (current_send_buffer_.get() || !send_buffer_queue_.empty()) {
-          send_buffer_queue_.push_back(buffer);
-          return true;
-        }
-        current_send_buffer_ = new DrainableIOBuffer(buffer.get(), len);
-        return SendDataInternal(current_send_buffer_->data(),
-                                current_send_buffer_->BytesRemaining());
-      }
-
-    case CLOSING:
-    case CLOSED:
-      return false;
-  }
-  return false;
-}
-
-void WebSocketJob::Close() {
-  if (state_ == CLOSED)
-    return;
-
-  state_ = CLOSING;
-  if (current_send_buffer_.get()) {
-    // Will close in SendPending.
-    return;
-  }
-  state_ = CLOSED;
-  CloseInternal();
-}
-
-void WebSocketJob::RestartWithAuth(const AuthCredentials& credentials) {
-  state_ = CONNECTING;
-  socket_->RestartWithAuth(credentials);
-}
-
-void WebSocketJob::DetachDelegate() {
-  state_ = CLOSED;
-  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
-
-  scoped_refptr<WebSocketJob> protect(this);
-  weak_ptr_factory_.InvalidateWeakPtrs();
-  weak_ptr_factory_for_send_pending_.InvalidateWeakPtrs();
-
-  delegate_ = NULL;
-  if (socket_.get())
-    socket_->DetachDelegate();
-  socket_ = NULL;
-  if (!callback_.is_null()) {
-    waiting_ = false;
-    callback_.Reset();
-    Release();  // Balanced with OnStartOpenConnection().
-  }
-}
-
-int WebSocketJob::OnStartOpenConnection(
-    SocketStream* socket, const CompletionCallback& callback) {
-  DCHECK(callback_.is_null());
-  state_ = CONNECTING;
-
-  addresses_ = socket->address_list();
-  if (!WebSocketThrottle::GetInstance()->PutInQueue(this)) {
-    return ERR_WS_THROTTLE_QUEUE_TOO_LARGE;
-  }
-
-  if (delegate_) {
-    int result = delegate_->OnStartOpenConnection(socket, callback);
-    DCHECK_EQ(OK, result);
-  }
-  if (waiting_) {
-    // PutInQueue() may set |waiting_| true for throttling. In this case,
-    // Wakeup() will be called later.
-    callback_ = callback;
-    AddRef();  // Balanced when callback_ is cleared.
-    return ERR_IO_PENDING;
-  }
-  return TrySpdyStream();
-}
-
-void WebSocketJob::OnConnected(
-    SocketStream* socket, int max_pending_send_allowed) {
-  if (state_ == CLOSED)
-    return;
-  DCHECK_EQ(CONNECTING, state_);
-  if (delegate_)
-    delegate_->OnConnected(socket, max_pending_send_allowed);
-}
-
-void WebSocketJob::OnSentData(SocketStream* socket, int amount_sent) {
-  DCHECK_NE(INITIALIZED, state_);
-  DCHECK_GT(amount_sent, 0);
-  if (state_ == CLOSED)
-    return;
-  if (state_ == CONNECTING) {
-    OnSentHandshakeRequest(socket, amount_sent);
-    return;
-  }
-  if (delegate_) {
-    DCHECK(state_ == OPEN || state_ == CLOSING);
-    if (!current_send_buffer_.get()) {
-      VLOG(1)
-          << "OnSentData current_send_buffer=NULL amount_sent=" << amount_sent;
-      return;
-    }
-    current_send_buffer_->DidConsume(amount_sent);
-    if (current_send_buffer_->BytesRemaining() > 0)
-      return;
-
-    // We need to report amount_sent of original buffer size, instead of
-    // amount sent to |socket|.
-    amount_sent = current_send_buffer_->size();
-    DCHECK_GT(amount_sent, 0);
-    current_send_buffer_ = NULL;
-    if (!weak_ptr_factory_for_send_pending_.HasWeakPtrs()) {
-      base::MessageLoopForIO::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&WebSocketJob::SendPending,
-                     weak_ptr_factory_for_send_pending_.GetWeakPtr()));
-    }
-    delegate_->OnSentData(socket, amount_sent);
-  }
-}
-
-void WebSocketJob::OnReceivedData(
-    SocketStream* socket, const char* data, int len) {
-  DCHECK_NE(INITIALIZED, state_);
-  if (state_ == CLOSED)
-    return;
-  if (state_ == CONNECTING) {
-    OnReceivedHandshakeResponse(socket, data, len);
-    return;
-  }
-  DCHECK(state_ == OPEN || state_ == CLOSING);
-  if (delegate_ && len > 0)
-    delegate_->OnReceivedData(socket, data, len);
-}
-
-void WebSocketJob::OnClose(SocketStream* socket) {
-  state_ = CLOSED;
-  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
-
-  scoped_refptr<WebSocketJob> protect(this);
-  weak_ptr_factory_.InvalidateWeakPtrs();
-
-  SocketStream::Delegate* delegate = delegate_;
-  delegate_ = NULL;
-  socket_ = NULL;
-  if (!callback_.is_null()) {
-    waiting_ = false;
-    callback_.Reset();
-    Release();  // Balanced with OnStartOpenConnection().
-  }
-  if (delegate)
-    delegate->OnClose(socket);
-}
-
-void WebSocketJob::OnAuthRequired(
-    SocketStream* socket, AuthChallengeInfo* auth_info) {
-  if (delegate_)
-    delegate_->OnAuthRequired(socket, auth_info);
-}
-
-void WebSocketJob::OnSSLCertificateError(
-    SocketStream* socket, const SSLInfo& ssl_info, bool fatal) {
-  if (delegate_)
-    delegate_->OnSSLCertificateError(socket, ssl_info, fatal);
-}
-
-void WebSocketJob::OnError(const SocketStream* socket, int error) {
-  if (delegate_ && error != ERR_PROTOCOL_SWITCHED)
-    delegate_->OnError(socket, error);
-}
-
-void WebSocketJob::OnCreatedSpdyStream(int result) {
-  DCHECK(spdy_websocket_stream_.get());
-  DCHECK(socket_.get());
-  DCHECK_NE(ERR_IO_PENDING, result);
-
-  if (state_ == CLOSED) {
-    result = ERR_ABORTED;
-  } else if (result == OK) {
-    state_ = CONNECTING;
-    result = ERR_PROTOCOL_SWITCHED;
-  } else {
-    spdy_websocket_stream_.reset();
-  }
-
-  CompleteIO(result);
-}
-
-void WebSocketJob::OnSentSpdyHeaders() {
-  DCHECK_NE(INITIALIZED, state_);
-  if (state_ != CONNECTING)
-    return;
-  size_t original_length = handshake_request_->original_length();
-  handshake_request_.reset();
-  if (delegate_)
-    delegate_->OnSentData(socket_.get(), original_length);
-}
-
-void WebSocketJob::OnSpdyResponseHeadersUpdated(
-    const SpdyHeaderBlock& response_headers) {
-  DCHECK_NE(INITIALIZED, state_);
-  if (state_ != CONNECTING)
-    return;
-  // TODO(toyoshim): Fallback to non-spdy connection?
-  handshake_response_->ParseResponseHeaderBlock(response_headers,
-                                                challenge_,
-                                                spdy_protocol_version_);
-
-  SaveCookiesAndNotifyHeadersComplete();
-}
-
-void WebSocketJob::OnSentSpdyData(size_t bytes_sent) {
-  DCHECK_NE(INITIALIZED, state_);
-  DCHECK_NE(CONNECTING, state_);
-  if (state_ == CLOSED)
-    return;
-  if (!spdy_websocket_stream_.get())
-    return;
-  OnSentData(socket_.get(), static_cast<int>(bytes_sent));
-}
-
-void WebSocketJob::OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) {
-  DCHECK_NE(INITIALIZED, state_);
-  DCHECK_NE(CONNECTING, state_);
-  if (state_ == CLOSED)
-    return;
-  if (!spdy_websocket_stream_.get())
-    return;
-  if (buffer) {
-    OnReceivedData(
-        socket_.get(), buffer->GetRemainingData(), buffer->GetRemainingSize());
-  } else {
-    OnReceivedData(socket_.get(), NULL, 0);
-  }
-}
-
-void WebSocketJob::OnCloseSpdyStream() {
-  spdy_websocket_stream_.reset();
-  OnClose(socket_.get());
-}
-
-bool WebSocketJob::SendHandshakeRequest(const char* data, int len) {
-  DCHECK_EQ(state_, CONNECTING);
-  if (started_to_send_handshake_request_)
-    return false;
-  if (!handshake_request_->ParseRequest(data, len))
-    return false;
-
-  AddCookieHeaderAndSend();
-  return true;
-}
-
-void WebSocketJob::AddCookieHeaderAndSend() {
-  bool allow = true;
-  if (delegate_ && !delegate_->CanGetCookies(socket_.get(), GetURLForCookies()))
-    allow = false;
-
-  if (socket_.get() && delegate_ && state_ == CONNECTING) {
-    handshake_request_->RemoveHeaders(kCookieHeaders,
-                                      arraysize(kCookieHeaders));
-    if (allow && socket_->cookie_store()) {
-      // Add cookies, including HttpOnly cookies.
-      CookieOptions cookie_options;
-      cookie_options.set_include_httponly();
-      socket_->cookie_store()->GetCookiesWithOptionsAsync(
-          GetURLForCookies(), cookie_options,
-          base::Bind(&WebSocketJob::LoadCookieCallback,
-                     weak_ptr_factory_.GetWeakPtr()));
-    } else {
-      DoSendData();
-    }
-  }
-}
-
-void WebSocketJob::LoadCookieCallback(const std::string& cookie) {
-  if (!cookie.empty())
-    // TODO(tyoshino): Sending cookie means that connection doesn't need
-    // PRIVACY_MODE_ENABLED as cookies may be server-bound and channel id
-    // wouldn't negatively affect privacy anyway. Need to restart connection
-    // or refactor to determine cookie status prior to connecting.
-    handshake_request_->AppendHeaderIfMissing("Cookie", cookie);
-  DoSendData();
-}
-
-void WebSocketJob::DoSendData() {
-  if (spdy_websocket_stream_.get()) {
-    scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
-    handshake_request_->GetRequestHeaderBlock(
-        socket_->url(), headers.get(), &challenge_, spdy_protocol_version_);
-    spdy_websocket_stream_->SendRequest(headers.Pass());
-  } else {
-    const std::string& handshake_request =
-        handshake_request_->GetRawRequest();
-    handshake_request_sent_ = 0;
-    socket_->net_log()->AddEvent(
-        NetLog::TYPE_WEB_SOCKET_SEND_REQUEST_HEADERS,
-        base::Bind(&NetLogWebSocketHandshakeCallback, &handshake_request));
-    socket_->SendData(handshake_request.data(),
-                      handshake_request.size());
-  }
-  // Just buffered in |handshake_request_|.
-  started_to_send_handshake_request_ = true;
-}
-
-void WebSocketJob::OnSentHandshakeRequest(
-    SocketStream* socket, int amount_sent) {
-  DCHECK_EQ(state_, CONNECTING);
-  handshake_request_sent_ += amount_sent;
-  DCHECK_LE(handshake_request_sent_, handshake_request_->raw_length());
-  if (handshake_request_sent_ >= handshake_request_->raw_length()) {
-    // handshake request has been sent.
-    // notify original size of handshake request to delegate.
-    // Reset the handshake_request_ first in case this object is deleted by the
-    // delegate.
-    size_t original_length = handshake_request_->original_length();
-    handshake_request_.reset();
-    if (delegate_)
-      delegate_->OnSentData(socket, original_length);
-  }
-}
-
-void WebSocketJob::OnReceivedHandshakeResponse(
-    SocketStream* socket, const char* data, int len) {
-  DCHECK_EQ(state_, CONNECTING);
-  if (handshake_response_->HasResponse()) {
-    // If we already has handshake response, received data should be frame
-    // data, not handshake message.
-    received_data_after_handshake_.insert(
-        received_data_after_handshake_.end(), data, data + len);
-    return;
-  }
-
-  size_t response_length = handshake_response_->ParseRawResponse(data, len);
-  if (!handshake_response_->HasResponse()) {
-    // not yet. we need more data.
-    return;
-  }
-  // handshake message is completed.
-  std::string raw_response = handshake_response_->GetRawResponse();
-  socket_->net_log()->AddEvent(
-      NetLog::TYPE_WEB_SOCKET_READ_RESPONSE_HEADERS,
-      base::Bind(&NetLogWebSocketHandshakeCallback, &raw_response));
-  if (len - response_length > 0) {
-    // If we received extra data, it should be frame data.
-    DCHECK(received_data_after_handshake_.empty());
-    received_data_after_handshake_.assign(data + response_length, data + len);
-  }
-  SaveCookiesAndNotifyHeadersComplete();
-}
-
-void WebSocketJob::SaveCookiesAndNotifyHeadersComplete() {
-  // handshake message is completed.
-  DCHECK(handshake_response_->HasResponse());
-
-  // Extract cookies from the handshake response into a temporary vector.
-  response_cookies_.clear();
-  response_cookies_save_index_ = 0;
-
-  handshake_response_->GetHeaders(
-      kSetCookieHeaders, arraysize(kSetCookieHeaders), &response_cookies_);
-
-  // Now, loop over the response cookies, and attempt to persist each.
-  SaveNextCookie();
-}
-
-void WebSocketJob::NotifyHeadersComplete() {
-  // Remove cookie headers, with malformed headers preserved.
-  // Actual handshake should be done in Blink.
-  handshake_response_->RemoveHeaders(
-      kSetCookieHeaders, arraysize(kSetCookieHeaders));
-  std::string handshake_response = handshake_response_->GetResponse();
-  handshake_response_.reset();
-  std::vector<char> received_data(handshake_response.begin(),
-                                  handshake_response.end());
-  received_data.insert(received_data.end(),
-                       received_data_after_handshake_.begin(),
-                       received_data_after_handshake_.end());
-  received_data_after_handshake_.clear();
-
-  state_ = OPEN;
-
-  DCHECK(!received_data.empty());
-  if (delegate_)
-    delegate_->OnReceivedData(
-        socket_.get(), &received_data.front(), received_data.size());
-
-  WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
-}
-
-void WebSocketJob::SaveNextCookie() {
-  if (!socket_.get() || !delegate_ || state_ != CONNECTING)
-    return;
-
-  callback_pending_ = false;
-  save_next_cookie_running_ = true;
-
-  if (socket_->cookie_store()) {
-    GURL url_for_cookies = GetURLForCookies();
-
-    CookieOptions options;
-    options.set_include_httponly();
-
-    // Loop as long as SetCookieWithOptionsAsync completes synchronously. Since
-    // CookieMonster's asynchronous operation APIs queue the callback to run it
-    // on the thread where the API was called, there won't be race. I.e. unless
-    // the callback is run synchronously, it won't be run in parallel with this
-    // method.
-    while (!callback_pending_ &&
-           response_cookies_save_index_ < response_cookies_.size()) {
-      std::string cookie = response_cookies_[response_cookies_save_index_];
-      response_cookies_save_index_++;
-
-      if (!delegate_->CanSetCookie(
-              socket_.get(), url_for_cookies, cookie, &options))
-        continue;
-
-      callback_pending_ = true;
-      socket_->cookie_store()->SetCookieWithOptionsAsync(
-          url_for_cookies, cookie, options,
-          base::Bind(&WebSocketJob::OnCookieSaved,
-                     weak_ptr_factory_.GetWeakPtr()));
-    }
-  }
-
-  save_next_cookie_running_ = false;
-
-  if (callback_pending_)
-    return;
-
-  response_cookies_.clear();
-  response_cookies_save_index_ = 0;
-
-  NotifyHeadersComplete();
-}
-
-void WebSocketJob::OnCookieSaved(bool cookie_status) {
-  // Tell the caller of SetCookieWithOptionsAsync() that this completion
-  // callback is invoked.
-  // - If the caller checks callback_pending earlier than this callback, the
-  //   caller exits to let this method continue iteration.
-  // - Otherwise, the caller continues iteration.
-  callback_pending_ = false;
-
-  // Resume SaveNextCookie if the caller of SetCookieWithOptionsAsync() exited
-  // the loop. Otherwise, return.
-  if (save_next_cookie_running_)
-    return;
-
-  SaveNextCookie();
-}
-
-GURL WebSocketJob::GetURLForCookies() const {
-  GURL url = socket_->url();
-  std::string scheme = socket_->is_secure() ? "https" : "http";
-  url::Replacements<char> replacements;
-  replacements.SetScheme(scheme.c_str(), url::Component(0, scheme.length()));
-  return url.ReplaceComponents(replacements);
-}
-
-const AddressList& WebSocketJob::address_list() const {
-  return addresses_;
-}
-
-int WebSocketJob::TrySpdyStream() {
-  if (!socket_.get())
-    return ERR_FAILED;
-
-  // Check if we have a SPDY session available.
-  HttpTransactionFactory* factory =
-      socket_->context()->http_transaction_factory();
-  if (!factory)
-    return OK;
-  scoped_refptr<HttpNetworkSession> session = factory->GetSession();
-  if (!session.get() || !session->params().enable_websocket_over_spdy)
-    return OK;
-  SpdySessionPool* spdy_pool = session->spdy_session_pool();
-  PrivacyMode privacy_mode = socket_->privacy_mode();
-  const SpdySessionKey key(HostPortPair::FromURL(socket_->url()),
-                           socket_->proxy_server(), privacy_mode);
-  // Forbid wss downgrade to SPDY without SSL.
-  // TODO(toyoshim): Does it realize the same policy with HTTP?
-  base::WeakPtr<SpdySession> spdy_session =
-      spdy_pool->FindAvailableSession(key, *socket_->net_log());
-  if (!spdy_session)
-    return OK;
-
-  SSLInfo ssl_info;
-  bool was_npn_negotiated;
-  NextProto protocol_negotiated = kProtoUnknown;
-  bool use_ssl = spdy_session->GetSSLInfo(
-      &ssl_info, &was_npn_negotiated, &protocol_negotiated);
-  if (socket_->is_secure() && !use_ssl)
-    return OK;
-
-  // Create SpdyWebSocketStream.
-  spdy_protocol_version_ = spdy_session->GetProtocolVersion();
-  spdy_websocket_stream_.reset(new SpdyWebSocketStream(spdy_session, this));
-
-  int result = spdy_websocket_stream_->InitializeStream(
-      socket_->url(), MEDIUM, *socket_->net_log());
-  if (result == OK) {
-    OnConnected(socket_.get(), kMaxPendingSendAllowed);
-    return ERR_PROTOCOL_SWITCHED;
-  }
-  if (result != ERR_IO_PENDING) {
-    spdy_websocket_stream_.reset();
-    return OK;
-  }
-
-  return ERR_IO_PENDING;
-}
-
-void WebSocketJob::SetWaiting() {
-  waiting_ = true;
-}
-
-bool WebSocketJob::IsWaiting() const {
-  return waiting_;
-}
-
-void WebSocketJob::Wakeup() {
-  if (!waiting_)
-    return;
-  waiting_ = false;
-  DCHECK(!callback_.is_null());
-  base::MessageLoopForIO::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&WebSocketJob::RetryPendingIO,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void WebSocketJob::RetryPendingIO() {
-  int result = TrySpdyStream();
-
-  // In the case of ERR_IO_PENDING, CompleteIO() will be called from
-  // OnCreatedSpdyStream().
-  if (result != ERR_IO_PENDING)
-    CompleteIO(result);
-}
-
-void WebSocketJob::CompleteIO(int result) {
-  // |callback_| may be null if OnClose() or DetachDelegate() was called.
-  if (!callback_.is_null()) {
-    CompletionCallback callback = callback_;
-    callback_.Reset();
-    callback.Run(result);
-    Release();  // Balanced with OnStartOpenConnection().
-  }
-}
-
-bool WebSocketJob::SendDataInternal(const char* data, int length) {
-  if (spdy_websocket_stream_.get())
-    return ERR_IO_PENDING == spdy_websocket_stream_->SendData(data, length);
-  if (socket_.get())
-    return socket_->SendData(data, length);
-  return false;
-}
-
-void WebSocketJob::CloseInternal() {
-  if (spdy_websocket_stream_.get())
-    spdy_websocket_stream_->Close();
-  if (socket_.get())
-    socket_->Close();
-}
-
-void WebSocketJob::SendPending() {
-  if (current_send_buffer_.get())
-    return;
-
-  // Current buffer has been sent. Try next if any.
-  if (send_buffer_queue_.empty()) {
-    // No more data to send.
-    if (state_ == CLOSING)
-      CloseInternal();
-    return;
-  }
-
-  scoped_refptr<IOBufferWithSize> next_buffer = send_buffer_queue_.front();
-  send_buffer_queue_.pop_front();
-  current_send_buffer_ =
-      new DrainableIOBuffer(next_buffer.get(), next_buffer->size());
-  SendDataInternal(current_send_buffer_->data(),
-                   current_send_buffer_->BytesRemaining());
-}
-
-}  // namespace net
diff --git a/net/websockets/websocket_job.h b/net/websockets/websocket_job.h
deleted file mode 100644
index bad06cf..0000000
--- a/net/websockets/websocket_job.h
+++ /dev/null
@@ -1,154 +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 NET_WEBSOCKETS_WEBSOCKET_JOB_H_
-#define NET_WEBSOCKETS_WEBSOCKET_JOB_H_
-
-#include <deque>
-#include <string>
-#include <vector>
-
-#include "base/memory/weak_ptr.h"
-#include "net/base/address_list.h"
-#include "net/base/completion_callback.h"
-#include "net/socket_stream/socket_stream_job.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_websocket_stream.h"
-
-class GURL;
-
-namespace net {
-
-class DrainableIOBuffer;
-class SSLInfo;
-class WebSocketHandshakeRequestHandler;
-class WebSocketHandshakeResponseHandler;
-
-// WebSocket protocol specific job on SocketStream.
-// It captures WebSocket handshake message and handles cookie operations.
-// Chrome security policy doesn't allow renderer process (except dev tools)
-// see HttpOnly cookies, so it injects cookie header in handshake request and
-// strips set-cookie headers in handshake response.
-// TODO(ukai): refactor websocket.cc to use this.
-class NET_EXPORT WebSocketJob
-    : public SocketStreamJob,
-      public SocketStream::Delegate,
-      public SpdyWebSocketStream::Delegate {
- public:
-  // This is state of WebSocket, not SocketStream.
-  enum State {
-    INITIALIZED = -1,
-    CONNECTING = 0,
-    OPEN = 1,
-    CLOSING = 2,
-    CLOSED = 3,
-  };
-
-  explicit WebSocketJob(SocketStream::Delegate* delegate);
-
-  static void EnsureInit();
-
-  State state() const { return state_; }
-  void Connect() override;
-  bool SendData(const char* data, int len) override;
-  void Close() override;
-  void RestartWithAuth(const AuthCredentials& credentials) override;
-  void DetachDelegate() override;
-
-  // SocketStream::Delegate methods.
-  int OnStartOpenConnection(SocketStream* socket,
-                            const CompletionCallback& callback) override;
-  void OnConnected(SocketStream* socket, int max_pending_send_allowed) override;
-  void OnSentData(SocketStream* socket, int amount_sent) override;
-  void OnReceivedData(SocketStream* socket, const char* data, int len) override;
-  void OnClose(SocketStream* socket) override;
-  void OnAuthRequired(SocketStream* socket,
-                      AuthChallengeInfo* auth_info) override;
-  void OnSSLCertificateError(SocketStream* socket,
-                             const SSLInfo& ssl_info,
-                             bool fatal) override;
-  void OnError(const SocketStream* socket, int error) override;
-
-  // SpdyWebSocketStream::Delegate methods.
-  void OnCreatedSpdyStream(int status) override;
-  void OnSentSpdyHeaders() override;
-  void OnSpdyResponseHeadersUpdated(
-      const SpdyHeaderBlock& response_headers) override;
-  void OnSentSpdyData(size_t bytes_sent) override;
-  void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) override;
-  void OnCloseSpdyStream() override;
-
- private:
-  friend class WebSocketThrottle;
-  friend class WebSocketJobTest;
-  ~WebSocketJob() override;
-
-  bool SendHandshakeRequest(const char* data, int len);
-  void AddCookieHeaderAndSend();
-  void LoadCookieCallback(const std::string& cookie);
-
-  void OnSentHandshakeRequest(SocketStream* socket, int amount_sent);
-  // Parses received data into handshake_response_. When finished receiving the
-  // response, calls SaveCookiesAndNotifyHeadersComplete().
-  void OnReceivedHandshakeResponse(
-      SocketStream* socket, const char* data, int len);
-  // Saves received cookies to the cookie store, and then notifies the
-  // delegate_ of completion of handshake.
-  void SaveCookiesAndNotifyHeadersComplete();
-  void SaveNextCookie();
-  void OnCookieSaved(bool cookie_status);
-  // Clears variables for handling cookies, rebuilds handshake string excluding
-  // cookies, and then pass the handshake string to delegate_.
-  void NotifyHeadersComplete();
-  void DoSendData();
-
-  GURL GetURLForCookies() const;
-
-  const AddressList& address_list() const;
-  int TrySpdyStream();
-  void SetWaiting();
-  bool IsWaiting() const;
-  void Wakeup();
-  void RetryPendingIO();
-  void CompleteIO(int result);
-
-  bool SendDataInternal(const char* data, int length);
-  void CloseInternal();
-  void SendPending();
-
-  SocketStream::Delegate* delegate_;
-  State state_;
-  bool waiting_;
-  AddressList addresses_;
-  CompletionCallback callback_;  // for throttling.
-
-  scoped_ptr<WebSocketHandshakeRequestHandler> handshake_request_;
-  scoped_ptr<WebSocketHandshakeResponseHandler> handshake_response_;
-
-  bool started_to_send_handshake_request_;
-  size_t handshake_request_sent_;
-
-  std::vector<std::string> response_cookies_;
-  size_t response_cookies_save_index_;
-
-  std::deque<scoped_refptr<IOBufferWithSize> > send_buffer_queue_;
-  scoped_refptr<DrainableIOBuffer> current_send_buffer_;
-  std::vector<char> received_data_after_handshake_;
-
-  int spdy_protocol_version_;
-  scoped_ptr<SpdyWebSocketStream> spdy_websocket_stream_;
-  std::string challenge_;
-
-  bool save_next_cookie_running_;
-  bool callback_pending_;
-
-  base::WeakPtrFactory<WebSocketJob> weak_ptr_factory_;
-  base::WeakPtrFactory<WebSocketJob> weak_ptr_factory_for_send_pending_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebSocketJob);
-};
-
-}  // namespace
-
-#endif  // NET_WEBSOCKETS_WEBSOCKET_JOB_H_
diff --git a/net/websockets/websocket_job_test.cc b/net/websockets/websocket_job_test.cc
deleted file mode 100644
index c84af8f..0000000
--- a/net/websockets/websocket_job_test.cc
+++ /dev/null
@@ -1,1287 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/websockets/websocket_job.h"
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_errors.h"
-#include "net/base/test_completion_callback.h"
-#include "net/cookies/cookie_store.h"
-#include "net/cookies/cookie_store_test_helpers.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/http/http_transaction_factory.h"
-#include "net/http/transport_security_state.h"
-#include "net/proxy/proxy_service.h"
-#include "net/socket/next_proto.h"
-#include "net/socket/socket_test_util.h"
-#include "net/socket_stream/socket_stream.h"
-#include "net/spdy/spdy_session.h"
-#include "net/spdy/spdy_websocket_test_util.h"
-#include "net/ssl/ssl_config_service.h"
-#include "net/url_request/url_request_context.h"
-#include "net/websockets/websocket_throttle.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "url/gurl.h"
-
-namespace net {
-
-namespace {
-
-class MockSocketStream : public SocketStream {
- public:
-  MockSocketStream(const GURL& url, SocketStream::Delegate* delegate,
-                   URLRequestContext* context, CookieStore* cookie_store)
-      : SocketStream(url, delegate, context, cookie_store) {}
-
-  void Connect() override {}
-  bool SendData(const char* data, int len) override {
-    sent_data_ += std::string(data, len);
-    return true;
-  }
-
-  void Close() override {}
-  void RestartWithAuth(const AuthCredentials& credentials) override {}
-
-  void DetachDelegate() override { delegate_ = NULL; }
-
-  const std::string& sent_data() const {
-    return sent_data_;
-  }
-
- protected:
-  ~MockSocketStream() override {}
-
- private:
-  std::string sent_data_;
-};
-
-class MockSocketStreamDelegate : public SocketStream::Delegate {
- public:
-  MockSocketStreamDelegate()
-      : amount_sent_(0), allow_all_cookies_(true) {}
-  void set_allow_all_cookies(bool allow_all_cookies) {
-    allow_all_cookies_ = allow_all_cookies;
-  }
-  ~MockSocketStreamDelegate() override {}
-
-  void SetOnStartOpenConnection(const base::Closure& callback) {
-    on_start_open_connection_ = callback;
-  }
-  void SetOnConnected(const base::Closure& callback) {
-    on_connected_ = callback;
-  }
-  void SetOnSentData(const base::Closure& callback) {
-    on_sent_data_ = callback;
-  }
-  void SetOnReceivedData(const base::Closure& callback) {
-    on_received_data_ = callback;
-  }
-  void SetOnClose(const base::Closure& callback) {
-    on_close_ = callback;
-  }
-
-  int OnStartOpenConnection(SocketStream* socket,
-                            const CompletionCallback& callback) override {
-    if (!on_start_open_connection_.is_null())
-      on_start_open_connection_.Run();
-    return OK;
-  }
-  void OnConnected(SocketStream* socket,
-                   int max_pending_send_allowed) override {
-    if (!on_connected_.is_null())
-      on_connected_.Run();
-  }
-  void OnSentData(SocketStream* socket, int amount_sent) override {
-    amount_sent_ += amount_sent;
-    if (!on_sent_data_.is_null())
-      on_sent_data_.Run();
-  }
-  void OnReceivedData(SocketStream* socket,
-                      const char* data,
-                      int len) override {
-    received_data_ += std::string(data, len);
-    if (!on_received_data_.is_null())
-      on_received_data_.Run();
-  }
-  void OnClose(SocketStream* socket) override {
-    if (!on_close_.is_null())
-      on_close_.Run();
-  }
-  bool CanGetCookies(SocketStream* socket, const GURL& url) override {
-    return allow_all_cookies_;
-  }
-  bool CanSetCookie(SocketStream* request,
-                    const GURL& url,
-                    const std::string& cookie_line,
-                    CookieOptions* options) override {
-    return allow_all_cookies_;
-  }
-
-  size_t amount_sent() const { return amount_sent_; }
-  const std::string& received_data() const { return received_data_; }
-
- private:
-  int amount_sent_;
-  bool allow_all_cookies_;
-  std::string received_data_;
-  base::Closure on_start_open_connection_;
-  base::Closure on_connected_;
-  base::Closure on_sent_data_;
-  base::Closure on_received_data_;
-  base::Closure on_close_;
-};
-
-class MockCookieStore : public CookieStore {
- public:
-  struct Entry {
-    GURL url;
-    std::string cookie_line;
-    CookieOptions options;
-  };
-
-  MockCookieStore() {}
-
-  bool SetCookieWithOptions(const GURL& url,
-                            const std::string& cookie_line,
-                            const CookieOptions& options) {
-    Entry entry;
-    entry.url = url;
-    entry.cookie_line = cookie_line;
-    entry.options = options;
-    entries_.push_back(entry);
-    return true;
-  }
-
-  std::string GetCookiesWithOptions(const GURL& url,
-                                    const CookieOptions& options) {
-    std::string result;
-    for (size_t i = 0; i < entries_.size(); i++) {
-      Entry& entry = entries_[i];
-      if (url == entry.url) {
-        if (!result.empty()) {
-          result += "; ";
-        }
-        result += entry.cookie_line;
-      }
-    }
-    return result;
-  }
-
-  // CookieStore:
-  void SetCookieWithOptionsAsync(const GURL& url,
-                                 const std::string& cookie_line,
-                                 const CookieOptions& options,
-                                 const SetCookiesCallback& callback) override {
-    bool result = SetCookieWithOptions(url, cookie_line, options);
-    if (!callback.is_null())
-      callback.Run(result);
-  }
-
-  void GetCookiesWithOptionsAsync(const GURL& url,
-                                  const CookieOptions& options,
-                                  const GetCookiesCallback& callback) override {
-    if (!callback.is_null())
-      callback.Run(GetCookiesWithOptions(url, options));
-  }
-
-  void GetAllCookiesForURLAsync(
-      const GURL& url,
-      const GetCookieListCallback& callback) override {
-    ADD_FAILURE();
-  }
-
-  void DeleteCookieAsync(const GURL& url,
-                         const std::string& cookie_name,
-                         const base::Closure& callback) override {
-    ADD_FAILURE();
-  }
-
-  void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
-                                    const base::Time& delete_end,
-                                    const DeleteCallback& callback) override {
-    ADD_FAILURE();
-  }
-
-  void DeleteAllCreatedBetweenForHostAsync(
-      const base::Time delete_begin,
-      const base::Time delete_end,
-      const GURL& url,
-      const DeleteCallback& callback) override {
-    ADD_FAILURE();
-  }
-
-  void DeleteSessionCookiesAsync(const DeleteCallback&) override {
-    ADD_FAILURE();
-  }
-
-  CookieMonster* GetCookieMonster() override { return NULL; }
-
-  scoped_ptr<CookieStore::CookieChangedSubscription>
-  AddCallbackForCookie(const GURL& url, const std::string& name,
-                       const CookieChangedCallback& callback) override {
-    ADD_FAILURE();
-    return scoped_ptr<CookieChangedSubscription>();
-  }
-
-  const std::vector<Entry>& entries() const { return entries_; }
-
- private:
-  friend class base::RefCountedThreadSafe<MockCookieStore>;
-  ~MockCookieStore() override {}
-
-  std::vector<Entry> entries_;
-};
-
-class MockSSLConfigService : public SSLConfigService {
- public:
-  void GetSSLConfig(SSLConfig* config) override {}
-
- protected:
-  ~MockSSLConfigService() override {}
-};
-
-class MockURLRequestContext : public URLRequestContext {
- public:
-  explicit MockURLRequestContext(CookieStore* cookie_store)
-      : transport_security_state_() {
-    set_cookie_store(cookie_store);
-    set_transport_security_state(&transport_security_state_);
-    base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
-    bool include_subdomains = false;
-    transport_security_state_.AddHSTS("upgrademe.com", expiry,
-                                      include_subdomains);
-  }
-
-  ~MockURLRequestContext() override { AssertNoURLRequests(); }
-
- private:
-  TransportSecurityState transport_security_state_;
-};
-
-class MockHttpTransactionFactory : public HttpTransactionFactory {
- public:
-  MockHttpTransactionFactory(NextProto next_proto,
-                             OrderedSocketData* data,
-                             bool enable_websocket_over_spdy) {
-    data_ = data;
-    MockConnect connect_data(SYNCHRONOUS, OK);
-    data_->set_connect_data(connect_data);
-    session_deps_.reset(new SpdySessionDependencies(next_proto));
-    session_deps_->enable_websocket_over_spdy = enable_websocket_over_spdy;
-    session_deps_->socket_factory->AddSocketDataProvider(data_);
-    http_session_ =
-        SpdySessionDependencies::SpdyCreateSession(session_deps_.get());
-    host_port_pair_.set_host("example.com");
-    host_port_pair_.set_port(80);
-    spdy_session_key_ = SpdySessionKey(host_port_pair_,
-                                            ProxyServer::Direct(),
-                                            PRIVACY_MODE_DISABLED);
-    session_ = CreateInsecureSpdySession(
-        http_session_, spdy_session_key_, BoundNetLog());
-  }
-
-  int CreateTransaction(RequestPriority priority,
-                        scoped_ptr<HttpTransaction>* trans) override {
-    NOTREACHED();
-    return ERR_UNEXPECTED;
-  }
-
-  HttpCache* GetCache() override {
-    NOTREACHED();
-    return NULL;
-  }
-
-  HttpNetworkSession* GetSession() override { return http_session_.get(); }
-
- private:
-  OrderedSocketData* data_;
-  scoped_ptr<SpdySessionDependencies> session_deps_;
-  scoped_refptr<HttpNetworkSession> http_session_;
-  base::WeakPtr<SpdySession> session_;
-  HostPortPair host_port_pair_;
-  SpdySessionKey spdy_session_key_;
-};
-
-class DeletingSocketStreamDelegate : public SocketStream::Delegate {
- public:
-  DeletingSocketStreamDelegate()
-      : delete_next_(false) {}
-
-  // Since this class needs to be able to delete |job_|, it must be the only
-  // reference holder (except for temporary references). Provide access to the
-  // pointer for tests to use.
-  WebSocketJob* job() { return job_.get(); }
-
-  void set_job(WebSocketJob* job) { job_ = job; }
-
-  // After calling this, the next call to a method on this delegate will delete
-  // the WebSocketJob object.
-  void set_delete_next(bool delete_next) { delete_next_ = delete_next; }
-
-  void DeleteJobMaybe() {
-    if (delete_next_) {
-      job_->DetachContext();
-      job_->DetachDelegate();
-      job_ = NULL;
-    }
-  }
-
-  // SocketStream::Delegate implementation
-
-  // OnStartOpenConnection() is not implemented by SocketStreamDispatcherHost
-
-  void OnConnected(SocketStream* socket,
-                   int max_pending_send_allowed) override {
-    DeleteJobMaybe();
-  }
-
-  void OnSentData(SocketStream* socket, int amount_sent) override {
-    DeleteJobMaybe();
-  }
-
-  void OnReceivedData(SocketStream* socket,
-                      const char* data,
-                      int len) override {
-    DeleteJobMaybe();
-  }
-
-  void OnClose(SocketStream* socket) override { DeleteJobMaybe(); }
-
-  void OnAuthRequired(SocketStream* socket,
-                      AuthChallengeInfo* auth_info) override {
-    DeleteJobMaybe();
-  }
-
-  void OnSSLCertificateError(SocketStream* socket,
-                             const SSLInfo& ssl_info,
-                             bool fatal) override {
-    DeleteJobMaybe();
-  }
-
-  void OnError(const SocketStream* socket, int error) override {
-    DeleteJobMaybe();
-  }
-
-  // CanGetCookies() and CanSetCookies() do not appear to be able to delete the
-  // WebSocketJob object.
-
- private:
-  scoped_refptr<WebSocketJob> job_;
-  bool delete_next_;
-};
-
-}  // namespace
-
-class WebSocketJobTest : public PlatformTest,
-                         public ::testing::WithParamInterface<NextProto> {
- public:
-  WebSocketJobTest()
-      : spdy_util_(GetParam()),
-        enable_websocket_over_spdy_(false) {}
-
-  void SetUp() override {
-    stream_type_ = STREAM_INVALID;
-    cookie_store_ = new MockCookieStore;
-    context_.reset(new MockURLRequestContext(cookie_store_.get()));
-  }
-  void TearDown() override {
-    cookie_store_ = NULL;
-    context_.reset();
-    websocket_ = NULL;
-    socket_ = NULL;
-  }
-  void DoSendRequest() {
-    EXPECT_TRUE(websocket_->SendData(kHandshakeRequestWithoutCookie,
-                                     kHandshakeRequestWithoutCookieLength));
-  }
-  void DoSendData() {
-    if (received_data().size() == kHandshakeResponseWithoutCookieLength)
-      websocket_->SendData(kDataHello, kDataHelloLength);
-  }
-  void DoSync() {
-    sync_test_callback_.callback().Run(OK);
-  }
-  int WaitForResult() {
-    return sync_test_callback_.WaitForResult();
-  }
-
- protected:
-  enum StreamType {
-    STREAM_INVALID,
-    STREAM_MOCK_SOCKET,
-    STREAM_SOCKET,
-    STREAM_SPDY_WEBSOCKET,
-  };
-  enum ThrottlingOption {
-    THROTTLING_OFF,
-    THROTTLING_ON,
-  };
-  enum SpdyOption {
-    SPDY_OFF,
-    SPDY_ON,
-  };
-  void InitWebSocketJob(const GURL& url,
-                        MockSocketStreamDelegate* delegate,
-                        StreamType stream_type) {
-    DCHECK_NE(STREAM_INVALID, stream_type);
-    stream_type_ = stream_type;
-    websocket_ = new WebSocketJob(delegate);
-
-    if (stream_type == STREAM_MOCK_SOCKET)
-      socket_ = new MockSocketStream(url, websocket_.get(), context_.get(),
-                                     NULL);
-
-    if (stream_type == STREAM_SOCKET || stream_type == STREAM_SPDY_WEBSOCKET) {
-      if (stream_type == STREAM_SPDY_WEBSOCKET) {
-        http_factory_.reset(new MockHttpTransactionFactory(
-            GetParam(), data_.get(), enable_websocket_over_spdy_));
-        context_->set_http_transaction_factory(http_factory_.get());
-      }
-
-      ssl_config_service_ = new MockSSLConfigService();
-      context_->set_ssl_config_service(ssl_config_service_.get());
-      proxy_service_.reset(ProxyService::CreateDirect());
-      context_->set_proxy_service(proxy_service_.get());
-      host_resolver_.reset(new MockHostResolver);
-      context_->set_host_resolver(host_resolver_.get());
-
-      socket_ = new SocketStream(url, websocket_.get(), context_.get(), NULL);
-      socket_factory_.reset(new MockClientSocketFactory);
-      DCHECK(data_.get());
-      socket_factory_->AddSocketDataProvider(data_.get());
-      socket_->SetClientSocketFactory(socket_factory_.get());
-    }
-
-    websocket_->InitSocketStream(socket_.get());
-    // MockHostResolver resolves all hosts to 127.0.0.1; however, when we create
-    // a WebSocketJob purely to block another one in a throttling test, we don't
-    // perform a real connect. In that case, the following address is used
-    // instead.
-    IPAddressNumber ip;
-    ParseIPLiteralToNumber("127.0.0.1", &ip);
-    websocket_->addresses_ = AddressList::CreateFromIPAddress(ip, 80);
-  }
-  void SkipToConnecting() {
-    websocket_->state_ = WebSocketJob::CONNECTING;
-    ASSERT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(websocket_.get()));
-  }
-  WebSocketJob::State GetWebSocketJobState() {
-    return websocket_->state_;
-  }
-  void CloseWebSocketJob() {
-    if (websocket_->socket_.get()) {
-      websocket_->socket_->DetachDelegate();
-      WebSocketThrottle::GetInstance()->RemoveFromQueue(websocket_.get());
-    }
-    websocket_->state_ = WebSocketJob::CLOSED;
-    websocket_->delegate_ = NULL;
-    websocket_->socket_ = NULL;
-  }
-  SocketStream* GetSocket(SocketStreamJob* job) {
-    return job->socket_.get();
-  }
-  const std::string& sent_data() const {
-    DCHECK_EQ(STREAM_MOCK_SOCKET, stream_type_);
-    MockSocketStream* socket =
-        static_cast<MockSocketStream*>(socket_.get());
-    DCHECK(socket);
-    return socket->sent_data();
-  }
-  const std::string& received_data() const {
-    DCHECK_NE(STREAM_INVALID, stream_type_);
-    MockSocketStreamDelegate* delegate =
-        static_cast<MockSocketStreamDelegate*>(websocket_->delegate_);
-    DCHECK(delegate);
-    return delegate->received_data();
-  }
-
-  void TestSimpleHandshake();
-  void TestSlowHandshake();
-  void TestHandshakeWithCookie();
-  void TestHandshakeWithCookieButNotAllowed();
-  void TestHSTSUpgrade();
-  void TestInvalidSendData();
-  void TestConnectByWebSocket(ThrottlingOption throttling);
-  void TestConnectBySpdy(SpdyOption spdy, ThrottlingOption throttling);
-  void TestThrottlingLimit();
-
-  SpdyWebSocketTestUtil spdy_util_;
-  StreamType stream_type_;
-  scoped_refptr<MockCookieStore> cookie_store_;
-  scoped_ptr<MockURLRequestContext> context_;
-  scoped_refptr<WebSocketJob> websocket_;
-  scoped_refptr<SocketStream> socket_;
-  scoped_ptr<MockClientSocketFactory> socket_factory_;
-  scoped_ptr<OrderedSocketData> data_;
-  TestCompletionCallback sync_test_callback_;
-  scoped_refptr<MockSSLConfigService> ssl_config_service_;
-  scoped_ptr<ProxyService> proxy_service_;
-  scoped_ptr<MockHostResolver> host_resolver_;
-  scoped_ptr<MockHttpTransactionFactory> http_factory_;
-
-  // Must be set before call to enable_websocket_over_spdy, defaults to false.
-  bool enable_websocket_over_spdy_;
-
-  static const char kHandshakeRequestWithoutCookie[];
-  static const char kHandshakeRequestWithCookie[];
-  static const char kHandshakeRequestWithFilteredCookie[];
-  static const char kHandshakeResponseWithoutCookie[];
-  static const char kHandshakeResponseWithCookie[];
-  static const char kDataHello[];
-  static const char kDataWorld[];
-  static const char* const kHandshakeRequestForSpdy[];
-  static const char* const kHandshakeResponseForSpdy[];
-  static const size_t kHandshakeRequestWithoutCookieLength;
-  static const size_t kHandshakeRequestWithCookieLength;
-  static const size_t kHandshakeRequestWithFilteredCookieLength;
-  static const size_t kHandshakeResponseWithoutCookieLength;
-  static const size_t kHandshakeResponseWithCookieLength;
-  static const size_t kDataHelloLength;
-  static const size_t kDataWorldLength;
-};
-
-// Tests using this fixture verify that the WebSocketJob can handle being
-// deleted while calling back to the delegate correctly. These tests need to be
-// run under AddressSanitizer or other systems for detecting use-after-free
-// errors in order to find problems.
-class WebSocketJobDeleteTest : public ::testing::Test {
- protected:
-  WebSocketJobDeleteTest()
-      : delegate_(new DeletingSocketStreamDelegate),
-        cookie_store_(new MockCookieStore),
-        context_(new MockURLRequestContext(cookie_store_.get())) {
-    WebSocketJob* websocket = new WebSocketJob(delegate_.get());
-    delegate_->set_job(websocket);
-
-    socket_ = new MockSocketStream(
-        GURL("ws://127.0.0.1/"), websocket, context_.get(), NULL);
-
-    websocket->InitSocketStream(socket_.get());
-  }
-
-  void SetDeleteNext() { return delegate_->set_delete_next(true); }
-  WebSocketJob* job() { return delegate_->job(); }
-
-  scoped_ptr<DeletingSocketStreamDelegate> delegate_;
-  scoped_refptr<MockCookieStore> cookie_store_;
-  scoped_ptr<MockURLRequestContext> context_;
-  scoped_refptr<SocketStream> socket_;
-};
-
-const char WebSocketJobTest::kHandshakeRequestWithoutCookie[] =
-    "GET /demo HTTP/1.1\r\n"
-    "Host: example.com\r\n"
-    "Upgrade: WebSocket\r\n"
-    "Connection: Upgrade\r\n"
-    "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
-    "Origin: http://example.com\r\n"
-    "Sec-WebSocket-Protocol: sample\r\n"
-    "Sec-WebSocket-Version: 13\r\n"
-    "\r\n";
-
-const char WebSocketJobTest::kHandshakeRequestWithCookie[] =
-    "GET /demo HTTP/1.1\r\n"
-    "Host: example.com\r\n"
-    "Upgrade: WebSocket\r\n"
-    "Connection: Upgrade\r\n"
-    "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
-    "Origin: http://example.com\r\n"
-    "Sec-WebSocket-Protocol: sample\r\n"
-    "Sec-WebSocket-Version: 13\r\n"
-    "Cookie: WK-test=1\r\n"
-    "\r\n";
-
-const char WebSocketJobTest::kHandshakeRequestWithFilteredCookie[] =
-    "GET /demo HTTP/1.1\r\n"
-    "Host: example.com\r\n"
-    "Upgrade: WebSocket\r\n"
-    "Connection: Upgrade\r\n"
-    "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
-    "Origin: http://example.com\r\n"
-    "Sec-WebSocket-Protocol: sample\r\n"
-    "Sec-WebSocket-Version: 13\r\n"
-    "Cookie: CR-test=1; CR-test-httponly=1\r\n"
-    "\r\n";
-
-const char WebSocketJobTest::kHandshakeResponseWithoutCookie[] =
-    "HTTP/1.1 101 Switching Protocols\r\n"
-    "Upgrade: websocket\r\n"
-    "Connection: Upgrade\r\n"
-    "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
-    "Sec-WebSocket-Protocol: sample\r\n"
-    "\r\n";
-
-const char WebSocketJobTest::kHandshakeResponseWithCookie[] =
-    "HTTP/1.1 101 Switching Protocols\r\n"
-    "Upgrade: websocket\r\n"
-    "Connection: Upgrade\r\n"
-    "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
-    "Sec-WebSocket-Protocol: sample\r\n"
-    "Set-Cookie: CR-set-test=1\r\n"
-    "\r\n";
-
-const char WebSocketJobTest::kDataHello[] = "Hello, ";
-
-const char WebSocketJobTest::kDataWorld[] = "World!\n";
-
-const size_t WebSocketJobTest::kHandshakeRequestWithoutCookieLength =
-    arraysize(kHandshakeRequestWithoutCookie) - 1;
-const size_t WebSocketJobTest::kHandshakeRequestWithCookieLength =
-    arraysize(kHandshakeRequestWithCookie) - 1;
-const size_t WebSocketJobTest::kHandshakeRequestWithFilteredCookieLength =
-    arraysize(kHandshakeRequestWithFilteredCookie) - 1;
-const size_t WebSocketJobTest::kHandshakeResponseWithoutCookieLength =
-    arraysize(kHandshakeResponseWithoutCookie) - 1;
-const size_t WebSocketJobTest::kHandshakeResponseWithCookieLength =
-    arraysize(kHandshakeResponseWithCookie) - 1;
-const size_t WebSocketJobTest::kDataHelloLength =
-    arraysize(kDataHello) - 1;
-const size_t WebSocketJobTest::kDataWorldLength =
-    arraysize(kDataWorld) - 1;
-
-void WebSocketJobTest::TestSimpleHandshake() {
-  GURL url("ws://example.com/demo");
-  MockSocketStreamDelegate delegate;
-  InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
-  SkipToConnecting();
-
-  DoSendRequest();
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
-  EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
-  websocket_->OnSentData(socket_.get(),
-                         kHandshakeRequestWithoutCookieLength);
-  EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
-
-  websocket_->OnReceivedData(socket_.get(),
-                             kHandshakeResponseWithoutCookie,
-                             kHandshakeResponseWithoutCookieLength);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
-  EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
-  CloseWebSocketJob();
-}
-
-void WebSocketJobTest::TestSlowHandshake() {
-  GURL url("ws://example.com/demo");
-  MockSocketStreamDelegate delegate;
-  InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
-  SkipToConnecting();
-
-  DoSendRequest();
-  // We assume request is sent in one data chunk (from WebKit)
-  // We don't support streaming request.
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
-  EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
-  websocket_->OnSentData(socket_.get(),
-                         kHandshakeRequestWithoutCookieLength);
-  EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
-
-  std::vector<std::string> lines;
-  base::SplitString(kHandshakeResponseWithoutCookie, '\n', &lines);
-  for (size_t i = 0; i < lines.size() - 2; i++) {
-    std::string line = lines[i] + "\r\n";
-    SCOPED_TRACE("Line: " + line);
-    websocket_->OnReceivedData(socket_.get(), line.c_str(), line.size());
-    base::MessageLoop::current()->RunUntilIdle();
-    EXPECT_TRUE(delegate.received_data().empty());
-    EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
-  }
-  websocket_->OnReceivedData(socket_.get(), "\r\n", 2);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_FALSE(delegate.received_data().empty());
-  EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
-  EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
-  CloseWebSocketJob();
-}
-
-INSTANTIATE_TEST_CASE_P(
-    NextProto,
-    WebSocketJobTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
-
-TEST_P(WebSocketJobTest, DelayedCookies) {
-  enable_websocket_over_spdy_ = true;
-  GURL url("ws://example.com/demo");
-  GURL cookieUrl("http://example.com/demo");
-  CookieOptions cookie_options;
-  scoped_refptr<DelayedCookieMonster> cookie_store = new DelayedCookieMonster();
-  context_->set_cookie_store(cookie_store.get());
-  cookie_store->SetCookieWithOptionsAsync(cookieUrl,
-                                          "CR-test=1",
-                                          cookie_options,
-                                          CookieMonster::SetCookiesCallback());
-  cookie_options.set_include_httponly();
-  cookie_store->SetCookieWithOptionsAsync(
-      cookieUrl, "CR-test-httponly=1", cookie_options,
-      CookieMonster::SetCookiesCallback());
-
-  MockSocketStreamDelegate delegate;
-  InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
-  SkipToConnecting();
-
-  bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
-                                   kHandshakeRequestWithCookieLength);
-  EXPECT_TRUE(sent);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data());
-  EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
-  websocket_->OnSentData(socket_.get(),
-                         kHandshakeRequestWithFilteredCookieLength);
-  EXPECT_EQ(kHandshakeRequestWithCookieLength,
-            delegate.amount_sent());
-
-  websocket_->OnReceivedData(socket_.get(),
-                             kHandshakeResponseWithCookie,
-                             kHandshakeResponseWithCookieLength);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
-  EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
-
-  CloseWebSocketJob();
-}
-
-void WebSocketJobTest::TestHandshakeWithCookie() {
-  GURL url("ws://example.com/demo");
-  GURL cookieUrl("http://example.com/demo");
-  CookieOptions cookie_options;
-  cookie_store_->SetCookieWithOptions(
-      cookieUrl, "CR-test=1", cookie_options);
-  cookie_options.set_include_httponly();
-  cookie_store_->SetCookieWithOptions(
-      cookieUrl, "CR-test-httponly=1", cookie_options);
-
-  MockSocketStreamDelegate delegate;
-  InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
-  SkipToConnecting();
-
-  bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
-                                   kHandshakeRequestWithCookieLength);
-  EXPECT_TRUE(sent);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data());
-  EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
-  websocket_->OnSentData(socket_.get(),
-                         kHandshakeRequestWithFilteredCookieLength);
-  EXPECT_EQ(kHandshakeRequestWithCookieLength,
-            delegate.amount_sent());
-
-  websocket_->OnReceivedData(socket_.get(),
-                             kHandshakeResponseWithCookie,
-                             kHandshakeResponseWithCookieLength);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
-  EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
-
-  EXPECT_EQ(3U, cookie_store_->entries().size());
-  EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url);
-  EXPECT_EQ("CR-test=1", cookie_store_->entries()[0].cookie_line);
-  EXPECT_EQ(cookieUrl, cookie_store_->entries()[1].url);
-  EXPECT_EQ("CR-test-httponly=1", cookie_store_->entries()[1].cookie_line);
-  EXPECT_EQ(cookieUrl, cookie_store_->entries()[2].url);
-  EXPECT_EQ("CR-set-test=1", cookie_store_->entries()[2].cookie_line);
-
-  CloseWebSocketJob();
-}
-
-void WebSocketJobTest::TestHandshakeWithCookieButNotAllowed() {
-  GURL url("ws://example.com/demo");
-  GURL cookieUrl("http://example.com/demo");
-  CookieOptions cookie_options;
-  cookie_store_->SetCookieWithOptions(
-      cookieUrl, "CR-test=1", cookie_options);
-  cookie_options.set_include_httponly();
-  cookie_store_->SetCookieWithOptions(
-      cookieUrl, "CR-test-httponly=1", cookie_options);
-
-  MockSocketStreamDelegate delegate;
-  delegate.set_allow_all_cookies(false);
-  InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
-  SkipToConnecting();
-
-  bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
-                                   kHandshakeRequestWithCookieLength);
-  EXPECT_TRUE(sent);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
-  EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
-  websocket_->OnSentData(socket_.get(), kHandshakeRequestWithoutCookieLength);
-  EXPECT_EQ(kHandshakeRequestWithCookieLength, delegate.amount_sent());
-
-  websocket_->OnReceivedData(socket_.get(),
-                             kHandshakeResponseWithCookie,
-                             kHandshakeResponseWithCookieLength);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
-  EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
-
-  EXPECT_EQ(2U, cookie_store_->entries().size());
-  EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url);
-  EXPECT_EQ("CR-test=1", cookie_store_->entries()[0].cookie_line);
-  EXPECT_EQ(cookieUrl, cookie_store_->entries()[1].url);
-  EXPECT_EQ("CR-test-httponly=1", cookie_store_->entries()[1].cookie_line);
-
-  CloseWebSocketJob();
-}
-
-void WebSocketJobTest::TestHSTSUpgrade() {
-  GURL url("ws://upgrademe.com/");
-  MockSocketStreamDelegate delegate;
-  scoped_refptr<SocketStreamJob> job =
-      SocketStreamJob::CreateSocketStreamJob(
-          url, &delegate, context_->transport_security_state(),
-          context_->ssl_config_service(), NULL, NULL);
-  EXPECT_TRUE(GetSocket(job.get())->is_secure());
-  job->DetachDelegate();
-
-  url = GURL("ws://donotupgrademe.com/");
-  job = SocketStreamJob::CreateSocketStreamJob(
-      url, &delegate, context_->transport_security_state(),
-      context_->ssl_config_service(), NULL, NULL);
-  EXPECT_FALSE(GetSocket(job.get())->is_secure());
-  job->DetachDelegate();
-}
-
-void WebSocketJobTest::TestInvalidSendData() {
-  GURL url("ws://example.com/demo");
-  MockSocketStreamDelegate delegate;
-  InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
-  SkipToConnecting();
-
-  DoSendRequest();
-  // We assume request is sent in one data chunk (from WebKit)
-  // We don't support streaming request.
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
-  EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
-  websocket_->OnSentData(socket_.get(),
-                         kHandshakeRequestWithoutCookieLength);
-  EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
-
-  // We could not send any data until connection is established.
-  bool sent = websocket_->SendData(kHandshakeRequestWithoutCookie,
-                                   kHandshakeRequestWithoutCookieLength);
-  EXPECT_FALSE(sent);
-  EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
-  CloseWebSocketJob();
-}
-
-// Following tests verify cooperation between WebSocketJob and SocketStream.
-// Other former tests use MockSocketStream as SocketStream, so we could not
-// check SocketStream behavior.
-// OrderedSocketData provide socket level verifiation by checking out-going
-// packets in comparison with the MockWrite array and emulating in-coming
-// packets with MockRead array.
-
-void WebSocketJobTest::TestConnectByWebSocket(
-    ThrottlingOption throttling) {
-  // This is a test for verifying cooperation between WebSocketJob and
-  // SocketStream. If |throttling| was |THROTTLING_OFF|, it test basic
-  // situation. If |throttling| was |THROTTLING_ON|, throttling limits the
-  // latter connection.
-  MockWrite writes[] = {
-    MockWrite(ASYNC,
-              kHandshakeRequestWithoutCookie,
-              kHandshakeRequestWithoutCookieLength,
-              1),
-    MockWrite(ASYNC,
-              kDataHello,
-              kDataHelloLength,
-              3)
-  };
-  MockRead reads[] = {
-    MockRead(ASYNC,
-             kHandshakeResponseWithoutCookie,
-             kHandshakeResponseWithoutCookieLength,
-             2),
-    MockRead(ASYNC,
-             kDataWorld,
-             kDataWorldLength,
-             4),
-    MockRead(SYNCHRONOUS, 0, 5)  // EOF
-  };
-  data_.reset(new OrderedSocketData(
-      reads, arraysize(reads), writes, arraysize(writes)));
-
-  GURL url("ws://example.com/demo");
-  MockSocketStreamDelegate delegate;
-  WebSocketJobTest* test = this;
-  if (throttling == THROTTLING_ON)
-    delegate.SetOnStartOpenConnection(
-        base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
-  delegate.SetOnConnected(
-      base::Bind(&WebSocketJobTest::DoSendRequest,
-                 base::Unretained(test)));
-  delegate.SetOnReceivedData(
-      base::Bind(&WebSocketJobTest::DoSendData, base::Unretained(test)));
-  delegate.SetOnClose(
-      base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
-  InitWebSocketJob(url, &delegate, STREAM_SOCKET);
-
-  scoped_refptr<WebSocketJob> block_websocket;
-  if (throttling == THROTTLING_ON) {
-    // Create former WebSocket object which obstructs the latter one.
-    block_websocket = new WebSocketJob(NULL);
-    block_websocket->addresses_ = AddressList(websocket_->address_list());
-    ASSERT_TRUE(
-        WebSocketThrottle::GetInstance()->PutInQueue(block_websocket.get()));
-  }
-
-  websocket_->Connect();
-
-  if (throttling == THROTTLING_ON) {
-    EXPECT_EQ(OK, WaitForResult());
-    EXPECT_TRUE(websocket_->IsWaiting());
-
-    // Remove the former WebSocket object from throttling queue to unblock the
-    // latter.
-    block_websocket->state_ = WebSocketJob::CLOSED;
-    WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket.get());
-    block_websocket = NULL;
-  }
-
-  EXPECT_EQ(OK, WaitForResult());
-  EXPECT_TRUE(data_->at_read_eof());
-  EXPECT_TRUE(data_->at_write_eof());
-  EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState());
-}
-
-void WebSocketJobTest::TestConnectBySpdy(
-    SpdyOption spdy, ThrottlingOption throttling) {
-  // This is a test for verifying cooperation between WebSocketJob and
-  // SocketStream in the situation we have SPDY session to the server. If
-  // |throttling| was |THROTTLING_ON|, throttling limits the latter connection.
-  // If you enabled spdy, you should specify |spdy| as |SPDY_ON|. Expected
-  // results depend on its configuration.
-  MockWrite writes_websocket[] = {
-    MockWrite(ASYNC,
-              kHandshakeRequestWithoutCookie,
-              kHandshakeRequestWithoutCookieLength,
-              1),
-    MockWrite(ASYNC,
-              kDataHello,
-              kDataHelloLength,
-              3)
-  };
-  MockRead reads_websocket[] = {
-    MockRead(ASYNC,
-             kHandshakeResponseWithoutCookie,
-             kHandshakeResponseWithoutCookieLength,
-             2),
-    MockRead(ASYNC,
-             kDataWorld,
-             kDataWorldLength,
-             4),
-    MockRead(SYNCHRONOUS, 0, 5)  // EOF
-  };
-
-  scoped_ptr<SpdyHeaderBlock> request_headers(new SpdyHeaderBlock());
-  spdy_util_.SetHeader("path", "/demo", request_headers.get());
-  spdy_util_.SetHeader("version", "WebSocket/13", request_headers.get());
-  spdy_util_.SetHeader("scheme", "ws", request_headers.get());
-  spdy_util_.SetHeader("host", "example.com", request_headers.get());
-  spdy_util_.SetHeader("origin", "http://example.com", request_headers.get());
-  spdy_util_.SetHeader("sec-websocket-protocol", "sample",
-                       request_headers.get());
-
-  scoped_ptr<SpdyHeaderBlock> response_headers(new SpdyHeaderBlock());
-  spdy_util_.SetHeader("status", "101 Switching Protocols",
-                       response_headers.get());
-  spdy_util_.SetHeader("sec-websocket-protocol", "sample",
-                       response_headers.get());
-
-  const SpdyStreamId kStreamId = 1;
-  scoped_ptr<SpdyFrame> request_frame(
-      spdy_util_.ConstructSpdyWebSocketHandshakeRequestFrame(
-          request_headers.Pass(),
-          kStreamId,
-          MEDIUM));
-  scoped_ptr<SpdyFrame> response_frame(
-      spdy_util_.ConstructSpdyWebSocketHandshakeResponseFrame(
-          response_headers.Pass(),
-          kStreamId,
-          MEDIUM));
-  scoped_ptr<SpdyFrame> data_hello_frame(
-      spdy_util_.ConstructSpdyWebSocketDataFrame(
-          kDataHello,
-          kDataHelloLength,
-          kStreamId,
-          false));
-  scoped_ptr<SpdyFrame> data_world_frame(
-      spdy_util_.ConstructSpdyWebSocketDataFrame(
-          kDataWorld,
-          kDataWorldLength,
-          kStreamId,
-          false));
-  MockWrite writes_spdy[] = {
-    CreateMockWrite(*request_frame.get(), 1),
-    CreateMockWrite(*data_hello_frame.get(), 3),
-  };
-  MockRead reads_spdy[] = {
-    CreateMockRead(*response_frame.get(), 2),
-    CreateMockRead(*data_world_frame.get(), 4),
-    MockRead(SYNCHRONOUS, 0, 5)  // EOF
-  };
-
-  if (spdy == SPDY_ON)
-    data_.reset(new OrderedSocketData(
-        reads_spdy, arraysize(reads_spdy),
-        writes_spdy, arraysize(writes_spdy)));
-  else
-    data_.reset(new OrderedSocketData(
-        reads_websocket, arraysize(reads_websocket),
-        writes_websocket, arraysize(writes_websocket)));
-
-  GURL url("ws://example.com/demo");
-  MockSocketStreamDelegate delegate;
-  WebSocketJobTest* test = this;
-  if (throttling == THROTTLING_ON)
-    delegate.SetOnStartOpenConnection(
-        base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
-  delegate.SetOnConnected(
-      base::Bind(&WebSocketJobTest::DoSendRequest,
-                 base::Unretained(test)));
-  delegate.SetOnReceivedData(
-      base::Bind(&WebSocketJobTest::DoSendData, base::Unretained(test)));
-  delegate.SetOnClose(
-      base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
-  InitWebSocketJob(url, &delegate, STREAM_SPDY_WEBSOCKET);
-
-  scoped_refptr<WebSocketJob> block_websocket;
-  if (throttling == THROTTLING_ON) {
-    // Create former WebSocket object which obstructs the latter one.
-    block_websocket = new WebSocketJob(NULL);
-    block_websocket->addresses_ = AddressList(websocket_->address_list());
-    ASSERT_TRUE(
-        WebSocketThrottle::GetInstance()->PutInQueue(block_websocket.get()));
-  }
-
-  websocket_->Connect();
-
-  if (throttling == THROTTLING_ON) {
-    EXPECT_EQ(OK, WaitForResult());
-    EXPECT_TRUE(websocket_->IsWaiting());
-
-    // Remove the former WebSocket object from throttling queue to unblock the
-    // latter.
-    block_websocket->state_ = WebSocketJob::CLOSED;
-    WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket.get());
-    block_websocket = NULL;
-  }
-
-  EXPECT_EQ(OK, WaitForResult());
-  EXPECT_TRUE(data_->at_read_eof());
-  EXPECT_TRUE(data_->at_write_eof());
-  EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState());
-}
-
-void WebSocketJobTest::TestThrottlingLimit() {
-  std::vector<scoped_refptr<WebSocketJob> > jobs;
-  const int kMaxWebSocketJobsThrottled = 1024;
-  IPAddressNumber ip;
-  ParseIPLiteralToNumber("127.0.0.1", &ip);
-  for (int i = 0; i < kMaxWebSocketJobsThrottled + 1; ++i) {
-    scoped_refptr<WebSocketJob> job = new WebSocketJob(NULL);
-    job->addresses_ = AddressList(AddressList::CreateFromIPAddress(ip, 80));
-    if (i >= kMaxWebSocketJobsThrottled)
-      EXPECT_FALSE(WebSocketThrottle::GetInstance()->PutInQueue(job.get()));
-    else
-      EXPECT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(job.get()));
-    jobs.push_back(job);
-  }
-
-  // Close the jobs in reverse order. Otherwise, We need to make them prepared
-  // for Wakeup call.
-  for (std::vector<scoped_refptr<WebSocketJob> >::reverse_iterator iter =
-           jobs.rbegin();
-       iter != jobs.rend();
-       ++iter) {
-    WebSocketJob* job = (*iter).get();
-    job->state_ = WebSocketJob::CLOSED;
-    WebSocketThrottle::GetInstance()->RemoveFromQueue(job);
-  }
-}
-
-// Execute tests in both spdy-disabled mode and spdy-enabled mode.
-TEST_P(WebSocketJobTest, SimpleHandshake) {
-  TestSimpleHandshake();
-}
-
-TEST_P(WebSocketJobTest, SlowHandshake) {
-  TestSlowHandshake();
-}
-
-TEST_P(WebSocketJobTest, HandshakeWithCookie) {
-  TestHandshakeWithCookie();
-}
-
-TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowed) {
-  TestHandshakeWithCookieButNotAllowed();
-}
-
-TEST_P(WebSocketJobTest, HSTSUpgrade) {
-  TestHSTSUpgrade();
-}
-
-TEST_P(WebSocketJobTest, InvalidSendData) {
-  TestInvalidSendData();
-}
-
-TEST_P(WebSocketJobTest, SimpleHandshakeSpdyEnabled) {
-  enable_websocket_over_spdy_ = true;
-  TestSimpleHandshake();
-}
-
-TEST_P(WebSocketJobTest, SlowHandshakeSpdyEnabled) {
-  enable_websocket_over_spdy_ = true;
-  TestSlowHandshake();
-}
-
-TEST_P(WebSocketJobTest, HandshakeWithCookieSpdyEnabled) {
-  enable_websocket_over_spdy_ = true;
-  TestHandshakeWithCookie();
-}
-
-TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowedSpdyEnabled) {
-  enable_websocket_over_spdy_ = true;
-  TestHandshakeWithCookieButNotAllowed();
-}
-
-TEST_P(WebSocketJobTest, HSTSUpgradeSpdyEnabled) {
-  enable_websocket_over_spdy_ = true;
-  TestHSTSUpgrade();
-}
-
-TEST_P(WebSocketJobTest, InvalidSendDataSpdyEnabled) {
-  enable_websocket_over_spdy_ = true;
-  TestInvalidSendData();
-}
-
-TEST_P(WebSocketJobTest, ConnectByWebSocket) {
-  enable_websocket_over_spdy_ = true;
-  TestConnectByWebSocket(THROTTLING_OFF);
-}
-
-TEST_P(WebSocketJobTest, ConnectByWebSocketSpdyEnabled) {
-  enable_websocket_over_spdy_ = true;
-  TestConnectByWebSocket(THROTTLING_OFF);
-}
-
-TEST_P(WebSocketJobTest, ConnectBySpdy) {
-  TestConnectBySpdy(SPDY_OFF, THROTTLING_OFF);
-}
-
-TEST_P(WebSocketJobTest, ConnectBySpdySpdyEnabled) {
-  enable_websocket_over_spdy_ = true;
-  TestConnectBySpdy(SPDY_ON, THROTTLING_OFF);
-}
-
-TEST_P(WebSocketJobTest, ThrottlingWebSocket) {
-  TestConnectByWebSocket(THROTTLING_ON);
-}
-
-TEST_P(WebSocketJobTest, ThrottlingMaxNumberOfThrottledJobLimit) {
-  TestThrottlingLimit();
-}
-
-TEST_P(WebSocketJobTest, ThrottlingWebSocketSpdyEnabled) {
-  enable_websocket_over_spdy_ = true;
-  TestConnectByWebSocket(THROTTLING_ON);
-}
-
-TEST_P(WebSocketJobTest, ThrottlingSpdy) {
-  TestConnectBySpdy(SPDY_OFF, THROTTLING_ON);
-}
-
-TEST_P(WebSocketJobTest, ThrottlingSpdySpdyEnabled) {
-  enable_websocket_over_spdy_ = true;
-  TestConnectBySpdy(SPDY_ON, THROTTLING_ON);
-}
-
-TEST_F(WebSocketJobDeleteTest, OnClose) {
-  SetDeleteNext();
-  job()->OnClose(socket_.get());
-  // OnClose() sets WebSocketJob::_socket to NULL before we can detach it, so
-  // socket_->delegate is still set at this point. Clear it to avoid hitting
-  // DCHECK(!delegate_) in the SocketStream destructor. SocketStream::Finish()
-  // is the only caller of this method in real code, and it also sets delegate_
-  // to NULL.
-  socket_->DetachDelegate();
-  EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, OnAuthRequired) {
-  SetDeleteNext();
-  job()->OnAuthRequired(socket_.get(), NULL);
-  EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, OnSSLCertificateError) {
-  SSLInfo ssl_info;
-  SetDeleteNext();
-  job()->OnSSLCertificateError(socket_.get(), ssl_info, true);
-  EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, OnError) {
-  SetDeleteNext();
-  job()->OnError(socket_.get(), ERR_CONNECTION_RESET);
-  EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, OnSentSpdyHeaders) {
-  job()->Connect();
-  SetDeleteNext();
-  job()->OnSentSpdyHeaders();
-  EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, OnSentHandshakeRequest) {
-  static const char kMinimalRequest[] =
-      "GET /demo HTTP/1.1\r\n"
-      "Host: example.com\r\n"
-      "Upgrade: WebSocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
-      "Origin: http://example.com\r\n"
-      "Sec-WebSocket-Version: 13\r\n"
-      "\r\n";
-  const size_t kMinimalRequestSize = arraysize(kMinimalRequest) - 1;
-  job()->Connect();
-  job()->SendData(kMinimalRequest, kMinimalRequestSize);
-  SetDeleteNext();
-  job()->OnSentData(socket_.get(), kMinimalRequestSize);
-  EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, NotifyHeadersComplete) {
-  static const char kMinimalResponse[] =
-      "HTTP/1.1 101 Switching Protocols\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
-      "\r\n";
-  job()->Connect();
-  SetDeleteNext();
-  job()->OnReceivedData(
-      socket_.get(), kMinimalResponse, arraysize(kMinimalResponse) - 1);
-  EXPECT_FALSE(job());
-}
-
-// TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation.
-// TODO(toyoshim,yutak): Add tests to verify closing handshake.
-}  // namespace net
diff --git a/net/websockets/websocket_net_log_params.cc b/net/websockets/websocket_net_log_params.cc
deleted file mode 100644
index dd9bdde..0000000
--- a/net/websockets/websocket_net_log_params.cc
+++ /dev/null
@@ -1,49 +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 "net/websockets/websocket_net_log_params.h"
-
-#include "base/strings/stringprintf.h"
-#include "base/values.h"
-
-namespace net {
-
-base::Value* NetLogWebSocketHandshakeCallback(
-    const std::string* headers,
-    NetLog::LogLevel /* log_level */) {
-  base::DictionaryValue* dict = new base::DictionaryValue();
-  base::ListValue* header_list = new base::ListValue();
-
-  size_t last = 0;
-  size_t headers_size = headers->size();
-  size_t pos = 0;
-  while (pos <= headers_size) {
-    if (pos == headers_size ||
-        ((*headers)[pos] == '\r' &&
-         pos + 1 < headers_size && (*headers)[pos + 1] == '\n')) {
-      std::string entry = headers->substr(last, pos - last);
-      pos += 2;
-      last = pos;
-
-      header_list->Append(new base::StringValue(entry));
-
-      if (entry.empty()) {
-        // Dump WebSocket key3.
-        std::string key;
-        for (; pos < headers_size; ++pos) {
-          key += base::StringPrintf("\\x%02x", (*headers)[pos] & 0xff);
-        }
-        header_list->Append(new base::StringValue(key));
-        break;
-      }
-    } else {
-      ++pos;
-    }
-  }
-
-  dict->Set("headers", header_list);
-  return dict;
-}
-
-}  // namespace net
diff --git a/net/websockets/websocket_net_log_params.h b/net/websockets/websocket_net_log_params.h
deleted file mode 100644
index 45dabb0..0000000
--- a/net/websockets/websocket_net_log_params.h
+++ /dev/null
@@ -1,21 +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 NET_WEBSOCKETS_WEBSOCKET_NET_LOG_PARAMS_H_
-#define NET_WEBSOCKETS_WEBSOCKET_NET_LOG_PARAMS_H_
-
-#include <string>
-
-#include "net/base/net_export.h"
-#include "net/base/net_log.h"
-
-namespace net {
-
-NET_EXPORT_PRIVATE base::Value* NetLogWebSocketHandshakeCallback(
-    const std::string* headers,
-    NetLog::LogLevel /* log_level */);
-
-}  // namespace net
-
-#endif  // NET_WEBSOCKETS_WEBSOCKET_NET_LOG_PARAMS_H_
diff --git a/net/websockets/websocket_net_log_params_test.cc b/net/websockets/websocket_net_log_params_test.cc
deleted file mode 100644
index d6d2a0d..0000000
--- a/net/websockets/websocket_net_log_params_test.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/websockets/websocket_net_log_params.h"
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/values.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(NetLogWebSocketHandshakeParameterTest, ToValue) {
-  base::ListValue* list = new base::ListValue();
-  list->Append(new base::StringValue("GET /demo HTTP/1.1"));
-  list->Append(new base::StringValue("Host: example.com"));
-  list->Append(new base::StringValue("Connection: Upgrade"));
-  list->Append(new base::StringValue("Sec-WebSocket-Key2: 12998 5 Y3 1  .P00"));
-  list->Append(new base::StringValue("Sec-WebSocket-Protocol: sample"));
-  list->Append(new base::StringValue("Upgrade: WebSocket"));
-  list->Append(new base::StringValue(
-      "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5"));
-  list->Append(new base::StringValue("Origin: http://example.com"));
-  list->Append(new base::StringValue(std::string()));
-  list->Append(new base::StringValue(
-      "\\x00\\x01\\x0a\\x0d\\xff\\xfe\\x0d\\x0a"));
-
-  base::DictionaryValue expected;
-  expected.Set("headers", list);
-
-  const std::string key("\x00\x01\x0a\x0d\xff\xfe\x0d\x0a", 8);
-  const std::string testInput =
-    "GET /demo HTTP/1.1\r\n"
-    "Host: example.com\r\n"
-    "Connection: Upgrade\r\n"
-    "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n"
-    "Sec-WebSocket-Protocol: sample\r\n"
-    "Upgrade: WebSocket\r\n"
-    "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n"
-    "Origin: http://example.com\r\n"
-    "\r\n" +
-    key;
-
-  scoped_ptr<base::Value> actual(
-      net::NetLogWebSocketHandshakeCallback(&testInput,
-                                            net::NetLog::LOG_ALL));
-
-  EXPECT_TRUE(expected.Equals(actual.get()));
-}
diff --git a/net/websockets/websocket_throttle.cc b/net/websockets/websocket_throttle.cc
deleted file mode 100644
index 59e73fd..0000000
--- a/net/websockets/websocket_throttle.cc
+++ /dev/null
@@ -1,144 +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 "net/websockets/websocket_throttle.h"
-
-#include <algorithm>
-#include <set>
-#include <string>
-#include <utility>
-
-#include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/base/io_buffer.h"
-#include "net/socket_stream/socket_stream.h"
-#include "net/websockets/websocket_job.h"
-
-namespace net {
-
-namespace {
-
-const size_t kMaxWebSocketJobsThrottled = 1024;
-
-}  // namespace
-
-WebSocketThrottle::WebSocketThrottle() {
-}
-
-WebSocketThrottle::~WebSocketThrottle() {
-  DCHECK(queue_.empty());
-  DCHECK(addr_map_.empty());
-}
-
-// static
-WebSocketThrottle* WebSocketThrottle::GetInstance() {
-  return Singleton<WebSocketThrottle>::get();
-}
-
-bool WebSocketThrottle::PutInQueue(WebSocketJob* job) {
-  if (queue_.size() >= kMaxWebSocketJobsThrottled)
-    return false;
-
-  queue_.push_back(job);
-  const AddressList& address_list = job->address_list();
-  std::set<IPEndPoint> address_set;
-  for (AddressList::const_iterator addr_iter = address_list.begin();
-       addr_iter != address_list.end();
-       ++addr_iter) {
-    const IPEndPoint& address = *addr_iter;
-    // If |address| is already processed, don't do it again.
-    if (!address_set.insert(address).second)
-      continue;
-
-    ConnectingAddressMap::iterator iter = addr_map_.find(address);
-    if (iter == addr_map_.end()) {
-      ConnectingAddressMap::iterator new_queue =
-          addr_map_.insert(make_pair(address, ConnectingQueue())).first;
-      new_queue->second.push_back(job);
-    } else {
-      DCHECK(!iter->second.empty());
-      iter->second.push_back(job);
-      job->SetWaiting();
-      DVLOG(1) << "Waiting on " << address.ToString();
-    }
-  }
-
-  return true;
-}
-
-void WebSocketThrottle::RemoveFromQueue(WebSocketJob* job) {
-  ConnectingQueue::iterator queue_iter =
-      std::find(queue_.begin(), queue_.end(), job);
-  if (queue_iter == queue_.end())
-    return;
-  queue_.erase(queue_iter);
-
-  std::set<WebSocketJob*> wakeup_candidates;
-
-  const AddressList& resolved_address_list = job->address_list();
-  std::set<IPEndPoint> address_set;
-  for (AddressList::const_iterator addr_iter = resolved_address_list.begin();
-       addr_iter != resolved_address_list.end();
-       ++addr_iter) {
-    const IPEndPoint& address = *addr_iter;
-    // If |address| is already processed, don't do it again.
-    if (!address_set.insert(address).second)
-      continue;
-
-    ConnectingAddressMap::iterator map_iter = addr_map_.find(address);
-    DCHECK(map_iter != addr_map_.end());
-
-    ConnectingQueue& per_address_queue = map_iter->second;
-    DCHECK(!per_address_queue.empty());
-    // Job may not be front of the queue if the socket is closed while waiting.
-    ConnectingQueue::iterator per_address_queue_iter =
-        std::find(per_address_queue.begin(), per_address_queue.end(), job);
-    bool was_front = false;
-    if (per_address_queue_iter != per_address_queue.end()) {
-      was_front = (per_address_queue_iter == per_address_queue.begin());
-      per_address_queue.erase(per_address_queue_iter);
-    }
-    if (per_address_queue.empty()) {
-      addr_map_.erase(map_iter);
-    } else if (was_front) {
-      // The new front is a wake-up candidate.
-      wakeup_candidates.insert(per_address_queue.front());
-    }
-  }
-
-  WakeupSocketIfNecessary(wakeup_candidates);
-}
-
-void WebSocketThrottle::WakeupSocketIfNecessary(
-    const std::set<WebSocketJob*>& wakeup_candidates) {
-  for (std::set<WebSocketJob*>::const_iterator iter = wakeup_candidates.begin();
-       iter != wakeup_candidates.end();
-       ++iter) {
-    WebSocketJob* job = *iter;
-    if (!job->IsWaiting())
-      continue;
-
-    bool should_wakeup = true;
-    const AddressList& resolved_address_list = job->address_list();
-    for (AddressList::const_iterator addr_iter = resolved_address_list.begin();
-         addr_iter != resolved_address_list.end();
-         ++addr_iter) {
-      const IPEndPoint& address = *addr_iter;
-      ConnectingAddressMap::iterator map_iter = addr_map_.find(address);
-      DCHECK(map_iter != addr_map_.end());
-      const ConnectingQueue& per_address_queue = map_iter->second;
-      if (job != per_address_queue.front()) {
-        should_wakeup = false;
-        break;
-      }
-    }
-    if (should_wakeup)
-      job->Wakeup();
-  }
-}
-
-}  // namespace net
diff --git a/net/websockets/websocket_throttle.h b/net/websockets/websocket_throttle.h
deleted file mode 100644
index 0b7a39f..0000000
--- a/net/websockets/websocket_throttle.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_WEBSOCKETS_WEBSOCKET_THROTTLE_H_
-#define NET_WEBSOCKETS_WEBSOCKET_THROTTLE_H_
-
-#include <deque>
-#include <map>
-#include <set>
-#include <string>
-
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_export.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-namespace net {
-
-class SocketStream;
-class WebSocketJob;
-
-// SocketStreamThrottle for WebSocket protocol.
-// Implements the client-side requirements in the spec.
-// http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
-// 4.1 Handshake
-//   1.   If the user agent already has a Web Socket connection to the
-//        remote host (IP address) identified by /host/, even if known by
-//        another name, wait until that connection has been established or
-//        for that connection to have failed.
-class NET_EXPORT_PRIVATE WebSocketThrottle {
- public:
-  // Returns the singleton instance.
-  static WebSocketThrottle* GetInstance();
-
-  // Puts |job| in |queue_| and queues for the destination addresses
-  // of |job|.
-  // If other job is using the same destination address, set |job| waiting.
-  //
-  // Returns true if successful. If the number of pending jobs will exceed
-  // the limit, does nothing and returns false.
-  bool PutInQueue(WebSocketJob* job);
-
-  // Removes |job| from |queue_| and queues for the destination addresses
-  // of |job|, and then wakes up jobs that can now resume establishing a
-  // connection.
-  void RemoveFromQueue(WebSocketJob* job);
-
- private:
-  typedef std::deque<WebSocketJob*> ConnectingQueue;
-  typedef std::map<IPEndPoint, ConnectingQueue> ConnectingAddressMap;
-
-  WebSocketThrottle();
-  ~WebSocketThrottle();
-  friend struct DefaultSingletonTraits<WebSocketThrottle>;
-
-  // Examines if any of the given jobs can resume establishing a connection. If
-  // for all per-address queues for each resolved addresses
-  // (job->address_list()) of a job, the job is at the front of the queues, the
-  // job can resume establishing a connection, so wakes up the job.
-  void WakeupSocketIfNecessary(
-      const std::set<WebSocketJob*>& wakeup_candidates);
-
-  // Key: string of host's address.  Value: queue of sockets for the address.
-  ConnectingAddressMap addr_map_;
-
-  // Queue of sockets for websockets in opening state.
-  ConnectingQueue queue_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebSocketThrottle);
-};
-
-}  // namespace net
-
-#endif  // NET_WEBSOCKETS_WEBSOCKET_THROTTLE_H_
diff --git a/net/websockets/websocket_throttle_test.cc b/net/websockets/websocket_throttle_test.cc
deleted file mode 100644
index 4e27c83..0000000
--- a/net/websockets/websocket_throttle_test.cc
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/websockets/websocket_throttle.h"
-
-#include <string>
-
-#include "base/message_loop/message_loop.h"
-#include "net/base/address_list.h"
-#include "net/base/test_completion_callback.h"
-#include "net/socket_stream/socket_stream.h"
-#include "net/url_request/url_request_test_util.h"
-#include "net/websockets/websocket_job.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "url/gurl.h"
-
-namespace net {
-
-namespace {
-
-class DummySocketStreamDelegate : public SocketStream::Delegate {
- public:
-  DummySocketStreamDelegate() {}
-  ~DummySocketStreamDelegate() override {}
-  void OnConnected(SocketStream* socket,
-                   int max_pending_send_allowed) override {}
-  void OnSentData(SocketStream* socket, int amount_sent) override {}
-  void OnReceivedData(SocketStream* socket,
-                      const char* data,
-                      int len) override {}
-  void OnClose(SocketStream* socket) override {}
-};
-
-class WebSocketThrottleTestContext : public TestURLRequestContext {
- public:
-  explicit WebSocketThrottleTestContext(bool enable_websocket_over_spdy)
-      : TestURLRequestContext(true) {
-    HttpNetworkSession::Params params;
-    params.enable_websocket_over_spdy = enable_websocket_over_spdy;
-    Init();
-  }
-};
-
-}  // namespace
-
-class WebSocketThrottleTest : public PlatformTest {
- protected:
-  static IPEndPoint MakeAddr(int a1, int a2, int a3, int a4) {
-    IPAddressNumber ip;
-    ip.push_back(a1);
-    ip.push_back(a2);
-    ip.push_back(a3);
-    ip.push_back(a4);
-    return IPEndPoint(ip, 0);
-  }
-
-  static void MockSocketStreamConnect(
-      SocketStream* socket, const AddressList& list) {
-    socket->set_addresses(list);
-    // TODO(toyoshim): We should introduce additional tests on cases via proxy.
-    socket->proxy_info_.UseDirect();
-    // In SocketStream::Connect(), it adds reference to socket, which is
-    // balanced with SocketStream::Finish() that is finally called from
-    // SocketStream::Close() or SocketStream::DetachDelegate(), when
-    // next_state_ is not STATE_NONE.
-    // If next_state_ is STATE_NONE, SocketStream::Close() or
-    // SocketStream::DetachDelegate() won't call SocketStream::Finish(),
-    // so Release() won't be called.  Thus, we don't need socket->AddRef()
-    // here.
-    DCHECK_EQ(socket->next_state_, SocketStream::STATE_NONE);
-  }
-};
-
-TEST_F(WebSocketThrottleTest, Throttle) {
-  // TODO(toyoshim): We need to consider both spdy-enabled and spdy-disabled
-  // configuration.
-  WebSocketThrottleTestContext context(true);
-  DummySocketStreamDelegate delegate;
-
-  // For host1: 1.2.3.4, 1.2.3.5, 1.2.3.6
-  AddressList addr;
-  addr.push_back(MakeAddr(1, 2, 3, 4));
-  addr.push_back(MakeAddr(1, 2, 3, 5));
-  addr.push_back(MakeAddr(1, 2, 3, 6));
-  scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate));
-  scoped_refptr<SocketStream> s1(
-      new SocketStream(GURL("ws://host1/"), w1.get(), &context, NULL));
-  w1->InitSocketStream(s1.get());
-  WebSocketThrottleTest::MockSocketStreamConnect(s1.get(), addr);
-
-  DVLOG(1) << "socket1";
-  TestCompletionCallback callback_s1;
-  // Trying to open connection to host1 will start without wait.
-  EXPECT_EQ(OK, w1->OnStartOpenConnection(s1.get(), callback_s1.callback()));
-
-  // Now connecting to host1, so waiting queue looks like
-  // Address | head -> tail
-  // 1.2.3.4 | w1
-  // 1.2.3.5 | w1
-  // 1.2.3.6 | w1
-
-  // For host2: 1.2.3.4
-  addr.clear();
-  addr.push_back(MakeAddr(1, 2, 3, 4));
-  scoped_refptr<WebSocketJob> w2(new WebSocketJob(&delegate));
-  scoped_refptr<SocketStream> s2(
-      new SocketStream(GURL("ws://host2/"), w2.get(), &context, NULL));
-  w2->InitSocketStream(s2.get());
-  WebSocketThrottleTest::MockSocketStreamConnect(s2.get(), addr);
-
-  DVLOG(1) << "socket2";
-  TestCompletionCallback callback_s2;
-  // Trying to open connection to host2 will wait for w1.
-  EXPECT_EQ(ERR_IO_PENDING,
-            w2->OnStartOpenConnection(s2.get(), callback_s2.callback()));
-  // Now waiting queue looks like
-  // Address | head -> tail
-  // 1.2.3.4 | w1 w2
-  // 1.2.3.5 | w1
-  // 1.2.3.6 | w1
-
-  // For host3: 1.2.3.5
-  addr.clear();
-  addr.push_back(MakeAddr(1, 2, 3, 5));
-  scoped_refptr<WebSocketJob> w3(new WebSocketJob(&delegate));
-  scoped_refptr<SocketStream> s3(
-      new SocketStream(GURL("ws://host3/"), w3.get(), &context, NULL));
-  w3->InitSocketStream(s3.get());
-  WebSocketThrottleTest::MockSocketStreamConnect(s3.get(), addr);
-
-  DVLOG(1) << "socket3";
-  TestCompletionCallback callback_s3;
-  // Trying to open connection to host3 will wait for w1.
-  EXPECT_EQ(ERR_IO_PENDING,
-            w3->OnStartOpenConnection(s3.get(), callback_s3.callback()));
-  // Address | head -> tail
-  // 1.2.3.4 | w1 w2
-  // 1.2.3.5 | w1    w3
-  // 1.2.3.6 | w1
-
-  // For host4: 1.2.3.4, 1.2.3.6
-  addr.clear();
-  addr.push_back(MakeAddr(1, 2, 3, 4));
-  addr.push_back(MakeAddr(1, 2, 3, 6));
-  scoped_refptr<WebSocketJob> w4(new WebSocketJob(&delegate));
-  scoped_refptr<SocketStream> s4(
-      new SocketStream(GURL("ws://host4/"), w4.get(), &context, NULL));
-  w4->InitSocketStream(s4.get());
-  WebSocketThrottleTest::MockSocketStreamConnect(s4.get(), addr);
-
-  DVLOG(1) << "socket4";
-  TestCompletionCallback callback_s4;
-  // Trying to open connection to host4 will wait for w1, w2.
-  EXPECT_EQ(ERR_IO_PENDING,
-            w4->OnStartOpenConnection(s4.get(), callback_s4.callback()));
-  // Address | head -> tail
-  // 1.2.3.4 | w1 w2    w4
-  // 1.2.3.5 | w1    w3
-  // 1.2.3.6 | w1       w4
-
-  // For host5: 1.2.3.6
-  addr.clear();
-  addr.push_back(MakeAddr(1, 2, 3, 6));
-  scoped_refptr<WebSocketJob> w5(new WebSocketJob(&delegate));
-  scoped_refptr<SocketStream> s5(
-      new SocketStream(GURL("ws://host5/"), w5.get(), &context, NULL));
-  w5->InitSocketStream(s5.get());
-  WebSocketThrottleTest::MockSocketStreamConnect(s5.get(), addr);
-
-  DVLOG(1) << "socket5";
-  TestCompletionCallback callback_s5;
-  // Trying to open connection to host5 will wait for w1, w4
-  EXPECT_EQ(ERR_IO_PENDING,
-            w5->OnStartOpenConnection(s5.get(), callback_s5.callback()));
-  // Address | head -> tail
-  // 1.2.3.4 | w1 w2    w4
-  // 1.2.3.5 | w1    w3
-  // 1.2.3.6 | w1       w4 w5
-
-  // For host6: 1.2.3.6
-  addr.clear();
-  addr.push_back(MakeAddr(1, 2, 3, 6));
-  scoped_refptr<WebSocketJob> w6(new WebSocketJob(&delegate));
-  scoped_refptr<SocketStream> s6(
-      new SocketStream(GURL("ws://host6/"), w6.get(), &context, NULL));
-  w6->InitSocketStream(s6.get());
-  WebSocketThrottleTest::MockSocketStreamConnect(s6.get(), addr);
-
-  DVLOG(1) << "socket6";
-  TestCompletionCallback callback_s6;
-  // Trying to open connection to host6 will wait for w1, w4, w5
-  EXPECT_EQ(ERR_IO_PENDING,
-            w6->OnStartOpenConnection(s6.get(), callback_s6.callback()));
-  // Address | head -> tail
-  // 1.2.3.4 | w1 w2    w4
-  // 1.2.3.5 | w1    w3
-  // 1.2.3.6 | w1       w4 w5 w6
-
-  // Receive partial response on w1, still connecting.
-  DVLOG(1) << "socket1 1";
-  static const char kHeader[] = "HTTP/1.1 101 WebSocket Protocol\r\n";
-  w1->OnReceivedData(s1.get(), kHeader, sizeof(kHeader) - 1);
-  EXPECT_FALSE(callback_s2.have_result());
-  EXPECT_FALSE(callback_s3.have_result());
-  EXPECT_FALSE(callback_s4.have_result());
-  EXPECT_FALSE(callback_s5.have_result());
-  EXPECT_FALSE(callback_s6.have_result());
-
-  // Receive rest of handshake response on w1.
-  DVLOG(1) << "socket1 2";
-  static const char kHeader2[] =
-      "Upgrade: WebSocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Origin: http://www.google.com\r\n"
-      "Sec-WebSocket-Location: ws://websocket.chromium.org\r\n"
-      "\r\n"
-      "8jKS'y:G*Co,Wxa-";
-  w1->OnReceivedData(s1.get(), kHeader2, sizeof(kHeader2) - 1);
-  base::MessageLoopForIO::current()->RunUntilIdle();
-  // Now, w1 is open.
-  EXPECT_EQ(WebSocketJob::OPEN, w1->state());
-  // So, w2 and w3 can start connecting. w4 needs to wait w2 (1.2.3.4)
-  EXPECT_TRUE(callback_s2.have_result());
-  EXPECT_TRUE(callback_s3.have_result());
-  EXPECT_FALSE(callback_s4.have_result());
-  // Address | head -> tail
-  // 1.2.3.4 |    w2    w4
-  // 1.2.3.5 |       w3
-  // 1.2.3.6 |          w4 w5 w6
-
-  // Closing s1 doesn't change waiting queue.
-  DVLOG(1) << "socket1 close";
-  w1->OnClose(s1.get());
-  base::MessageLoopForIO::current()->RunUntilIdle();
-  EXPECT_FALSE(callback_s4.have_result());
-  s1->DetachDelegate();
-  // Address | head -> tail
-  // 1.2.3.4 |    w2    w4
-  // 1.2.3.5 |       w3
-  // 1.2.3.6 |          w4 w5 w6
-
-  // w5 can close while waiting in queue.
-  DVLOG(1) << "socket5 close";
-  // w5 close() closes SocketStream that change state to STATE_CLOSE, calls
-  // DoLoop(), so OnClose() callback will be called.
-  w5->OnClose(s5.get());
-  base::MessageLoopForIO::current()->RunUntilIdle();
-  EXPECT_FALSE(callback_s4.have_result());
-  // Address | head -> tail
-  // 1.2.3.4 |    w2    w4
-  // 1.2.3.5 |       w3
-  // 1.2.3.6 |          w4 w6
-  s5->DetachDelegate();
-
-  // w6 close abnormally (e.g. renderer finishes) while waiting in queue.
-  DVLOG(1) << "socket6 close abnormally";
-  w6->DetachDelegate();
-  base::MessageLoopForIO::current()->RunUntilIdle();
-  EXPECT_FALSE(callback_s4.have_result());
-  // Address | head -> tail
-  // 1.2.3.4 |    w2    w4
-  // 1.2.3.5 |       w3
-  // 1.2.3.6 |          w4
-
-  // Closing s2 kicks w4 to start connecting.
-  DVLOG(1) << "socket2 close";
-  w2->OnClose(s2.get());
-  base::MessageLoopForIO::current()->RunUntilIdle();
-  EXPECT_TRUE(callback_s4.have_result());
-  // Address | head -> tail
-  // 1.2.3.4 |          w4
-  // 1.2.3.5 |       w3
-  // 1.2.3.6 |          w4
-  s2->DetachDelegate();
-
-  DVLOG(1) << "socket3 close";
-  w3->OnClose(s3.get());
-  base::MessageLoopForIO::current()->RunUntilIdle();
-  s3->DetachDelegate();
-  w4->OnClose(s4.get());
-  s4->DetachDelegate();
-  DVLOG(1) << "Done";
-  base::MessageLoopForIO::current()->RunUntilIdle();
-}
-
-TEST_F(WebSocketThrottleTest, NoThrottleForDuplicateAddress) {
-  WebSocketThrottleTestContext context(true);
-  DummySocketStreamDelegate delegate;
-
-  // For localhost: 127.0.0.1, 127.0.0.1
-  AddressList addr;
-  addr.push_back(MakeAddr(127, 0, 0, 1));
-  addr.push_back(MakeAddr(127, 0, 0, 1));
-  scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate));
-  scoped_refptr<SocketStream> s1(
-      new SocketStream(GURL("ws://localhost/"), w1.get(), &context, NULL));
-  w1->InitSocketStream(s1.get());
-  WebSocketThrottleTest::MockSocketStreamConnect(s1.get(), addr);
-
-  DVLOG(1) << "socket1";
-  TestCompletionCallback callback_s1;
-  // Trying to open connection to localhost will start without wait.
-  EXPECT_EQ(OK, w1->OnStartOpenConnection(s1.get(), callback_s1.callback()));
-
-  DVLOG(1) << "socket1 close";
-  w1->OnClose(s1.get());
-  s1->DetachDelegate();
-  DVLOG(1) << "Done";
-  base::MessageLoopForIO::current()->RunUntilIdle();
-}
-
-// A connection should not be blocked by another connection to the same IP
-// with a different port.
-TEST_F(WebSocketThrottleTest, NoThrottleForDistinctPort) {
-  WebSocketThrottleTestContext context(false);
-  DummySocketStreamDelegate delegate;
-  IPAddressNumber localhost;
-  ParseIPLiteralToNumber("127.0.0.1", &localhost);
-
-  // socket1: 127.0.0.1:80
-  scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate));
-  scoped_refptr<SocketStream> s1(
-      new SocketStream(GURL("ws://localhost:80/"), w1.get(), &context, NULL));
-  w1->InitSocketStream(s1.get());
-  MockSocketStreamConnect(s1.get(),
-                          AddressList::CreateFromIPAddress(localhost, 80));
-
-  DVLOG(1) << "connecting socket1";
-  TestCompletionCallback callback_s1;
-  // Trying to open connection to localhost:80 will start without waiting.
-  EXPECT_EQ(OK, w1->OnStartOpenConnection(s1.get(), callback_s1.callback()));
-
-  // socket2: 127.0.0.1:81
-  scoped_refptr<WebSocketJob> w2(new WebSocketJob(&delegate));
-  scoped_refptr<SocketStream> s2(
-      new SocketStream(GURL("ws://localhost:81/"), w2.get(), &context, NULL));
-  w2->InitSocketStream(s2.get());
-  MockSocketStreamConnect(s2.get(),
-                          AddressList::CreateFromIPAddress(localhost, 81));
-
-  DVLOG(1) << "connecting socket2";
-  TestCompletionCallback callback_s2;
-  // Trying to open connection to localhost:81 will start without waiting.
-  EXPECT_EQ(OK, w2->OnStartOpenConnection(s2.get(), callback_s2.callback()));
-
-  DVLOG(1) << "closing socket1";
-  w1->OnClose(s1.get());
-  s1->DetachDelegate();
-
-  DVLOG(1) << "closing socket2";
-  w2->OnClose(s2.get());
-  s2->DetachDelegate();
-  DVLOG(1) << "Done";
-  base::MessageLoopForIO::current()->RunUntilIdle();
-}
-
-}  // namespace net
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
index f73d8df..23baf4e 100644
--- a/sandbox/linux/BUILD.gn
+++ b/sandbox/linux/BUILD.gn
@@ -229,6 +229,8 @@
     "services/thread_helpers.h",
     "services/yama.h",
     "services/yama.cc",
+    "syscall_broker/broker_channel.cc",
+    "syscall_broker/broker_channel.h",
     "syscall_broker/broker_client.cc",
     "syscall_broker/broker_client.h",
     "syscall_broker/broker_common.h",
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc b/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc
index c56c819..b3d9126 100644
--- a/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc
+++ b/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc
@@ -759,26 +759,29 @@
     allowed_files.push_back("/proc/allowed");
     allowed_files.push_back("/proc/cpuinfo");
 
-    broker_process_.reset(
-        new BrokerProcess(EPERM, allowed_files, std::vector<std::string>()));
+    broker_process_.reset(new syscall_broker::BrokerProcess(
+        EPERM, allowed_files, std::vector<std::string>()));
     BPF_ASSERT(broker_process() != NULL);
     BPF_ASSERT(broker_process_->Init(base::Bind(&NoOpCallback)));
 
     initialized_ = true;
   }
   bool initialized() { return initialized_; }
-  class BrokerProcess* broker_process() { return broker_process_.get(); }
+  class syscall_broker::BrokerProcess* broker_process() {
+    return broker_process_.get();
+  }
 
  private:
   bool initialized_;
-  scoped_ptr<class BrokerProcess> broker_process_;
+  scoped_ptr<class syscall_broker::BrokerProcess> broker_process_;
   DISALLOW_COPY_AND_ASSIGN(InitializedOpenBroker);
 };
 
 intptr_t BrokerOpenTrapHandler(const struct arch_seccomp_data& args,
                                void* aux) {
   BPF_ASSERT(aux);
-  BrokerProcess* broker_process = static_cast<BrokerProcess*>(aux);
+  syscall_broker::BrokerProcess* broker_process =
+      static_cast<syscall_broker::BrokerProcess*>(aux);
   switch (args.nr) {
     case __NR_faccessat:  // access is a wrapper of faccessat in android
       BPF_ASSERT(static_cast<int>(args.args[0]) == AT_FDCWD);
@@ -824,7 +827,7 @@
 #endif
       case __NR_openat:
         // We get a InitializedOpenBroker class, but our trap handler wants
-        // the BrokerProcess object.
+        // the syscall_broker::BrokerProcess object.
         return Trap(BrokerOpenTrapHandler, iob_->broker_process());
       default:
         return Allow();
@@ -844,7 +847,7 @@
          DenyOpenPolicy,
          InitializedOpenBroker /* (*BPF_AUX) */) {
   BPF_ASSERT(BPF_AUX->initialized());
-  BrokerProcess* broker_process = BPF_AUX->broker_process();
+  syscall_broker::BrokerProcess* broker_process = BPF_AUX->broker_process();
   BPF_ASSERT(broker_process != NULL);
 
   // First, use the broker "manually"
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi
index ba530c0..aa6341d 100644
--- a/sandbox/linux/sandbox_linux.gypi
+++ b/sandbox/linux/sandbox_linux.gypi
@@ -228,6 +228,8 @@
         'services/thread_helpers.h',
         'services/yama.cc',
         'services/yama.h',
+        'syscall_broker/broker_channel.cc',
+        'syscall_broker/broker_channel.h',
         'syscall_broker/broker_client.cc',
         'syscall_broker/broker_client.h',
         'syscall_broker/broker_common.h',
diff --git a/sandbox/linux/syscall_broker/broker_channel.cc b/sandbox/linux/syscall_broker/broker_channel.cc
new file mode 100644
index 0000000..fa0f761
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_channel.cc
@@ -0,0 +1,35 @@
+// 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 "sandbox/linux/syscall_broker/broker_channel.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// static
+void BrokerChannel::CreatePair(EndPoint* reader, EndPoint* writer) {
+  DCHECK(reader);
+  DCHECK(writer);
+  int socket_pair[2];
+  // Use SOCK_SEQPACKET, to preserve message boundaries but we also want to be
+  // notified (recvmsg should return and not block) when the connection has
+  // been broken which could mean that the other end has been closed.
+  PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, socket_pair));
+
+  reader->reset(socket_pair[0]);
+  PCHECK(0 == shutdown(reader->get(), SHUT_WR));
+
+  writer->reset(socket_pair[1]);
+  PCHECK(0 == shutdown(writer->get(), SHUT_RD));
+}
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
diff --git a/sandbox/linux/syscall_broker/broker_channel.h b/sandbox/linux/syscall_broker/broker_channel.h
new file mode 100644
index 0000000..2abdba4
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_channel.h
@@ -0,0 +1,31 @@
+// 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 SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// A small class to create a pipe-like communication channel. It is based on a
+// SOCK_SEQPACKET unix socket, which is connection-based and guaranteed to
+// preserve message boundaries.
+class BrokerChannel {
+ public:
+  typedef base::ScopedFD EndPoint;
+  static void CreatePair(EndPoint* reader, EndPoint* writer);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(BrokerChannel);
+};
+
+}  // namespace syscall_broker
+
+}  // namespace sandbox
+
+#endif  // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
diff --git a/sandbox/linux/syscall_broker/broker_client.cc b/sandbox/linux/syscall_broker/broker_client.cc
index 60dc9ba..e63205f 100644
--- a/sandbox/linux/syscall_broker/broker_client.cc
+++ b/sandbox/linux/syscall_broker/broker_client.cc
@@ -14,6 +14,7 @@
 #include "base/logging.h"
 #include "base/pickle.h"
 #include "base/posix/unix_domain_socket_linux.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
 #include "sandbox/linux/syscall_broker/broker_common.h"
 #include "sandbox/linux/syscall_broker/broker_policy.h"
 
@@ -75,12 +76,9 @@
   // temporary socketpair (created internally by SendRecvMsg()).
   // Then read the reply on this new socketpair in reply_buf and put an
   // eventual attached file descriptor in |returned_fd|.
-  ssize_t msg_len = UnixDomainSocket::SendRecvMsgWithFlags(ipc_channel_,
-                                                           reply_buf,
-                                                           sizeof(reply_buf),
-                                                           recvmsg_flags,
-                                                           &returned_fd,
-                                                           write_pickle);
+  ssize_t msg_len = UnixDomainSocket::SendRecvMsgWithFlags(
+      ipc_channel_.get(), reply_buf, sizeof(reply_buf), recvmsg_flags,
+      &returned_fd, write_pickle);
   if (msg_len <= 0) {
     if (!quiet_failures_for_tests_)
       RAW_LOG(ERROR, "Could not make request to broker process");
@@ -119,11 +117,11 @@
 }
 
 BrokerClient::BrokerClient(const BrokerPolicy& broker_policy,
-                           int ipc_channel,
+                           BrokerChannel::EndPoint ipc_channel,
                            bool fast_check_in_client,
                            bool quiet_failures_for_tests)
     : broker_policy_(broker_policy),
-      ipc_channel_(ipc_channel),
+      ipc_channel_(ipc_channel.Pass()),
       fast_check_in_client_(fast_check_in_client),
       quiet_failures_for_tests_(quiet_failures_for_tests) {
 }
diff --git a/sandbox/linux/syscall_broker/broker_client.h b/sandbox/linux/syscall_broker/broker_client.h
index 7d06175..2dfef81 100644
--- a/sandbox/linux/syscall_broker/broker_client.h
+++ b/sandbox/linux/syscall_broker/broker_client.h
@@ -6,6 +6,7 @@
 #define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CLIENT_H_
 
 #include "base/macros.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
 #include "sandbox/linux/syscall_broker/broker_common.h"
 
 namespace sandbox {
@@ -30,7 +31,7 @@
   // |fast_check_in_client| should be set to true and
   // |quiet_failures_for_tests| to false unless you are writing tests.
   BrokerClient(const BrokerPolicy& policy,
-               int ipc_channel,
+               BrokerChannel::EndPoint ipc_channel,
                bool fast_check_in_client,
                bool quiet_failures_for_tests);
   ~BrokerClient();
@@ -48,9 +49,12 @@
   // This is async signal safe.
   int Open(const char* pathname, int flags) const;
 
+  // Get the file descriptor used for IPC. This is used for tests.
+  int GetIPCDescriptor() const { return ipc_channel_.get(); }
+
  private:
   const BrokerPolicy& broker_policy_;
-  const int ipc_channel_;
+  const BrokerChannel::EndPoint ipc_channel_;
   const bool fast_check_in_client_;  // Whether to forward a request that we
                                      // know will be denied to the broker. (Used
                                      // for tests).
diff --git a/sandbox/linux/syscall_broker/broker_host.cc b/sandbox/linux/syscall_broker/broker_host.cc
index 995641d..29300f7 100644
--- a/sandbox/linux/syscall_broker/broker_host.cc
+++ b/sandbox/linux/syscall_broker/broker_host.cc
@@ -154,8 +154,9 @@
 
 }  // namespace
 
-BrokerHost::BrokerHost(const BrokerPolicy& broker_policy, int ipc_channel)
-    : broker_policy_(broker_policy), ipc_channel_(ipc_channel) {
+BrokerHost::BrokerHost(const BrokerPolicy& broker_policy,
+                       BrokerChannel::EndPoint ipc_channel)
+    : broker_policy_(broker_policy), ipc_channel_(ipc_channel.Pass()) {
 }
 
 BrokerHost::~BrokerHost() {
@@ -165,17 +166,16 @@
 // A request should have a file descriptor attached on which we will reply and
 // that we will then close.
 // A request should start with an int that will be used as the command type.
-bool BrokerHost::HandleRequest() const {
+BrokerHost::RequestStatus BrokerHost::HandleRequest() const {
   ScopedVector<base::ScopedFD> fds;
   char buf[kMaxMessageLength];
   errno = 0;
   const ssize_t msg_len =
-      UnixDomainSocket::RecvMsg(ipc_channel_, buf, sizeof(buf), &fds);
+      UnixDomainSocket::RecvMsg(ipc_channel_.get(), buf, sizeof(buf), &fds);
 
   if (msg_len == 0 || (msg_len == -1 && errno == ECONNRESET)) {
     // EOF from the client, or the client died, we should die.
-    // TODO(jln): change this.
-    _exit(0);
+    return RequestStatus::LOST_CLIENT;
   }
 
   // The client should send exactly one file descriptor, on which we
@@ -183,7 +183,7 @@
   // TODO(mdempsky): ScopedVector doesn't have 'at()', only 'operator[]'.
   if (msg_len < 0 || fds.size() != 1 || fds[0]->get() < 0) {
     PLOG(ERROR) << "Error reading message from the client";
-    return false;
+    return RequestStatus::FAILURE;
   }
 
   base::ScopedFD temporary_ipc(fds[0]->Pass());
@@ -192,28 +192,32 @@
   PickleIterator iter(pickle);
   int command_type;
   if (pickle.ReadInt(&iter, &command_type)) {
-    bool r = false;
+    bool command_handled = false;
     // Go through all the possible IPC messages.
     switch (command_type) {
       case COMMAND_ACCESS:
       case COMMAND_OPEN:
         // We reply on the file descriptor sent to us via the IPC channel.
-        r = HandleRemoteCommand(broker_policy_,
-                                static_cast<IPCCommand>(command_type),
-                                temporary_ipc.get(),
-                                pickle,
-                                iter);
+        command_handled = HandleRemoteCommand(
+            broker_policy_, static_cast<IPCCommand>(command_type),
+            temporary_ipc.get(), pickle, iter);
         break;
       default:
         NOTREACHED();
-        r = false;
         break;
     }
-    return r;
+
+    if (command_handled) {
+      return RequestStatus::SUCCESS;
+    } else {
+      return RequestStatus::FAILURE;
+    }
+
+    NOTREACHED();
   }
 
   LOG(ERROR) << "Error parsing IPC request";
-  return false;
+  return RequestStatus::FAILURE;
 }
 
 }  // namespace syscall_broker
diff --git a/sandbox/linux/syscall_broker/broker_host.h b/sandbox/linux/syscall_broker/broker_host.h
index 04c20ed..9866507 100644
--- a/sandbox/linux/syscall_broker/broker_host.h
+++ b/sandbox/linux/syscall_broker/broker_host.h
@@ -6,6 +6,7 @@
 #define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_HOST_H_
 
 #include "base/macros.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
 
 namespace sandbox {
 
@@ -18,14 +19,18 @@
 // |ipc_channel| according to |broker_policy|.
 class BrokerHost {
  public:
-  BrokerHost(const BrokerPolicy& broker_policy, int ipc_channel);
+  enum class RequestStatus { LOST_CLIENT = 0, SUCCESS, FAILURE };
+
+  BrokerHost(const BrokerPolicy& broker_policy,
+             BrokerChannel::EndPoint ipc_channel);
   ~BrokerHost();
 
-  bool HandleRequest() const;
+  RequestStatus HandleRequest() const;
 
  private:
   const BrokerPolicy& broker_policy_;
-  const int ipc_channel_;
+  const BrokerChannel::EndPoint ipc_channel_;
+
   DISALLOW_COPY_AND_ASSIGN(BrokerHost);
 };
 
diff --git a/sandbox/linux/syscall_broker/broker_process.cc b/sandbox/linux/syscall_broker/broker_process.cc
index 66b7660..ebd7d05 100644
--- a/sandbox/linux/syscall_broker/broker_process.cc
+++ b/sandbox/linux/syscall_broker/broker_process.cc
@@ -6,7 +6,6 @@
 
 #include <fcntl.h>
 #include <signal.h>
-#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
@@ -23,30 +22,33 @@
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/process_metrics.h"
 #include "build/build_config.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
 #include "sandbox/linux/syscall_broker/broker_client.h"
 #include "sandbox/linux/syscall_broker/broker_host.h"
 
 namespace sandbox {
 
+namespace syscall_broker {
+
 BrokerProcess::BrokerProcess(int denied_errno,
                              const std::vector<std::string>& allowed_r_files,
                              const std::vector<std::string>& allowed_w_files,
                              bool fast_check_in_client,
                              bool quiet_failures_for_tests)
     : initialized_(false),
-      is_child_(false),
       fast_check_in_client_(fast_check_in_client),
       quiet_failures_for_tests_(quiet_failures_for_tests),
       broker_pid_(-1),
-      policy_(denied_errno, allowed_r_files, allowed_w_files),
-      ipc_socketpair_(-1) {
+      policy_(denied_errno, allowed_r_files, allowed_w_files) {
 }
 
 BrokerProcess::~BrokerProcess() {
-  if (initialized_ && ipc_socketpair_ != -1) {
-    // Closing the socket should be enough to notify the child to die,
-    // unless it has been duplicated.
-    PCHECK(0 == IGNORE_EINTR(close(ipc_socketpair_)));
+  if (initialized_) {
+    if (broker_client_.get()) {
+      // Closing the socket should be enough to notify the child to die,
+      // unless it has been duplicated.
+      CloseChannel();
+    }
     PCHECK(0 == kill(broker_pid_, SIGKILL));
     siginfo_t process_info;
     // Reap the child.
@@ -58,59 +60,50 @@
 bool BrokerProcess::Init(
     const base::Callback<bool(void)>& broker_process_init_callback) {
   CHECK(!initialized_);
-  int socket_pair[2];
-  // Use SOCK_SEQPACKET, because we need to preserve message boundaries
-  // but we also want to be notified (recvmsg should return and not block)
-  // when the connection has been broken (one of the processes died).
-  if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, socket_pair)) {
-    LOG(ERROR) << "Failed to create socketpair";
-    return false;
-  }
+  BrokerChannel::EndPoint ipc_reader;
+  BrokerChannel::EndPoint ipc_writer;
+  BrokerChannel::CreatePair(&ipc_reader, &ipc_writer);
 
 #if !defined(THREAD_SANITIZER)
   DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
 #endif
   int child_pid = fork();
   if (child_pid == -1) {
-    close(socket_pair[0]);
-    close(socket_pair[1]);
     return false;
   }
   if (child_pid) {
     // We are the parent and we have just forked our broker process.
-    close(socket_pair[0]);
-    // We should only be able to write to the IPC channel. We'll always send
-    // a new file descriptor to receive the reply on.
-    shutdown(socket_pair[1], SHUT_RD);
-    ipc_socketpair_ = socket_pair[1];
-    is_child_ = false;
+    ipc_reader.reset();
     broker_pid_ = child_pid;
-    broker_client_.reset(
-        new syscall_broker::BrokerClient(policy_,
-                                         ipc_socketpair_,
-                                         fast_check_in_client_,
-                                         quiet_failures_for_tests_));
+    broker_client_.reset(new BrokerClient(policy_, ipc_writer.Pass(),
+                                          fast_check_in_client_,
+                                          quiet_failures_for_tests_));
     initialized_ = true;
     return true;
   } else {
-    // We are the broker.
-    close(socket_pair[1]);
-    // We should only be able to read from this IPC channel. We will send our
-    // replies on a new file descriptor attached to the requests.
-    shutdown(socket_pair[0], SHUT_WR);
-    ipc_socketpair_ = socket_pair[0];
-    is_child_ = true;
+    // We are the broker process. Make sure to close the writer's end so that
+    // we get notified if the client disappears.
+    ipc_writer.reset();
     CHECK(broker_process_init_callback.Run());
-    syscall_broker::BrokerHost broker_host(policy_, ipc_socketpair_);
-    initialized_ = true;
+    BrokerHost broker_host(policy_, ipc_reader.Pass());
     for (;;) {
-      broker_host.HandleRequest();
+      switch (broker_host.HandleRequest()) {
+        case BrokerHost::RequestStatus::LOST_CLIENT:
+          _exit(1);
+        case BrokerHost::RequestStatus::SUCCESS:
+        case BrokerHost::RequestStatus::FAILURE:
+          continue;
+      }
     }
     _exit(1);
   }
   NOTREACHED();
 }
 
+void BrokerProcess::CloseChannel() {
+  broker_client_.reset();
+}
+
 int BrokerProcess::Access(const char* pathname, int mode) const {
   RAW_CHECK(initialized_);
   return broker_client_->Access(pathname, mode);
@@ -121,4 +114,6 @@
   return broker_client_->Open(pathname, flags);
 }
 
+}  // namespace syscall_broker
+
 }  // namespace sandbox.
diff --git a/sandbox/linux/syscall_broker/broker_process.h b/sandbox/linux/syscall_broker/broker_process.h
index d5b521b..50e7eee 100644
--- a/sandbox/linux/syscall_broker/broker_process.h
+++ b/sandbox/linux/syscall_broker/broker_process.h
@@ -19,8 +19,8 @@
 namespace sandbox {
 
 namespace syscall_broker {
+
 class BrokerClient;
-}
 
 // Create a new "broker" process to which we can send requests via an IPC
 // channel by forking the current process.
@@ -68,21 +68,24 @@
   int broker_pid() const { return broker_pid_; }
 
  private:
+  friend class BrokerProcessTestHelper;
+
+  // Close the IPC channel with the other party. This should only be used
+  // by tests an none of the class methods should be used afterwards.
+  void CloseChannel();
+
   bool initialized_;  // Whether we've been through Init() yet.
-  bool is_child_;     // Whether we're the child (broker process).
-  bool fast_check_in_client_;
-  bool quiet_failures_for_tests_;
+  const bool fast_check_in_client_;
+  const bool quiet_failures_for_tests_;
   pid_t broker_pid_;                     // The PID of the broker (child).
   syscall_broker::BrokerPolicy policy_;  // The sandboxing policy.
-  scoped_ptr<syscall_broker::BrokerClient>
-      broker_client_;  // Can only exist if is_child_ is true.
+  scoped_ptr<syscall_broker::BrokerClient> broker_client_;
 
-  int ipc_socketpair_;  // Our communication channel to parent or child.
   DISALLOW_COPY_AND_ASSIGN(BrokerProcess);
-
-  friend class BrokerProcessTestHelper;
 };
 
+}  // namespace syscall_broker
+
 }  // namespace sandbox
 
 #endif  // SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_
diff --git a/sandbox/linux/syscall_broker/broker_process_unittest.cc b/sandbox/linux/syscall_broker/broker_process_unittest.cc
index e7d5442..997667c 100644
--- a/sandbox/linux/syscall_broker/broker_process_unittest.cc
+++ b/sandbox/linux/syscall_broker/broker_process_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <poll.h>
 #include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -24,6 +25,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/unix_domain_socket_linux.h"
+#include "sandbox/linux/syscall_broker/broker_client.h"
 #include "sandbox/linux/tests/scoped_temporary_file.h"
 #include "sandbox/linux/tests/test_utils.h"
 #include "sandbox/linux/tests/unit_tests.h"
@@ -31,10 +33,15 @@
 
 namespace sandbox {
 
+namespace syscall_broker {
+
 class BrokerProcessTestHelper {
  public:
-  static int get_ipc_socketpair(const BrokerProcess* broker) {
-    return broker->ipc_socketpair_;
+  static void CloseChannel(BrokerProcess* broker) { broker->CloseChannel(); }
+  // Get the client's IPC descriptor to send IPC requests directly.
+  // TODO(jln): refator tests to get rid of this.
+  static int GetIPCDescriptor(const BrokerProcess* broker) {
+    return broker->broker_client_->GetIPCDescriptor();
   }
 };
 
@@ -453,7 +460,7 @@
   BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>());
   SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback)));
 
-  const int ipc_fd = BrokerProcessTestHelper::get_ipc_socketpair(&open_broker);
+  const int ipc_fd = BrokerProcessTestHelper::GetIPCDescriptor(&open_broker);
   SANDBOX_ASSERT(ipc_fd >= 0);
 
   static const char kBogus[] = "not a pickle";
@@ -472,4 +479,60 @@
   SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd)));
 }
 
+bool CloseFD(int fd) {
+  PCHECK(0 == IGNORE_EINTR(close(fd)));
+  return true;
+}
+
+// Return true if the other end of the |reader| pipe was closed,
+// false if |timeout_in_seconds| was reached or another event
+// or error occured.
+bool WaitForClosedPipeWriter(int reader, int timeout_in_ms) {
+  struct pollfd poll_fd = {reader, POLLIN | POLLRDHUP, 0};
+  const int num_events = HANDLE_EINTR(poll(&poll_fd, 1, timeout_in_ms));
+  if (1 == num_events && poll_fd.revents | POLLHUP)
+    return true;
+  return false;
+}
+
+// Closing the broker client's IPC channel should terminate the broker
+// process.
+TEST(BrokerProcess, BrokerDiesOnClosedChannel) {
+  std::vector<std::string> read_whitelist;
+  read_whitelist.push_back("/proc/cpuinfo");
+
+  // Get the writing end of a pipe into the broker (child) process so
+  // that we can reliably detect when it dies.
+  int lifeline_fds[2];
+  PCHECK(0 == pipe(lifeline_fds));
+
+  BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>(),
+                            true /* fast_check_in_client */,
+                            false /* quiet_failures_for_tests */);
+  ASSERT_TRUE(open_broker.Init(base::Bind(&CloseFD, lifeline_fds[0])));
+  // Make sure the writing end only exists in the broker process.
+  CloseFD(lifeline_fds[1]);
+  base::ScopedFD reader(lifeline_fds[0]);
+
+  const pid_t broker_pid = open_broker.broker_pid();
+
+  // This should cause the broker process to exit.
+  BrokerProcessTestHelper::CloseChannel(&open_broker);
+
+  const int kTimeoutInMilliseconds = 5000;
+  const bool broker_lifeline_closed =
+      WaitForClosedPipeWriter(reader.get(), kTimeoutInMilliseconds);
+  // If the broker exited, its lifeline fd should be closed.
+  ASSERT_TRUE(broker_lifeline_closed);
+  // Now check that the broker has exited, but do not reap it.
+  siginfo_t process_info;
+  ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID, broker_pid, &process_info,
+                                   WEXITED | WNOWAIT)));
+  EXPECT_EQ(broker_pid, process_info.si_pid);
+  EXPECT_EQ(CLD_EXITED, process_info.si_code);
+  EXPECT_EQ(1, process_info.si_status);
+}
+
+}  // namespace syscall_broker
+
 }  // namespace sandbox
diff --git a/sandbox/linux/tests/unit_tests.h b/sandbox/linux/tests/unit_tests.h
index f745e13..6f150ac 100644
--- a/sandbox/linux/tests/unit_tests.h
+++ b/sandbox/linux/tests/unit_tests.h
@@ -99,6 +99,13 @@
   ((expr) ? static_cast<void>(0) : sandbox::UnitTests::AssertionFailure( \
                                        SANDBOX_STR(expr), __FILE__, __LINE__))
 
+#define SANDBOX_ASSERT_EQ(x, y) SANDBOX_ASSERT((x) == (y))
+#define SANDBOX_ASSERT_NE(x, y) SANDBOX_ASSERT((x) != (y))
+#define SANDBOX_ASSERT_LT(x, y) SANDBOX_ASSERT((x) < (y))
+#define SANDBOX_ASSERT_GT(x, y) SANDBOX_ASSERT((x) > (y))
+#define SANDBOX_ASSERT_LE(x, y) SANDBOX_ASSERT((x) <= (y))
+#define SANDBOX_ASSERT_GE(x, y) SANDBOX_ASSERT((x) >= (y))
+
 // This class allows to run unittests in their own process. The main method is
 // RunTestInProcess().
 class UnitTests {
diff --git a/sdch/BUILD.gn b/sdch/BUILD.gn
index 7a95f1f..727fb49 100644
--- a/sdch/BUILD.gn
+++ b/sdch/BUILD.gn
@@ -45,6 +45,24 @@
     "//third_party/zlib",
   ]
 
+  # gn orders flags on a target before flags from configs. The default config
+  # adds -Wall, and these flags have to be after -Wall -- so they need to come
+  # from a config and can't be on the target directly.
+  config("sdch_warnings") {
+    cflags = []
+    if (is_linux) {
+      # TODO(mostynb): remove this if open-vcdiff is ever updated for c++11:
+      cflags += [ "-Wno-deprecated-declarations" ]
+    }
+
+    if (is_clang) {
+      # sdch uses the pre-c++11 typedef-as-static_assert hack.
+      # https://code.google.com/p/open-vcdiff/issues/detail?id=44
+      cflags += [ "-Wno-unused-local-typedef" ]
+    }
+  }
+  configs += [ ":sdch_warnings" ]
+
   if (is_linux || is_android) {
     include_dirs = [ "linux" ]
   } else if (is_ios) {
@@ -69,9 +87,5 @@
   } else {
     logging_file = rebase_path("logging_forward.h", root_build_dir)
     cflags = [ "-include", logging_file ]
-    if (is_linux) {
-      # TODO(mostynb): remove this if open-vcdiff is ever updated for c++11:
-      cflags += [ "-Wno-deprecated-declarations" ]
-    }
   }
 }
diff --git a/sdch/sdch.gyp b/sdch/sdch.gyp
index 52a92f3..e886288 100644
--- a/sdch/sdch.gyp
+++ b/sdch/sdch.gyp
@@ -71,6 +71,11 @@
       # introduce static initializers, and which prevents open-vcdiff's
       # logging.h from being used).
       'variables': {
+        'clang_warning_flags': [
+          # sdch uses the pre-c++11 typedef-as-static_assert hack.
+          # https://code.google.com/p/open-vcdiff/issues/detail?id=44
+          '-Wno-unused-local-typedef',
+        ],
         'logging_path': 'logging_forward.h',
         'conditions': [
           # gyp leaves unspecified what the cwd is when running the compiler,
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index a57b6a1..7daabd4 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -302,8 +302,6 @@
     "ext/vector_canvas.h",
     "ext/vector_platform_device_emf_win.cc",
     "ext/vector_platform_device_emf_win.h",
-    "ext/vector_platform_device_skia.cc",
-    "ext/vector_platform_device_skia.h",
   ]
 
   # The skia gypi values are relative to the skia_dir, so we need to rebase.
@@ -416,16 +414,12 @@
   if (is_posix) {
     sources -= [ "ext/SkThread_chrome.cc" ]
   }
-  if (is_ios) {
-    sources -= [ "ext/vector_platform_device_skia.cc" ]
-  }
   if (is_win) {
     sources -= [ "ext/SkThread_chrome.cc" ]
   }
   if (is_android && (!enable_basic_printing && !enable_print_preview)) {
     sources -= [
       "ext/skia_utils_base.cc",
-      "ext/vector_platform_device_skia.cc"
     ]
   }
 
diff --git a/skia/ext/bitmap_platform_device_cairo.cc b/skia/ext/bitmap_platform_device_cairo.cc
index 6d5d77c..97fc92a 100644
--- a/skia/ext/bitmap_platform_device_cairo.cc
+++ b/skia/ext/bitmap_platform_device_cairo.cc
@@ -167,11 +167,11 @@
   cairo_destroy(cairo_);
 }
 
-SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const SkImageInfo& info,
-                                                   Usage /*usage*/) {
-  SkASSERT(info.colorType() == kN32_SkColorType);
-  return BitmapPlatformDevice::Create(info.width(), info.height(),
-                                      info.isOpaque());
+SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
+                                                     const CreateInfo& info) {
+  SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
+  return BitmapPlatformDevice::Create(info.fInfo.width(), info.fInfo.height(),
+                                      info.fInfo.isOpaque());
 }
 
 cairo_t* BitmapPlatformDevice::BeginPlatformPaint() {
diff --git a/skia/ext/bitmap_platform_device_cairo.h b/skia/ext/bitmap_platform_device_cairo.h
index 2932111..67a2f19 100644
--- a/skia/ext/bitmap_platform_device_cairo.h
+++ b/skia/ext/bitmap_platform_device_cairo.h
@@ -93,8 +93,8 @@
                                    const PlatformRect* src_rect) override;
 
  protected:
-  virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info,
-                                       Usage usage) override;
+  virtual SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info)
+    override;
 
  private:
   static BitmapPlatformDevice* Create(int width, int height, bool is_opaque,
diff --git a/skia/ext/bitmap_platform_device_mac.cc b/skia/ext/bitmap_platform_device_mac.cc
index 5204468..871ca83 100644
--- a/skia/ext/bitmap_platform_device_mac.cc
+++ b/skia/ext/bitmap_platform_device_mac.cc
@@ -237,11 +237,12 @@
     ReleaseBitmapContext();
 }
 
-SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const SkImageInfo& info,
-                                                   Usage /*usage*/) {
-  SkASSERT(info.colorType() == kN32_SkColorType);
-  return BitmapPlatformDevice::CreateAndClear(info.width(), info.height(),
-                                                info.isOpaque());
+SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
+                                                     const CreateInfo& info) {
+  SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
+  return BitmapPlatformDevice::CreateAndClear(info.fInfo.width(),
+                                              info.fInfo.height(),
+                                              info.fInfo.isOpaque());
 }
 
 // PlatformCanvas impl
diff --git a/skia/ext/bitmap_platform_device_mac.h b/skia/ext/bitmap_platform_device_mac.h
index dc78562..8921117 100644
--- a/skia/ext/bitmap_platform_device_mac.h
+++ b/skia/ext/bitmap_platform_device_mac.h
@@ -66,7 +66,7 @@
   BitmapPlatformDevice(CGContextRef context,
                        const SkBitmap& bitmap);
 
-  SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) override;
+  SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info) override;
 
  private:
   void ReleaseBitmapContext();
diff --git a/skia/ext/bitmap_platform_device_skia.cc b/skia/ext/bitmap_platform_device_skia.cc
index ee44e26..1dcf13b 100644
--- a/skia/ext/bitmap_platform_device_skia.cc
+++ b/skia/ext/bitmap_platform_device_skia.cc
@@ -51,11 +51,11 @@
 BitmapPlatformDevice::~BitmapPlatformDevice() {
 }
 
-SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const SkImageInfo& info,
-                                                   Usage /*usage*/) {
-  SkASSERT(info.colorType() == kN32_SkColorType);
-  return BitmapPlatformDevice::Create(info.width(), info.height(),
-                                      info.isOpaque());
+SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
+                                                     const CreateInfo& info) {
+  SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
+  return BitmapPlatformDevice::Create(info.fInfo.width(), info.fInfo.height(),
+                                      info.fInfo.isOpaque());
 }
 
 PlatformSurface BitmapPlatformDevice::BeginPlatformPaint() {
diff --git a/skia/ext/bitmap_platform_device_skia.h b/skia/ext/bitmap_platform_device_skia.h
index f670dea..3b8a28d 100644
--- a/skia/ext/bitmap_platform_device_skia.h
+++ b/skia/ext/bitmap_platform_device_skia.h
@@ -47,8 +47,8 @@
                                    const PlatformRect* src_rect) override;
 
  protected:
-  virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info,
-                                       Usage usage) override;
+  virtual SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info)
+    override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice);
diff --git a/skia/ext/bitmap_platform_device_win.cc b/skia/ext/bitmap_platform_device_win.cc
index e10a6de..3901ad5 100644
--- a/skia/ext/bitmap_platform_device_win.cc
+++ b/skia/ext/bitmap_platform_device_win.cc
@@ -270,11 +270,12 @@
   return SkBitmapDevice::onAccessBitmap();
 }
 
-SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const SkImageInfo& info,
-                                                   Usage /*usage*/) {
-  SkASSERT(info.colorType() == kN32_SkColorType);
-  return BitmapPlatformDevice::CreateAndClear(info.width(), info.height(),
-                                              info.isOpaque());
+SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
+                                                    const CreateInfo& info) {
+  SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
+  return BitmapPlatformDevice::CreateAndClear(info.fInfo.width(),
+                                              info.fInfo.height(),
+                                              info.fInfo.isOpaque());
 }
 
 // PlatformCanvas impl
diff --git a/skia/ext/bitmap_platform_device_win.h b/skia/ext/bitmap_platform_device_win.h
index a8b7d83..92b1408 100644
--- a/skia/ext/bitmap_platform_device_win.h
+++ b/skia/ext/bitmap_platform_device_win.h
@@ -68,8 +68,8 @@
   // starts accessing pixel data.
   virtual const SkBitmap& onAccessBitmap() override;
 
-  virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info,
-                                       Usage usage) override;
+  virtual SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info)
+    override;
 
  private:
   // Private constructor.
diff --git a/skia/ext/vector_platform_device_emf_win.cc b/skia/ext/vector_platform_device_emf_win.cc
index 19e3066..1271b16 100644
--- a/skia/ext/vector_platform_device_emf_win.cc
+++ b/skia/ext/vector_platform_device_emf_win.cc
@@ -695,11 +695,11 @@
   LoadClippingRegionToDC(hdc_, clip_region_, t);
 }
 
-SkBaseDevice* VectorPlatformDeviceEmf::onCreateDevice(const SkImageInfo& info,
-                                                      Usage /*usage*/) {
-  SkASSERT(info.colorType() == kN32_SkColorType);
+SkBaseDevice* VectorPlatformDeviceEmf::onCreateCompatibleDevice(
+                                                    const CreateInfo& info) {
+  SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
   return VectorPlatformDeviceEmf::CreateDevice(
-      info.width(), info.height(), info.isOpaque(), NULL);
+      info.fInfo.width(), info.fInfo.height(), info.fInfo.isOpaque(), NULL);
 }
 
 bool VectorPlatformDeviceEmf::CreateBrush(bool use_brush, COLORREF color) {
diff --git a/skia/ext/vector_platform_device_emf_win.h b/skia/ext/vector_platform_device_emf_win.h
index f65390f..8d5b393 100644
--- a/skia/ext/vector_platform_device_emf_win.h
+++ b/skia/ext/vector_platform_device_emf_win.h
@@ -79,8 +79,7 @@
   void LoadClipRegion();
 
  protected:
-  virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info,
-                                       Usage usage) override;
+  virtual SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info) override;
 
  private:
   // Applies the SkPaint's painting properties in the current GDI context, if
diff --git a/skia/ext/vector_platform_device_skia.cc b/skia/ext/vector_platform_device_skia.cc
deleted file mode 100644
index 5b8217c..0000000
--- a/skia/ext/vector_platform_device_skia.cc
+++ /dev/null
@@ -1,88 +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/vector_platform_device_skia.h"
-
-#include "skia/ext/bitmap_platform_device.h"
-#include "third_party/skia/include/core/SkClipStack.h"
-#include "third_party/skia/include/core/SkDraw.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "third_party/skia/include/core/SkRegion.h"
-#include "third_party/skia/include/core/SkScalar.h"
-
-namespace skia {
-
-static inline SkBitmap makeABitmap(int width, int height) {
-  SkBitmap bitmap;
-  bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
-  return bitmap;
-}
-
-VectorPlatformDeviceSkia::VectorPlatformDeviceSkia(
-    const SkISize& pageSize,
-    const SkISize& contentSize,
-    const SkMatrix& initialTransform)
-    : SkPDFDevice(pageSize, contentSize, initialTransform) {
-  SetPlatformDevice(this, this);
-}
-
-VectorPlatformDeviceSkia::~VectorPlatformDeviceSkia() {
-}
-
-bool VectorPlatformDeviceSkia::SupportsPlatformPaint() {
-  return false;
-}
-
-PlatformSurface VectorPlatformDeviceSkia::BeginPlatformPaint() {
-  // Even when drawing a vector representation of the page, we have to
-  // provide a raster surface for plugins to render into - they don't have
-  // a vector interface.  Therefore we create a BitmapPlatformDevice here
-  // and return the context from it, then layer on the raster data as an
-  // image in EndPlatformPaint.
-  DCHECK(raster_surface_ == NULL);
-  raster_surface_ = skia::AdoptRef(
-      BitmapPlatformDevice::CreateAndClear(width(), height(), false));
-  return raster_surface_->BeginPlatformPaint();
-}
-
-void VectorPlatformDeviceSkia::EndPlatformPaint() {
-  DCHECK(raster_surface_ != NULL);
-  SkPaint paint;
-  // SkPDFDevice checks the passed SkDraw for an empty clip (only).  Fake
-  // it out by setting a non-empty clip.
-  SkDraw draw;
-  SkRegion clip(SkIRect::MakeWH(width(), height()));
-  draw.fClip=&clip;
-  drawSprite(draw, raster_surface_->accessBitmap(false), 0, 0, paint);
-  // BitmapPlatformDevice matches begin and end calls.
-  raster_surface_->EndPlatformPaint();
-  raster_surface_.clear();
-}
-
-#if defined(OS_WIN)
-void VectorPlatformDeviceSkia::DrawToNativeContext(HDC dc,
-                                                   int x,
-                                                   int y,
-                                                   const RECT* src_rect) {
-  SkASSERT(false);
-}
-#elif defined(OS_MACOSX)
-void VectorPlatformDeviceSkia::DrawToNativeContext(CGContext* context, int x,
-    int y, const CGRect* src_rect) {
-  SkASSERT(false);
-}
-
-CGContextRef VectorPlatformDeviceSkia::GetBitmapContext() {
-  SkASSERT(false);
-  return NULL;
-}
-#elif defined(OS_POSIX)
-void VectorPlatformDeviceSkia::DrawToNativeContext(
-    PlatformSurface surface, int x, int y, const PlatformRect* src_rect) {
-  // Should never be called on Linux.
-  SkASSERT(false);
-}
-#endif
-
-}  // namespace skia
diff --git a/skia/ext/vector_platform_device_skia.h b/skia/ext/vector_platform_device_skia.h
deleted file mode 100644
index 528eac9..0000000
--- a/skia/ext/vector_platform_device_skia.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SKIA_EXT_VECTOR_PLATFORM_DEVICE_SKIA_H_
-#define SKIA_EXT_VECTOR_PLATFORM_DEVICE_SKIA_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "skia/ext/platform_device.h"
-#include "skia/ext/refptr.h"
-#include "third_party/skia/include/pdf/SkPDFDevice.h"
-
-class SkMatrix;
-
-namespace skia {
-
-class BitmapPlatformDevice;
-
-class VectorPlatformDeviceSkia : public SkPDFDevice, public PlatformDevice {
- public:
-  SK_API VectorPlatformDeviceSkia(const SkISize& pageSize,
-                                  const SkISize& contentSize,
-                                  const SkMatrix& initialTransform);
-  ~VectorPlatformDeviceSkia() override;
-
-  // PlatformDevice methods.
-  bool SupportsPlatformPaint() override;
-
-  PlatformSurface BeginPlatformPaint() override;
-  void EndPlatformPaint() override;
-#if defined(OS_WIN)
-  virtual void DrawToNativeContext(HDC dc,
-                                   int x,
-                                   int y,
-                                   const RECT* src_rect) override;
-#elif defined(OS_MACOSX)
-  void DrawToNativeContext(CGContext* context,
-                           int x,
-                           int y,
-                           const CGRect* src_rect) override;
-  CGContextRef GetBitmapContext() override;
-#elif defined(OS_POSIX)
-  virtual void DrawToNativeContext(PlatformSurface surface,
-                                   int x,
-                                   int y,
-                                   const PlatformRect* src_rect) override;
-#endif
-
- private:
-  skia::RefPtr<BitmapPlatformDevice> raster_surface_;
-
-  DISALLOW_COPY_AND_ASSIGN(VectorPlatformDeviceSkia);
-};
-
-}  // namespace skia
-
-#endif  // SKIA_EXT_VECTOR_PLATFORM_DEVICE_SKIA_H_
diff --git a/skia/skia_chrome.gypi b/skia/skia_chrome.gypi
index 0f97556..7db9009 100644
--- a/skia/skia_chrome.gypi
+++ b/skia/skia_chrome.gypi
@@ -83,8 +83,6 @@
     'ext/vector_canvas.h',
     'ext/vector_platform_device_emf_win.cc',
     'ext/vector_platform_device_emf_win.h',
-    'ext/vector_platform_device_skia.cc',
-    'ext/vector_platform_device_skia.h',
   ],
   'conditions': [
     [ 'OS == "android" and '
@@ -93,15 +91,7 @@
         'ext/skia_utils_base.cc',
       ],
     }],
-    [ 'enable_basic_printing==0 and enable_print_preview==0', {
-      'sources!': [
-        'ext/vector_platform_device_skia.cc',
-      ],
-    }],
     ['OS == "ios"', {
-      'sources/': [
-        ['exclude', '^ext/vector_platform_device_skia\\.'],
-      ],
       'dependencies!': [
         'skia_chrome_opts',
       ],
diff --git a/sky/engine/core/css/CSSFontSelector.cpp b/sky/engine/core/css/CSSFontSelector.cpp
index cd8faa2..8a18163 100644
--- a/sky/engine/core/css/CSSFontSelector.cpp
+++ b/sky/engine/core/css/CSSFontSelector.cpp
@@ -97,15 +97,15 @@
 
 static AtomicString familyNameFromSettings(const GenericFontFamilySettings& settings, const FontDescription& fontDescription, const AtomicString& genericFamilyName)
 {
-    UScriptCode script = fontDescription.script();
-
 #if OS(ANDROID)
     if (fontDescription.genericFamily() == FontDescription::StandardFamily)
-        return FontCache::getGenericFamilyNameForScript(FontFamilyNames::webkit_standard, script);
+        return FontCache::getGenericFamilyNameForScript(FontFamilyNames::webkit_standard, fontDescription);
 
     if (genericFamilyName.startsWith("-webkit-"))
-        return FontCache::getGenericFamilyNameForScript(genericFamilyName, script);
+        return FontCache::getGenericFamilyNameForScript(genericFamilyName, fontDescription);
 #else
+    UScriptCode script = fontDescription.script();
+
     if (fontDescription.genericFamily() == FontDescription::StandardFamily)
         return settings.standard(script);
     if (genericFamilyName == FontFamilyNames::webkit_serif)
diff --git a/sky/engine/platform/fonts/FontCache.h b/sky/engine/platform/fonts/FontCache.h
index e68a6cc..c41c6ad 100644
--- a/sky/engine/platform/fonts/FontCache.h
+++ b/sky/engine/platform/fonts/FontCache.h
@@ -94,7 +94,7 @@
 #endif
 
 #if OS(ANDROID)
-    static AtomicString getGenericFamilyNameForScript(const AtomicString& familyName, UScriptCode);
+    static AtomicString getGenericFamilyNameForScript(const AtomicString& familyName, const FontDescription&);
 #else
     struct PlatformFallbackFont {
         String name;
diff --git a/sky/engine/platform/fonts/android/FontCacheAndroid.cpp b/sky/engine/platform/fonts/android/FontCacheAndroid.cpp
index 8f070e8..25c4c75 100644
--- a/sky/engine/platform/fonts/android/FontCacheAndroid.cpp
+++ b/sky/engine/platform/fonts/android/FontCacheAndroid.cpp
@@ -31,7 +31,7 @@
 #include "config.h"
 #include "platform/fonts/FontCache.h"
 
-
+#include "platform/Language.h"
 #include "platform/fonts/SimpleFontData.h"
 #include "platform/fonts/FontDescription.h"
 #include "platform/fonts/FontFaceCreationParams.h"
@@ -40,31 +40,19 @@
 
 namespace blink {
 
-static AtomicString getFamilyNameForCharacter(UChar32 c, UScriptCode script)
+static AtomicString getFamilyNameForCharacter(UChar32 c, const FontDescription& fontDescription)
 {
-    // This is a hack to use the preferred font for CJK scripts.
-    // FIXME: Use new Skia API once Android system supports per-family and per-script fallback fonts.
-    const char* locale;
-    switch (script) {
-    case USCRIPT_SIMPLIFIED_HAN:
-        locale = "zh-CN";
-        break;
-    case USCRIPT_TRADITIONAL_HAN:
-        locale = "zh-TW";
-        break;
-    case USCRIPT_KATAKANA_OR_HIRAGANA:
-        locale = "ja";
-        break;
-    case USCRIPT_HANGUL:
-        locale = "ko";
-        break;
-    default:
-        locale = 0;
-        break;
-    }
-
     RefPtr<SkFontMgr> fm = adoptRef(SkFontMgr::RefDefault());
-    RefPtr<SkTypeface> typeface = adoptRef(fm->matchFamilyStyleCharacter(0, SkFontStyle(), locale, c));
+    const char* bcp47Locales[2];
+    int localeCount = 0;
+    CString defaultLocale = defaultLanguage().ascii();
+    bcp47Locales[localeCount++] = defaultLocale.data();
+    CString fontLocale;
+    if (!fontDescription.locale().isEmpty()) {
+        fontLocale = fontDescription.locale().ascii();
+        bcp47Locales[localeCount++] = fontLocale.data();
+    }
+    RefPtr<SkTypeface> typeface = adoptRef(fm->matchFamilyStyleCharacter(0, SkFontStyle(), bcp47Locales, localeCount, c));
     if (!typeface)
         return emptyAtom;
 
@@ -75,19 +63,19 @@
 
 PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*)
 {
-    AtomicString familyName = getFamilyNameForCharacter(c, fontDescription.script());
+    AtomicString familyName = getFamilyNameForCharacter(c, fontDescription);
     if (familyName.isEmpty())
         return getLastResortFallbackFont(fontDescription, DoNotRetain);
     return fontDataFromFontPlatformData(getFontPlatformData(fontDescription, FontFaceCreationParams(familyName)), DoNotRetain);
 }
 
 // static
-AtomicString FontCache::getGenericFamilyNameForScript(const AtomicString& familyName, UScriptCode script)
+AtomicString FontCache::getGenericFamilyNameForScript(const AtomicString& familyName, const FontDescription& fontDescription)
 {
     // This is a hack to use the preferred font for CJK scripts.
     // FIXME: Use new Skia API once Android system supports per-family and per-script fallback fonts.
     UChar32 examplerChar;
-    switch (script) {
+    switch (fontDescription.script()) {
     case USCRIPT_SIMPLIFIED_HAN:
     case USCRIPT_TRADITIONAL_HAN:
     case USCRIPT_KATAKANA_OR_HIRAGANA:
@@ -101,7 +89,7 @@
         return familyName;
     }
 
-    return getFamilyNameForCharacter(examplerChar, script);
+    return getFamilyNameForCharacter(examplerChar, fontDescription);
 }
 
 } // namespace blink
diff --git a/sky/viewer/platform/weblayertreeview_impl.cc b/sky/viewer/platform/weblayertreeview_impl.cc
index 2aa5486..f718fc3 100644
--- a/sky/viewer/platform/weblayertreeview_impl.cc
+++ b/sky/viewer/platform/weblayertreeview_impl.cc
@@ -7,6 +7,7 @@
 #include "base/message_loop/message_loop_proxy.h"
 #include "cc/layers/layer.h"
 #include "cc/output/begin_frame_args.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/trees/layer_tree_host.h"
 #include "mojo/cc/context_provider_mojo.h"
 #include "mojo/cc/output_surface_mojo.h"
@@ -47,7 +48,8 @@
                                         gpu_memory_buffer_manager,
                                         settings,
                                         base::MessageLoopProxy::current(),
-                                        compositor_message_loop_proxy);
+                                        compositor_message_loop_proxy,
+                                        nullptr);
   DCHECK(layer_tree_host_);
 }
 
diff --git a/testing/android/java/AndroidManifest.xml b/testing/android/java/AndroidManifest.xml
index c704cc4..a561f0c 100644
--- a/testing/android/java/AndroidManifest.xml
+++ b/testing/android/java/AndroidManifest.xml
@@ -24,6 +24,10 @@
         </activity>
     </application>
 
+    <instrumentation android:name="org.chromium.native_test.ChromiumNativeTestInstrumentationTestRunner"
+            android:targetPackage="org.chromium.native_test"
+            android:label="Instrumentation entry point for org.chromium.native_test"/>
+
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
diff --git a/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
index f5d381a..42befe5 100644
--- a/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
+++ b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
@@ -22,6 +22,11 @@
  *  the native activity class loader.
  */
 public class ChromeNativeTestActivity extends Activity {
+    public static final String EXTRA_COMMAND_LINE_FILE =
+            "org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile";
+    public static final String EXTRA_COMMAND_LINE_FLAGS =
+            "org.chromium.native_test.ChromeNativeTestActivity.CommandLineFlags";
+
     private static final String TAG = "ChromeNativeTestActivity";
     private static final String EXTRA_RUN_IN_SUB_THREAD = "RunInSubThread";
     // We post a delayed task to run tests so that we do not block onCreate().
@@ -66,8 +71,15 @@
     }
 
     private void runTests() {
+        String commandLineFlags = getIntent().getStringExtra(EXTRA_COMMAND_LINE_FLAGS);
+        if (commandLineFlags == null) commandLineFlags = "";
+
+        String commandLineFilePath = getIntent().getStringExtra(EXTRA_COMMAND_LINE_FILE);
+        if (commandLineFilePath == null) commandLineFilePath = "";
+
         // This directory is used by build/android/pylib/test_package_apk.py.
-        nativeRunTests(getFilesDir().getAbsolutePath(), getApplicationContext());
+        nativeRunTests(commandLineFlags, commandLineFilePath, getFilesDir().getAbsolutePath(),
+                getApplicationContext());
     }
 
     // Signal a failure of the native test loader to python scripts
@@ -85,5 +97,6 @@
         }
     }
 
-    private native void nativeRunTests(String filesDir, Context appContext);
+    private native void nativeRunTests(String commandLineFlags, String commandLineFilePath,
+            String filesDir, Context appContext);
 }
diff --git a/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java b/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java
new file mode 100644
index 0000000..5e8d8e5
--- /dev/null
+++ b/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java
@@ -0,0 +1,196 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.native_test;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *  An Instrumentation that runs tests based on ChromeNativeTestActivity.
+ */
+public class ChromiumNativeTestInstrumentationTestRunner extends Instrumentation {
+
+    private static final String TAG = "ChromiumNativeTestInstrumentationTestRunner";
+    private static final Pattern RE_TEST_OUTPUT = Pattern.compile("\\[ *([^ ]*) *\\] ?([^ ]*) .*");
+
+    private static interface ResultsBundleGenerator {
+        public Bundle generate(Map<String, TestResult> rawResults);
+    }
+
+    private String mCommandLineFile;
+    private String mCommandLineFlags;
+    private Bundle mLogBundle;
+    private ResultsBundleGenerator mBundleGenerator;
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        mCommandLineFile = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE);
+        mCommandLineFlags = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FLAGS);
+        mLogBundle = new Bundle();
+        mBundleGenerator = new RobotiumBundleGenerator();
+        start();
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        Bundle results = runTests();
+        finish(Activity.RESULT_OK, results);
+    }
+
+    /** Runs the tests in the ChromeNativeTestActivity and returns a Bundle containing the results.
+     */
+    private Bundle runTests() {
+        Log.i(TAG, "Creating activity.");
+        Activity activityUnderTest = startNativeTestActivity();
+
+        Log.i(TAG, "Getting results from FIFO.");
+        Map<String, TestResult> results = parseResultsFromFifo(activityUnderTest);
+
+        Log.i(TAG, "Finishing activity.");
+        activityUnderTest.finish();
+
+        Log.i(TAG, "Parsing results and generating output.");
+        return mBundleGenerator.generate(results);
+    }
+
+    /** Starts the ChromeNativeTestActivty.
+     */
+    private Activity startNativeTestActivity() {
+        Intent i = new Intent(Intent.ACTION_MAIN);
+        i.setComponent(new ComponentName(
+                "org.chromium.native_test",
+                "org.chromium.native_test.ChromeNativeTestActivity"));
+        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        if (mCommandLineFile != null) {
+            Log.i(TAG, "Passing command line file extra: " + mCommandLineFile);
+            i.putExtra(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE, mCommandLineFile);
+        }
+        if (mCommandLineFlags != null) {
+            Log.i(TAG, "Passing command line flag extra: " + mCommandLineFlags);
+            i.putExtra(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FLAGS, mCommandLineFlags);
+        }
+        return startActivitySync(i);
+    }
+
+    private static enum TestResult {
+        PASSED, FAILED, ERROR, UNKNOWN
+    }
+
+    /**
+     *  Generates a map between test names and test results from the instrumented Activity's FIFO.
+     */
+    private Map<String, TestResult> parseResultsFromFifo(Activity activityUnderTest) {
+        Map<String, TestResult> results = new HashMap<String, TestResult>();
+
+        File fifo = null;
+        BufferedReader r = null;
+
+        try {
+            // Wait for the test to create the FIFO.
+            fifo = new File(getTargetContext().getFilesDir().getAbsolutePath(), "test.fifo");
+            while (!fifo.exists()) {
+                Thread.sleep(1000);
+            }
+
+            r = new BufferedReader(
+                    new InputStreamReader(new BufferedInputStream(new FileInputStream(fifo))));
+
+            StringBuilder resultsStr = new StringBuilder();
+            for (String l = r.readLine(); l != null && !l.equals("<<ScopedMainEntryLogger");
+                    l = r.readLine()) {
+                Matcher m = RE_TEST_OUTPUT.matcher(l);
+                if (m.matches()) {
+                    if (m.group(1).equals("RUN")) {
+                        results.put(m.group(2), TestResult.UNKNOWN);
+                    } else if (m.group(1).equals("FAILED")) {
+                        results.put(m.group(2), TestResult.FAILED);
+                    } else if (m.group(1).equals("OK")) {
+                        results.put(m.group(2), TestResult.PASSED);
+                    }
+                }
+                resultsStr.append(l);
+                resultsStr.append("\n");
+            }
+            mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, resultsStr.toString());
+            sendStatus(0, mLogBundle);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted while waiting for FIFO file creation: " + e.toString());
+        } catch (FileNotFoundException e) {
+            Log.e(TAG, "Couldn't find FIFO file: " + e.toString());
+        } catch (IOException e) {
+            Log.e(TAG, "Error handling FIFO file: " + e.toString());
+        } finally {
+            if (r != null) {
+                try {
+                    r.close();
+                } catch (IOException e) {
+                    Log.e(TAG, "Error while closing FIFO reader.");
+                }
+            }
+            if (fifo != null) {
+                if (!fifo.delete()) {
+                    Log.e(TAG, "Unable to delete " + fifo.getAbsolutePath());
+                }
+            }
+        }
+        return results;
+    }
+
+    /**
+     * Creates a results bundle that emulates the one created by Robotium.
+     */
+    private static class RobotiumBundleGenerator implements ResultsBundleGenerator {
+        public Bundle generate(Map<String, TestResult> rawResults) {
+            Bundle resultsBundle = new Bundle();
+
+            int testsPassed = 0;
+            int testsFailed = 0;
+
+            for (Map.Entry<String, TestResult> entry : rawResults.entrySet()) {
+                switch (entry.getValue()) {
+                    case PASSED:
+                        ++testsPassed;
+                        break;
+                    case FAILED:
+                        ++testsFailed;
+                        break;
+                    default:
+                        Log.w(TAG, "Unhandled: " + entry.getKey() + ", "
+                                + entry.getValue().toString());
+                        break;
+                }
+            }
+
+            StringBuilder resultBuilder = new StringBuilder();
+            resultBuilder.append("\nOK (" + Integer.toString(testsPassed) + " tests)");
+            if (testsFailed > 0) {
+                resultBuilder.append(
+                        "\nFAILURES!!! Tests run: " + Integer.toString(rawResults.size())
+                        + ", Failures: " + Integer.toString(testsFailed) + ", Errors: 0");
+            }
+            resultsBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                    resultBuilder.toString());
+            return resultsBundle;
+        }
+    }
+
+}
diff --git a/testing/android/native_test_launcher.cc b/testing/android/native_test_launcher.cc
index 63e389a..b7c9d28 100644
--- a/testing/android/native_test_launcher.cc
+++ b/testing/android/native_test_launcher.cc
@@ -30,6 +30,7 @@
 
 using testing::native_test_util::ArgsToArgv;
 using testing::native_test_util::ParseArgsFromCommandLineFile;
+using testing::native_test_util::ParseArgsFromString;
 using testing::native_test_util::ScopedMainEntryLogger;
 
 // The main function of the program to be wrapped as a test apk.
@@ -117,6 +118,8 @@
 
 static void RunTests(JNIEnv* env,
                      jobject obj,
+                     jstring jcommand_line_flags,
+                     jstring jcommand_line_file_path,
                      jstring jfiles_dir,
                      jobject app_context) {
   base::AtExitManager exit_manager;
@@ -132,7 +135,17 @@
   base::android::RegisterJni(env);
 
   std::vector<std::string> args;
-  ParseArgsFromCommandLineFile(kCommandLineFilePath, &args);
+
+  const std::string command_line_file_path(
+      base::android::ConvertJavaStringToUTF8(env, jcommand_line_file_path));
+  if (command_line_file_path.empty())
+    ParseArgsFromCommandLineFile(kCommandLineFilePath, &args);
+  else
+    ParseArgsFromCommandLineFile(command_line_file_path.c_str(), &args);
+
+  const std::string command_line_flags(
+      base::android::ConvertJavaStringToUTF8(env, jcommand_line_flags));
+  ParseArgsFromString(command_line_flags, &args);
 
   std::vector<char*> argv;
   int argc = ArgsToArgv(args, &argv);
diff --git a/testing/android/native_test_util.cc b/testing/android/native_test_util.cc
index 98f32c7..885f297 100644
--- a/testing/android/native_test_util.cc
+++ b/testing/android/native_test_util.cc
@@ -9,7 +9,8 @@
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/string_util.h"
 
-namespace {
+namespace testing {
+namespace native_test_util {
 
 void ParseArgsFromString(const std::string& command_line,
                          std::vector<std::string>* args) {
@@ -22,11 +23,6 @@
   }
 }
 
-}  // namespace
-
-namespace testing {
-namespace native_test_util {
-
 void ParseArgsFromCommandLineFile(
     const char* path, std::vector<std::string>* args) {
   base::FilePath command_line(path);
diff --git a/testing/android/native_test_util.h b/testing/android/native_test_util.h
index a756739..ef17e52 100644
--- a/testing/android/native_test_util.h
+++ b/testing/android/native_test_util.h
@@ -27,6 +27,8 @@
   }
 };
 
+void ParseArgsFromString(
+    const std::string& command_line, std::vector<std::string>* args);
 void ParseArgsFromCommandLineFile(
     const char* path, std::vector<std::string>* args);
 int ArgsToArgv(const std::vector<std::string>& args, std::vector<char*>* argv);
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 2595ad8..d763318 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -61,7 +61,7 @@
         "test": "sandbox_linux_unittests",
         "args": ["--test-launcher-print-test-stdio=always"]
       },
-      "ui_unittests",
+      "ui_base_unittests",
       "views_unittests",
       "wm_unittests",
       "aura_unittests",
@@ -133,7 +133,7 @@
       },
       "sql_unittests",
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       "unit_tests",
       "url_unittests",
       "views_unittests",
@@ -180,7 +180,7 @@
         "test": "sandbox_linux_unittests",
         "args": ["--test-launcher-print-test-stdio=always"]
       },
-      "ui_unittests",
+      "ui_base_unittests",
       "views_unittests",
       "wm_unittests",
       "aura_unittests",
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index c1c7be4..c9869f7 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -32,7 +32,7 @@
       "printing_unittests",
       "remoting_unittests",
       "sandbox_linux_unittests",
-      "ui_unittests",
+      "ui_base_unittests",
       "ipc_tests",
       "sync_unit_tests",
       "unit_tests",
@@ -98,7 +98,7 @@
       "printing_unittests",
       "remoting_unittests",
       "sandbox_linux_unittests",
-      "ui_unittests",
+      "ui_base_unittests",
       "ipc_tests",
       "sync_unit_tests",
       "unit_tests",
@@ -164,7 +164,7 @@
       "printing_unittests",
       "remoting_unittests",
       "sandbox_linux_unittests",
-      "ui_unittests",
+      "ui_base_unittests",
       "ipc_tests",
       "sync_unit_tests",
       "unit_tests",
@@ -230,7 +230,7 @@
       "printing_unittests",
       "remoting_unittests",
       "sandbox_linux_unittests",
-      "ui_unittests",
+      "ui_base_unittests",
       "ipc_tests",
       "sync_unit_tests",
       "unit_tests",
@@ -308,7 +308,7 @@
       "sql_unittests",
       "sync_integration_tests",
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       "unit_tests",
       "url_unittests",
       "browser_tests"
@@ -400,7 +400,7 @@
       "sandbox_linux_unittests",
       "sql_unittests",
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       "unit_tests",
       "url_unittests",
       "views_unittests",
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 4fa07e6..850beb4 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -75,7 +75,7 @@
       "remoting_unittests",
       "sandbox_linux_unittests",
       "sql_unittests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "sync_integration_tests",
         "swarming": {
@@ -184,7 +184,7 @@
       "remoting_unittests",
       "sandbox_linux_unittests",
       "sql_unittests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "sync_integration_tests",
         "swarming": {
@@ -289,7 +289,7 @@
         "args": ["--test-launcher-print-test-stdio=always"]
       },
       "sql_unittests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "sync_integration_tests",
         "swarming": {
@@ -346,7 +346,7 @@
       "sandbox_linux_unittests",
       "sql_unittests",
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       "unit_tests"
     ]
   }
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index c1bdf11..cff26cd 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -73,7 +73,7 @@
         }
       },
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "unit_tests",
         "swarming": {
@@ -171,7 +171,7 @@
         }
       },
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "unit_tests",
         "swarming": {
@@ -269,7 +269,7 @@
         }
       },
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "unit_tests",
         "swarming": {
@@ -360,7 +360,7 @@
         }
       },
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "unit_tests",
         "swarming": {
diff --git a/testing/buildbot/chromium.memory.fyi.json b/testing/buildbot/chromium.memory.fyi.json
index adc4165..577ff7d 100644
--- a/testing/buildbot/chromium.memory.fyi.json
+++ b/testing/buildbot/chromium.memory.fyi.json
@@ -42,7 +42,7 @@
       "sandbox_linux_unittests",
       "sql_unittests",
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       "unit_tests",
       "url_unittests",
       "views_unittests",
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 1216d6e..8f72e65 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -62,7 +62,7 @@
       "sandbox_linux_unittests",
       "sql_unittests",
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "unit_tests",
         "swarming": {
@@ -150,7 +150,7 @@
       "remoting_unittests",
       "sql_unittests",
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       "url_unittests"
     ]
   },
@@ -211,7 +211,7 @@
       "remoting_unittests",
       "sql_unittests",
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "unit_tests",
         "swarming": {
@@ -303,7 +303,7 @@
           "shards": 2
         }
       },
-      "ui_unittests",
+      "ui_base_unittests",
       "url_unittests",
       "views_unittests"
     ]
diff --git a/testing/buildbot/chromium.webkit.json b/testing/buildbot/chromium.webkit.json
index b121217..434d369 100644
--- a/testing/buildbot/chromium.webkit.json
+++ b/testing/buildbot/chromium.webkit.json
@@ -58,7 +58,7 @@
       "printing_unittests",
       "remoting_unittests",
       "sandbox_linux_unittests",
-      "ui_unittests",
+      "ui_base_unittests",
       "views_unittests",
       "wm_unittests",
       "aura_unittests",
@@ -124,7 +124,7 @@
       "printing_unittests",
       "remoting_unittests",
       "sandbox_linux_unittests",
-      "ui_unittests",
+      "ui_base_unittests",
       "views_unittests",
       "wm_unittests",
       "aura_unittests",
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index d8c9672..0910b9f 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -82,7 +82,7 @@
           "can_use_on_swarming_builders": true
         }
       },
-      "ui_unittests",
+      "ui_base_unittests",
       "url_unittests",
       "views_unittests",
       "wm_unittests"
@@ -191,7 +191,7 @@
           "can_use_on_swarming_builders": true
         }
       },
-      "ui_unittests",
+      "ui_base_unittests",
       "url_unittests",
       "views_unittests",
       "wm_unittests"
@@ -209,6 +209,7 @@
   },
   "Win7 Tests (1)": {
     "gtest_tests": [
+      "app_installer_unittests",
       "accessibility_unittests",
       {
         "test": "ash_unittests",
@@ -296,7 +297,7 @@
         }
       },
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "unit_tests",
         "swarming": {
@@ -402,7 +403,7 @@
       },
       "sql_unittests",
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "unit_tests",
         "swarming": {
@@ -513,7 +514,7 @@
         }
       },
       "sync_unit_tests",
-      "ui_unittests",
+      "ui_base_unittests",
       {
         "test": "unit_tests",
         "swarming": {
diff --git a/testing/buildbot/chromium_memory_trybot.json b/testing/buildbot/chromium_memory_trybot.json
index 161071d..357735f 100644
--- a/testing/buildbot/chromium_memory_trybot.json
+++ b/testing/buildbot/chromium_memory_trybot.json
@@ -65,7 +65,7 @@
     },
     "sql_unittests",
     "sync_unit_tests",
-    "ui_unittests",
+    "ui_base_unittests",
     {
       "test": "unit_tests",
       "swarming": {
diff --git a/testing/buildbot/chromium_trybot.json b/testing/buildbot/chromium_trybot.json
index 9c7f5c9..6e3cff5 100644
--- a/testing/buildbot/chromium_trybot.json
+++ b/testing/buildbot/chromium_trybot.json
@@ -4,6 +4,10 @@
   ],
   "gtest_tests": [
     "accessibility_unittests",
+    {
+      "test": "app_installer_unittests",
+      "platforms": ["win"]
+    },
     "app_list_unittests",
     {
       "test": "ash_unittests",
@@ -33,7 +37,7 @@
       "test": "browser_tests",
       "swarming": {
         "can_use_on_swarming_builders": true,
-        "shards": 5
+        "shards": 8
       }
     },
     "cacheinvalidation_unittests",
@@ -153,7 +157,7 @@
       }
     },
     "sync_unit_tests",
-    "ui_unittests",
+    "ui_base_unittests",
     {
       "test": "unit_tests",
       "swarming": {
diff --git a/testing/chromoting/browser_test_commands_linux.txt b/testing/chromoting/browser_test_commands_linux.txt
index af64c09..3b6a61b 100644
--- a/testing/chromoting/browser_test_commands_linux.txt
+++ b/testing/chromoting/browser_test_commands_linux.txt
@@ -1,4 +1,6 @@
 /usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp --extension-name=Chromoting
 /usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
 /usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gafyd
-/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail
\ No newline at end of file
+/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail
+/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp.v2 --extension-name=Chromoting
+/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=20000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
diff --git a/testing/chromoting/browser_tests_launcher.py b/testing/chromoting/browser_tests_launcher.py
index 66b54fe..8f4bba1 100644
--- a/testing/chromoting/browser_tests_launcher.py
+++ b/testing/chromoting/browser_tests_launcher.py
@@ -14,14 +14,14 @@
 
   cmd_line = [command]
   try:
-    results = subprocess.check_output(
-        cmd_line, stderr=subprocess.STDOUT, shell=True)
+    p = subprocess.Popen(cmd_line, stdout=subprocess.PIPE, shell=True)
+    results, err = p.communicate()
+    if 'SUCCESS: all tests passed.' not in results:
+      raise Exception('Test failed\n%s\n%s' % (results, err))
   except subprocess.CalledProcessError, e:
     raise Exception('Exception %s running command %s' % (e, command))
   else:
     print results
-  finally:
-    pass
 
 
 def main():
diff --git a/testing/chromoting/chromoting_integration_tests.isolate b/testing/chromoting/chromoting_integration_tests.isolate
index db21d82..cdfd8c4 100644
--- a/testing/chromoting/chromoting_integration_tests.isolate
+++ b/testing/chromoting/chromoting_integration_tests.isolate
@@ -16,7 +16,6 @@
           '../xvfb.py',
           './browser_tests_launcher.py',
           './browser_test_commands_linux.txt',
-          '../../remoting/tools/internal/test_accounts.json',
           '<(PRODUCT_DIR)/libffmpegsumo.so',
           '<(PRODUCT_DIR)/libosmesa.so',
           '<(PRODUCT_DIR)/nacl_irt_x86_64.nexe',
@@ -36,7 +35,9 @@
           '../test_env.py',
           '<(PRODUCT_DIR)/browser_tests<(EXECUTABLE_SUFFIX)',
           '<(PRODUCT_DIR)/remoting/remoting.webapp/',
+          '<(PRODUCT_DIR)/remoting/remoting.webapp.v2/',
           '<(PRODUCT_DIR)/resources.pak',
+          '../../remoting/tools/internal/test_accounts.json',          
         ],
         'read_only': 1,
       },
@@ -83,4 +84,4 @@
   'includes': [
     '../../base/base.isolate',
   ],
-}
+}
\ No newline at end of file
diff --git a/testing/chromoting/integration_tests.gyp b/testing/chromoting/integration_tests.gyp
index 23fcf6f..78c1368 100644
--- a/testing/chromoting/integration_tests.gyp
+++ b/testing/chromoting/integration_tests.gyp
@@ -20,6 +20,13 @@
           'sources': [
             'chromoting_integration_tests.isolate',
           ],
+          'conditions': [
+            ['OS=="linux"', {
+              'dependencies': [
+                '../../remoting/remoting.gyp:remoting_me2me_host_archive',
+              ],
+            }],  # OS=="linux"
+          ],          
         },
       ],
     }],
diff --git a/testing/iossim/iossim.mm b/testing/iossim/iossim.mm
index 5eaed5c..83cfe92 100644
--- a/testing/iossim/iossim.mm
+++ b/testing/iossim/iossim.mm
@@ -504,13 +504,22 @@
           [NSCharacterSet newlineCharacterSet]];
       NSString* simulatedAppPID =
           [NSString stringWithFormat:@"%d", session.simulatedApplicationPID];
+      NSArray* kErrorStrings = @[
+        @"Service exited with abnormal code:",
+        @"Service exited due to signal:",
+      ];
       for (NSString* line in lines) {
-        NSString* const kErrorString = @"Service exited with abnormal code:";
-        if ([line rangeOfString:kErrorString].location != NSNotFound &&
-            [line rangeOfString:simulatedAppPID].location != NSNotFound) {
-          LogWarning(@"Console message: %@", line);
-          badEntryFound = YES;
-          break;
+        if ([line rangeOfString:simulatedAppPID].location != NSNotFound) {
+          for (NSString* errorString in kErrorStrings) {
+            if ([line rangeOfString:errorString].location != NSNotFound) {
+              LogWarning(@"Console message: %@", line);
+              badEntryFound = YES;
+              break;
+            }
+          }
+          if (badEntryFound) {
+            break;
+          }
         }
       }
       // Remove the log file so subsequent invocations of iossim won't be
diff --git a/third_party/boringssl/boringssl_tests.gypi b/third_party/boringssl/boringssl_tests.gypi
index 3f7cd53..cf2aff4 100644
--- a/third_party/boringssl/boringssl_tests.gypi
+++ b/third_party/boringssl/boringssl_tests.gypi
@@ -85,6 +85,19 @@
       'msvs_disabled_warnings': [ 4267, ],
     },
     {
+      'target_name': 'boringssl_constant_time_test',
+      'type': 'executable',
+      'dependencies': [
+        'boringssl.gyp:boringssl',
+      ],
+      'sources': [
+        'src/crypto/constant_time_test.c',
+      ],
+      # TODO(davidben): Fix size_t truncations in BoringSSL.
+      # https://crbug.com/429039
+      'msvs_disabled_warnings': [ 4267, ],
+    },
+    {
       'target_name': 'boringssl_dh_test',
       'type': 'executable',
       'dependencies': [
@@ -98,6 +111,19 @@
       'msvs_disabled_warnings': [ 4267, ],
     },
     {
+      'target_name': 'boringssl_digest_test',
+      'type': 'executable',
+      'dependencies': [
+        'boringssl.gyp:boringssl',
+      ],
+      'sources': [
+        'src/crypto/digest/digest_test.c',
+      ],
+      # TODO(davidben): Fix size_t truncations in BoringSSL.
+      # https://crbug.com/429039
+      'msvs_disabled_warnings': [ 4267, ],
+    },
+    {
       'target_name': 'boringssl_dsa_test',
       'type': 'executable',
       'dependencies': [
@@ -111,6 +137,19 @@
       'msvs_disabled_warnings': [ 4267, ],
     },
     {
+      'target_name': 'boringssl_ec_test',
+      'type': 'executable',
+      'dependencies': [
+        'boringssl.gyp:boringssl',
+      ],
+      'sources': [
+        'src/crypto/ec/ec_test.c',
+      ],
+      # TODO(davidben): Fix size_t truncations in BoringSSL.
+      # https://crbug.com/429039
+      'msvs_disabled_warnings': [ 4267, ],
+    },
+    {
       'target_name': 'boringssl_example_mul',
       'type': 'executable',
       'dependencies': [
@@ -189,19 +228,6 @@
       'msvs_disabled_warnings': [ 4267, ],
     },
     {
-      'target_name': 'boringssl_md5_test',
-      'type': 'executable',
-      'dependencies': [
-        'boringssl.gyp:boringssl',
-      ],
-      'sources': [
-        'src/crypto/md5/md5_test.c',
-      ],
-      # TODO(davidben): Fix size_t truncations in BoringSSL.
-      # https://crbug.com/429039
-      'msvs_disabled_warnings': [ 4267, ],
-    },
-    {
       'target_name': 'boringssl_gcm_test',
       'type': 'executable',
       'dependencies': [
@@ -241,19 +267,6 @@
       'msvs_disabled_warnings': [ 4267, ],
     },
     {
-      'target_name': 'boringssl_sha1_test',
-      'type': 'executable',
-      'dependencies': [
-        'boringssl.gyp:boringssl',
-      ],
-      'sources': [
-        'src/crypto/sha/sha1_test.c',
-      ],
-      # TODO(davidben): Fix size_t truncations in BoringSSL.
-      # https://crbug.com/429039
-      'msvs_disabled_warnings': [ 4267, ],
-    },
-    {
       'target_name': 'boringssl_pkcs7_test',
       'type': 'executable',
       'dependencies': [
@@ -301,8 +314,11 @@
       'boringssl_bn_test',
       'boringssl_bytestring_test',
       'boringssl_cipher_test',
+      'boringssl_constant_time_test',
       'boringssl_dh_test',
+      'boringssl_digest_test',
       'boringssl_dsa_test',
+      'boringssl_ec_test',
       'boringssl_ecdsa_test',
       'boringssl_err_test',
       'boringssl_evp_test',
@@ -310,12 +326,10 @@
       'boringssl_gcm_test',
       'boringssl_hmac_test',
       'boringssl_lhash_test',
-      'boringssl_md5_test',
       'boringssl_pkcs12_test',
       'boringssl_pkcs7_test',
       'boringssl_pqueue_test',
       'boringssl_rsa_test',
-      'boringssl_sha1_test',
       'boringssl_ssl_test',
     ],
   }
diff --git a/third_party/boringssl/boringssl_unittest.cc b/third_party/boringssl/boringssl_unittest.cc
index 1a62cac..6d54ad2 100644
--- a/third_party/boringssl/boringssl_unittest.cc
+++ b/third_party/boringssl/boringssl_unittest.cc
@@ -156,6 +156,10 @@
   TestSimple("bytestring_test");
 }
 
+TEST(BoringSSL, ConstantTime) {
+  TestSimple("constant_time_test");
+}
+
 TEST(BoringSSL, Cipher) {
   base::FilePath data_file;
   ASSERT_TRUE(CryptoCipherPath(&data_file));
@@ -171,10 +175,18 @@
   TestSimple("dh_test");
 }
 
+TEST(BoringSSL, Digest) {
+  TestSimple("digest_test");
+}
+
 TEST(BoringSSL, DSA) {
   TestSimple("dsa_test");
 }
 
+TEST(BoringSSL, EC) {
+  TestSimple("ec_test");
+}
+
 TEST(BoringSSL, ECDSA) {
   TestSimple("ecdsa_test");
 }
@@ -195,18 +207,10 @@
   TestSimple("lhash_test");
 }
 
-TEST(BoringSSL, MD5) {
-  TestSimple("md5_test");
-}
-
 TEST(BoringSSL, RSA) {
   TestSimple("rsa_test");
 }
 
-TEST(BoringSSL, SHA1) {
-  TestSimple("sha1_test");
-}
-
 TEST(BoringSSL, PKCS7) {
   TestSimple("pkcs7_test");
 }
diff --git a/third_party/boringssl/win-x86_64/crypto/aes/aesni-x86_64.asm b/third_party/boringssl/win-x86_64/crypto/aes/aesni-x86_64.asm
index 30e8a85..e1c9e0e 100644
--- a/third_party/boringssl/win-x86_64/crypto/aes/aesni-x86_64.asm
+++ b/third_party/boringssl/win-x86_64/crypto/aes/aesni-x86_64.asm
@@ -519,6 +519,12 @@
 	mov	r8,QWORD[40+rsp]
 
 
+	lea	rsp,[((-88))+rsp]
+	movaps	XMMWORD[rsp],xmm6
+	movaps	XMMWORD[16+rsp],xmm7
+	movaps	XMMWORD[32+rsp],xmm8
+	movaps	XMMWORD[48+rsp],xmm9
+$L$ecb_enc_body:
 	and	rdx,-16
 	jz	NEAR $L$ecb_ret
 
@@ -813,6 +819,12 @@
 	movups	XMMWORD[80+rsi],xmm7
 
 $L$ecb_ret:
+	movaps	xmm6,XMMWORD[rsp]
+	movaps	xmm7,XMMWORD[16+rsp]
+	movaps	xmm8,XMMWORD[32+rsp]
+	movaps	xmm9,XMMWORD[48+rsp]
+	lea	rsp,[88+rsp]
+$L$ecb_enc_ret:
 	mov	rdi,QWORD[8+rsp]	;WIN64 epilogue
 	mov	rsi,QWORD[16+rsp]
 	DB	0F3h,0C3h		;repret
@@ -3378,26 +3390,7 @@
 EXTERN	__imp_RtlVirtualUnwind
 
 ALIGN	16
-ecb_se_handler:
-	push	rsi
-	push	rdi
-	push	rbx
-	push	rbp
-	push	r12
-	push	r13
-	push	r14
-	push	r15
-	pushfq
-	sub	rsp,64
-
-	mov	rax,QWORD[152+r8]
-
-	jmp	NEAR $L$common_seh_tail
-
-
-
-ALIGN	16
-ccm64_se_handler:
+ecb_ccm64_se_handler:
 	push	rsi
 	push	rdi
 	push	rbx
@@ -3600,14 +3593,15 @@
 ALIGN	8
 $L$SEH_info_ecb:
 DB	9,0,0,0
-	DD	ecb_se_handler wrt ..imagebase
+	DD	ecb_ccm64_se_handler wrt ..imagebase
+	DD	$L$ecb_enc_body wrt ..imagebase,$L$ecb_enc_ret wrt ..imagebase
 $L$SEH_info_ccm64_enc:
 DB	9,0,0,0
-	DD	ccm64_se_handler wrt ..imagebase
+	DD	ecb_ccm64_se_handler wrt ..imagebase
 	DD	$L$ccm64_enc_body wrt ..imagebase,$L$ccm64_enc_ret wrt ..imagebase
 $L$SEH_info_ccm64_dec:
 DB	9,0,0,0
-	DD	ccm64_se_handler wrt ..imagebase
+	DD	ecb_ccm64_se_handler wrt ..imagebase
 	DD	$L$ccm64_dec_body wrt ..imagebase,$L$ccm64_dec_ret wrt ..imagebase
 $L$SEH_info_ctr32:
 DB	9,0,0,0
diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn
index 7f5b2e3..195c5c8 100644
--- a/third_party/harfbuzz-ng/BUILD.gn
+++ b/third_party/harfbuzz-ng/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/linux/pkg_config.gni")
+
 # The GYP build supports system harfbuzz for non-official builds when using
 # pangoft2 1.31.0 or greater (which pulls it in).
 # TODO(brettw) we can consider doing this as well, although the benefit is
@@ -11,7 +13,28 @@
 # don't want to bloat the binary more by including another copy.
 
 declare_args() {
-  use_system_harfbuzz = is_chromeos
+  if (is_chromeos) {
+    # ChromeOS includes an up-to-date system harfbuzz that we have control
+    # over, so it use the system one by default.
+    use_system_harfbuzz = true
+  } else if (is_official_build) {
+    # For official builds, we want to control the Harbuzz version so always
+    # use our included one. Currently the sysroot includes a version of pangoft
+    # that doesn't link to harfbuzz, so there are no linker problems. If we
+    # update that version, we'll need to work around the duplicate symbols some
+    # other way.
+    use_system_harfbuzz = false
+  } else if (is_linux) {
+    # Use the system harfbuzz for newer versions of pangoft, and not for older
+    # ones. pangoft links to the system harfbuzz starting with 1.31.0, which
+    # causes duplicate symbols when we link our own version.
+    use_system_harfbuzz = exec_script(
+        pkg_config_script,
+        pkg_config_args + [ "--atleast-version=1.31.0", "pangoft2" ],
+        "value")
+  } else {
+    use_system_harfbuzz = false
+  }
 }
 
 if (use_system_harfbuzz) {
@@ -28,7 +51,7 @@
     include_dirs = [ "src" ]
   }
 
-  source_set("harfbuzz-ng") {
+  static_library("harfbuzz-ng") {
     sources = [
       "src/hb-atomic-private.hh",
       "src/hb-blob.cc",
diff --git a/third_party/libxml/BUILD.gn b/third_party/libxml/BUILD.gn
index d42e0df..73bb3dc 100644
--- a/third_party/libxml/BUILD.gn
+++ b/third_party/libxml/BUILD.gn
@@ -153,7 +153,6 @@
   if (is_win) {
     cflags_c = [
       "/wd4101",  # Unreferenced local variable.
-      "/wd4267",  # TODO(jschuh): crbug.com/167187 size_t to int truncations.
     ]
   } else if (is_mac || is_android) {
     # http://www.xmlsoft.org/threads.html says that this is required when using
diff --git a/third_party/mesa/mesa.gyp b/third_party/mesa/mesa.gyp
index 6ccbb2a..bc115e1 100644
--- a/third_party/mesa/mesa.gyp
+++ b/third_party/mesa/mesa.gyp
@@ -657,14 +657,6 @@
             '_GLAPI_NO_EXPORTS',
           ],
         }],
-        ['ubsan==1', {
-          # Due to a bug in LLVM (http://llvm.org/bugs/show_bug.cgi?id=21349),
-          # compilation hangs for some Mesa source files. Disable -O2
-          # temporarily until http://crbug.com/426271 is fixed.
-          'cflags!': [
-            '-O2',
-          ],
-        }],
       ],
     },
     # Building this target will hide the native OpenGL shared library and
diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn
index 923e8eb..5dbec0f 100644
--- a/third_party/zlib/BUILD.gn
+++ b/third_party/zlib/BUILD.gn
@@ -12,9 +12,10 @@
     cflags = [ "-msse2", "-msse4.2", "-mpclmul" ]
   } else {
     sources = [ "simd_stub.c"]
-  }
-  if (is_win) {
-    cflags = [ "/wd4324" ]
+    if (is_win) {
+      # TODO(GYP): crbug.com/431462 disable warning about structure padding.
+      cflags = [ "/wd4324" ]
+    }
   }
 }
 
diff --git a/third_party/zlib/simd_stub.c b/third_party/zlib/simd_stub.c
index bb2ddc3..796f1f6 100644
--- a/third_party/zlib/simd_stub.c
+++ b/third_party/zlib/simd_stub.c
@@ -7,7 +7,7 @@
 #include "deflate.h"
 #include "x86.h"
 
-int x86_cpu_enable_simd;
+int x86_cpu_enable_simd = 0;
 
 void ZLIB_INTERNAL crc_fold_init(deflate_state *const s) {
     assert(0);
diff --git a/third_party/zlib/x86.c b/third_party/zlib/x86.c
index 35ec516..0649306 100644
--- a/third_party/zlib/x86.c
+++ b/third_party/zlib/x86.c
@@ -10,7 +10,7 @@
 
 #include "x86.h"
 
-int x86_cpu_enable_simd;
+int x86_cpu_enable_simd = 0;
 
 #ifndef _MSC_VER
 #include <pthread.h>
diff --git a/third_party/zlib/zlib.gyp b/third_party/zlib/zlib.gyp
index 8c5ae44..22a48a3 100644
--- a/third_party/zlib/zlib.gyp
+++ b/third_party/zlib/zlib.gyp
@@ -8,9 +8,11 @@
       'target_name' : 'zlib_x86_simd',
       'type': 'static_library',
       'conditions': [
-        # See http://crbug.com/420616 gyp on mac & ios doesn't apply cflags
-        ['OS!="ios" and OS!="mac" and (target_arch=="ia32" or target_arch=="x64")', {
+        ['OS!="ios" and (target_arch=="ia32" or target_arch=="x64")', {
           'cflags' : ["-msse2", "-msse4.2", "-mpclmul"],
+          'xcode_settings' : {
+             'OTHER_CFLAGS' : ["-msse4.2", "-mpclmul"],
+          },
           'sources' : [ 'crc_folding.c',
                         'fill_window_sse.c']
         }, {
@@ -65,7 +67,7 @@
         ],
       },
       'conditions': [
-        ['OS!="ios" and OS!="mac" and (target_arch=="ia32" or target_arch=="x64")', {
+        ['OS!="ios" and (target_arch=="ia32" or target_arch=="x64")', {
           'sources' : [ 'x86.c', ],
         }],
         ['OS!="win"', {
diff --git a/tools/clang/empty_string/EmptyStringConverter.cpp b/tools/clang/empty_string/EmptyStringConverter.cpp
index 28cc602..d056755 100644
--- a/tools/clang/empty_string/EmptyStringConverter.cpp
+++ b/tools/clang/empty_string/EmptyStringConverter.cpp
@@ -196,8 +196,8 @@
   // tools.
   llvm::outs() << "==== BEGIN EDITS ====\n";
   for (const auto& r : replacements) {
-    llvm::outs() << "r:" << r.getFilePath() << ":" << r.getOffset() << ":"
-                 << r.getLength() << ":" << r.getReplacementText() << "\n";
+    llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() << ":::"
+                 << r.getLength() << ":::" << r.getReplacementText() << "\n";
   }
   llvm::outs() << "==== END EDITS ====\n";
 
diff --git a/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp b/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
index b2cd31f..fe9d860 100644
--- a/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
+++ b/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
@@ -419,8 +419,8 @@
   for (const auto& r : replacements) {
     std::string replacement_text = r.getReplacementText().str();
     std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
-    llvm::outs() << "r:" << r.getFilePath() << ":" << r.getOffset() << ":"
-                 << r.getLength() << ":" << replacement_text << "\n";
+    llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() << ":::"
+                 << r.getLength() << ":::" << replacement_text << "\n";
   }
   llvm::outs() << "==== END EDITS ====\n";
 
diff --git a/tools/clang/scripts/run_tool.py b/tools/clang/scripts/run_tool.py
index 33bb462..61417e4 100755
--- a/tools/clang/scripts/run_tool.py
+++ b/tools/clang/scripts/run_tool.py
@@ -54,12 +54,17 @@
   Args:
     paths: Prefix filter for the returned paths. May contain multiple entries.
   """
-  args = ['git', 'ls-files']
+  args = []
+  if sys.platform == 'win32':
+    args.append('git.bat')
+  else:
+    args.append('git')
+  args.append('ls-files')
   if paths:
     args.extend(paths)
   command = subprocess.Popen(args, stdout=subprocess.PIPE)
   output, _ = command.communicate()
-  return output.splitlines()
+  return [os.path.realpath(p) for p in output.splitlines()]
 
 
 def _ExtractEditsFromStdout(build_directory, stdout):
@@ -81,11 +86,10 @@
   edits = collections.defaultdict(list)
   for line in lines[start_index + 1:end_index]:
     try:
-      edit_type, path, offset, length, replacement = line.split(':', 4)
+      edit_type, path, offset, length, replacement = line.split(':::', 4)
       replacement = replacement.replace("\0", "\n");
-      # Normalize the file path emitted by the clang tool to be relative to the
-      # current working directory.
-      path = os.path.relpath(os.path.join(build_directory, path))
+      # Normalize the file path emitted by the clang tool.
+      path = os.path.realpath(os.path.join(build_directory, path))
       edits[path].append(Edit(edit_type, int(offset), int(length), replacement))
     except ValueError:
       print 'Unable to parse edit: %s' % line
@@ -140,6 +144,7 @@
     self.__filenames = filenames
     self.__success_count = 0
     self.__failed_count = 0
+    self.__edit_count = 0
     self.__edits = collections.defaultdict(list)
 
   @property
@@ -172,6 +177,7 @@
       self.__success_count += 1
       for k, v in result['edits'].iteritems():
         self.__edits[k].extend(v)
+        self.__edit_count += len(v)
     else:
       self.__failed_count += 1
       sys.stdout.write('\nFailed to process %s\n' % result['filename'])
@@ -180,8 +186,9 @@
     percentage = (
         float(self.__success_count + self.__failed_count) /
         len(self.__filenames)) * 100
-    sys.stdout.write('Succeeded: %d, Failed: %d [%.2f%%]\r' % (
-        self.__success_count, self.__failed_count, percentage))
+    sys.stdout.write('Succeeded: %d, Failed: %d, Edits: %d [%.2f%%]\r' % (
+        self.__success_count, self.__failed_count, self.__edit_count,
+        percentage))
     sys.stdout.flush()
 
 
@@ -283,7 +290,9 @@
       '../../../third_party/llvm/tools/clang/tools/clang-format',
       'clang-format-diff.py')
   # TODO(dcheng): Allow this to be controlled with a flag as well.
-  if not os.path.isfile(clang_format_diff_path):
+  # TODO(dcheng): Shell escaping of args to git diff to clang-format is broken
+  # on Windows.
+  if not os.path.isfile(clang_format_diff_path) or sys.platform == 'win32':
     clang_format_diff_path = None
 
   filenames = frozenset(_GetFilesFromGit(argv[2:]))
@@ -297,7 +306,7 @@
   # useful to modify files that aren't under source control--typically, these
   # are generated files or files in a git submodule that's not part of Chromium.
   _ApplyEdits({k : v for k, v in dispatcher.edits.iteritems()
-                    if k in filenames},
+                    if os.path.realpath(k) in filenames},
               clang_format_diff_path)
   if dispatcher.failed_count != 0:
     return 2
diff --git a/tools/clang/scripts/test_tool.py b/tools/clang/scripts/test_tool.py
index d14dfda..1f64be4 100755
--- a/tools/clang/scripts/test_tool.py
+++ b/tools/clang/scripts/test_tool.py
@@ -20,7 +20,7 @@
   include_path_flags = ' '.join('-I %s' % include_path
                                for include_path in include_paths)
   return json.dumps([{'directory': '.',
-                      'command': 'clang++ -fsyntax-only %s -c %s' % (
+                      'command': 'clang++ -std=c++11 -fsyntax-only %s -c %s' % (
                           include_path_flags, f),
                       'file': f} for f in files], indent=2)
 
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 5ee7c30..25aa5a5 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -32,6 +32,7 @@
                               'Release+Asserts')
 COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, '32bit-compiler-rt')
 CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang')
+LLD_DIR = os.path.join(LLVM_DIR, 'tools', 'lld')
 COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt')
 STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision')
 
@@ -179,6 +180,7 @@
 
   Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR)
   Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR)
+  Checkout('LLD', LLVM_REPO_URL + '/lld/trunk', LLD_DIR)
   Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR)
 
   if not os.path.exists(LLVM_BUILD_DIR):
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index 4681b25..f80cdd0 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -133,6 +133,10 @@
     "includes": [23000],
     "structures": [23200],
   },
+  "chrome/browser/resources/options_test_resources.grd": {
+    "includes": [23400],
+    "structures": [23450],
+  },
   "cloud_print/virtual_driver/win/install/virtual_driver_setup_resources.grd": {
     "messages": [23500],
     "includes": [23550],
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index 8735e0d..27d554e 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -129,11 +129,14 @@
       # TODO(timurrrr): also check TSan and MSan?
       # `nm` might not be available, so use try-except.
       try:
-        nm_output = subprocess.check_output(["nm", exe_path])
-        if nm_output.find("__asan_init") != -1:
-          raise BadBinary("You're trying to run an executable instrumented "
-                          "with AddressSanitizer under %s. Please provide "
-                          "an uninstrumented executable." % tool_name)
+        # Do not perform this check on OS X, as 'nm' on 10.6 can't handle
+        # binaries built with Clang 3.5+.
+        if not common.IsMac():
+          nm_output = subprocess.check_output(["nm", exe_path])
+          if nm_output.find("__asan_init") != -1:
+            raise BadBinary("You're trying to run an executable instrumented "
+                            "with AddressSanitizer under %s. Please provide "
+                            "an uninstrumented executable." % tool_name)
       except OSError:
         pass
 
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index 5840dc1..96ae6fa 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -550,15 +550,6 @@
 *!content::BrowserThreadImpl::CacheThreadRun
 *!content::BrowserThreadImpl::Run
 
-UNADDRESSABLE ACCESS
-name=http://crbug.com/379204
-...
-*!WTF::MessageQueue<>::waitForMessageWithTimeout
-*!blink::WorkerRunLoop::run
-*!blink::WorkerRunLoop::run
-*!blink::WorkerThread::workerThread
-*!WTF::threadEntryPoint
-
 GDI USAGE ERROR
 name=379774
 system call NtUserCallOneParam.RELEASEDC
@@ -667,3 +658,10 @@
 blink_web.dll!blink::FrameView::prepareForDetach
 blink_web.dll!blink::LocalFrame::setView
 blink_web.dll!blink::FrameTree::~FrameTree
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/432070
+blink_web.dll!blink::Frame::detach
+content.dll!content::RenderFrameProxy::OnDeleteProxy
+content.dll!content::RenderFrameProxy::OnMessageReceived
+content.dll!content::MessageRouter::RouteMessage
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt
index ebe6a15..3cd6ca0 100644
--- a/tools/valgrind/drmemory/suppressions_full.txt
+++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -1864,3 +1864,10 @@
 name=bug_425097
 ...
 *!ash::test::ShelfViewTest_CheckDragAndDropFromOverflowBubbleToShelf_Test::TestBody
+
+UNINITIALIZED READ
+name=bug_432067
+system call NtCreateFile parameter #9
+MSWSOCK.dll!*
+content.dll!content::AppCacheStorageImpl::DatabaseTask::CallRun
+
diff --git a/tools/valgrind/gtest_exclude/aura_unittests.gtest.txt b/tools/valgrind/gtest_exclude/aura_unittests.gtest.txt
index 321f281..69ce8dc 100644
--- a/tools/valgrind/gtest_exclude/aura_unittests.gtest.txt
+++ b/tools/valgrind/gtest_exclude/aura_unittests.gtest.txt
@@ -1,5 +1,2 @@
 # Flaky under Valgrind, see http://crbug.com/348331
 WindowEventDispatcherTest.TouchMovesHeld
-
-# Failing on cros/win. crbug.com/427729
-GestureRecognizerTest.GestureEventSmallPinchEnabled
diff --git a/tools/valgrind/gtest_exclude/gfx_unittests.gtest-memcheck.txt b/tools/valgrind/gtest_exclude/gfx_unittests.gtest-memcheck.txt
new file mode 100644
index 0000000..3aaaafc
--- /dev/null
+++ b/tools/valgrind/gtest_exclude/gfx_unittests.gtest-memcheck.txt
@@ -0,0 +1,2 @@
+# http://crbug.com/402209
+FontRenderParamsTest.Default
diff --git a/tools/valgrind/gtest_exclude/ui_unittests.gtest-memcheck_linux.txt b/tools/valgrind/gtest_exclude/ui_unittests.gtest-memcheck_linux.txt
new file mode 100644
index 0000000..282de6b
--- /dev/null
+++ b/tools/valgrind/gtest_exclude/ui_unittests.gtest-memcheck_linux.txt
@@ -0,0 +1,2 @@
+# http://crbug.com/431708
+TouchExplorationTest.TwoFingerTapAndHold
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 852a638..fa0f599 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -2506,19 +2506,6 @@
    fun:nssTrustDomain_UpdateCachedTokenCerts
 }
 {
-   bug_331063
-   Memcheck:Uninitialized
-   ...
-   fun:_ZN5blink11RenderImage12imageChangedEPvPKNS_7IntRectE
-   fun:_ZN5blink12RenderObject12imageChangedEPNS_13ImageResourceEPKNS_7IntRectE
-   fun:_ZN5blink13ImageResource12didAddClientEPNS_14ResourceClientE
-   fun:_ZN5blink8Resource9addClientEPNS_14ResourceClientE
-   fun:_ZN5blink19RenderImageResource16setImageResourceEPNS_13ImageResourceE
-   fun:_ZN5blink30PasswordGeneratorButtonElement11updateImageEv
-   fun:_ZN5blink30PasswordGeneratorButtonElement6attachERKNS_4Node13AttachContextE
-   fun:_ZN5blink13ContainerNode14attachChildrenERKNS_4Node13AttachContextE
-}
-{
    bug_331925
    Memcheck:Leak
    ...
@@ -2845,19 +2832,6 @@
    fun:_ZN7content27ServiceWorkerContextWrapper12InitInternalERKN4base8FilePathEPNS1_19SequencedTaskRunnerEPNS1_16MessageLoopProxyEPN5quota17QuotaManagerProxyE
 }
 {
-   bug_379359
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN7content27ServiceWorkerContextWrapperC1EPNS_14BrowserContextE
-   fun:_ZN7content20StoragePartitionImpl6CreateEPNS_14BrowserContextEbRKN4base8FilePathE
-   fun:_ZN7content23StoragePartitionImplMap3GetERKSsS2_b
-   fun:_ZN7content12_GLOBAL__N_129GetStoragePartitionFromConfigEPNS_14BrowserContext*
-   fun:_ZN7content14BrowserContext19GetStoragePartitionEPS0_PNS_12SiteInstanceE
-   fun:_ZN7content14BrowserContext26GetDefaultStoragePartitionEPS0_
-   fun:_ZN7content21ShellBrowserMainParts21PreMainMessageLoopRunEv
-   fun:_ZN7content15BrowserMainLoop21PreMainMessageLoopRunEv
-}
-{
    bug_379943
    Memcheck:Leak
    fun:_Znw*
@@ -2867,6 +2841,7 @@
    fun:_ZN7content12_GLOBAL__N_129GetStoragePartitionFromConfigEPNS_14BrowserContext*
    fun:_ZN7content14BrowserContext19GetStoragePartitionEPS0_PNS_12SiteInstanceE
    fun:_ZN7content14BrowserContext26GetDefaultStoragePartitionEPS0_
+   ...
    fun:_ZN7content21ShellBrowserMainParts21PreMainMessageLoopRunEv
    fun:_ZN7content15BrowserMainLoop21PreMainMessageLoopRunEv
 }
@@ -3435,3 +3410,28 @@
    fun:_ZN7content19TestRenderFrameHost41SendNavigateWithTransitionAndResponseCodeEiRK4GURLN2ui14PageTransitionEi
    fun:_ZN7content19TestRenderFrameHost26SendNavigateWithTransitionEiRK4GURLN2ui14PageTransitionE
 }
+{
+   bug_431209a
+   Memcheck:Leak
+   fun:_Znw*
+   fun:_ZN8remoting13ClipboardAuraC1E13scoped_refptrIN4base22SingleThreadTaskRunnerEE
+   fun:_ZN8remoting17ClipboardAuraTest5SetUpEv
+}
+{
+   bug_431209b
+   Memcheck:Leak
+   fun:_Znw*
+   fun:_ZN2ui9Clipboard6CreateEv
+   fun:_ZN2ui9Clipboard19GetForCurrentThreadEv
+   fun:_ZN2ui21ScopedClipboardWriterD1Ev
+   fun:_ZN8remoting13ClipboardAura4Core20InjectClipboardEventERKNS_8protocol14ClipboardEventE
+}
+{
+   bug_431213
+   Memcheck:Leak
+   fun:_Znw*
+   fun:_ZN3gin22CreateFunctionTemplateIFSsPN4mojo2js13HandleWrapperEEEEN2v85LocalINS6_16FunctionTemplateEEEPNS6_7IsolateEN4base8CallbackIT_EEi
+   fun:_ZN3gin12_GLOBAL__N_114CallbackTraitsIMN4mojo2js13HandleWrapperEFSsvEvE14CreateTemplateEPN2v87IsolateES6_
+   fun:_ZN3gin21ObjectTemplateBuilder9SetMethodIMN4mojo2js13HandleWrapperEFSsvEEERS0_RKN4base16BasicStringPieceISsEERKT_
+   fun:_ZN4mojo2js13HandleWrapper24GetObjectTemplateBuilderEPN2v87IsolateE
+}
diff --git a/tools/valgrind/memcheck/suppressions_mac.txt b/tools/valgrind/memcheck/suppressions_mac.txt
index fe8f8a1..154e4e9 100644
--- a/tools/valgrind/memcheck/suppressions_mac.txt
+++ b/tools/valgrind/memcheck/suppressions_mac.txt
@@ -194,19 +194,6 @@
   fun:_ZN3gfx9GLSurface24InitializeOneOffForTestsEv
 }
 {
-   bug_380568
-   Memcheck:Leak
-   fun:calloc
-   fun:_internal_class_createInstanceFromZone
-   fun:_internal_class_createInstance
-   fun:NSAllocateObject
-   fun:+[NSObject(NSObject) alloc]
-   fun:-[VideoCaptureDeviceQTKit initWithFrameReceiver:]
-   fun:_ZN5media21VideoCaptureDeviceMac4InitENS_18VideoCaptureDevice4Name14CaptureApiTypeE
-   fun:_ZN5media28VideoCaptureDeviceFactoryMac6CreateERKNS_18VideoCaptureDevice4NameE
-   fun:_ZN5media45VideoCaptureDeviceTest_OpenInvalidDevice_Test8TestBodyEv
-}
-{
    bug_385604_b
    Memcheck:Leak
    fun:calloc
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index c9ad475..6bcb02a 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -18,6 +18,7 @@
 #include "cc/base/switches.h"
 #include "cc/input/input_handler.h"
 #include "cc/layers/layer.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/output/begin_frame_args.h"
 #include "cc/output/context_provider.h"
 #include "cc/surfaces/surface_id_allocator.h"
@@ -168,7 +169,8 @@
         context_factory_->GetGpuMemoryBufferManager(),
         settings,
         task_runner_,
-        compositor_thread_loop_);
+        compositor_thread_loop_,
+        nullptr);
   } else {
     host_ = cc::LayerTreeHost::CreateSingleThreaded(
         this,
@@ -176,7 +178,8 @@
         context_factory_->GetSharedBitmapManager(),
         context_factory_->GetGpuMemoryBufferManager(),
         settings,
-        task_runner_);
+        task_runner_,
+        nullptr);
   }
   UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor",
                       base::TimeTicks::Now() - before_create);
diff --git a/ui/compositor/float_animation_curve_adapter.cc b/ui/compositor/float_animation_curve_adapter.cc
index 308fc1e..3b5e155 100644
--- a/ui/compositor/float_animation_curve_adapter.cc
+++ b/ui/compositor/float_animation_curve_adapter.cc
@@ -17,8 +17,8 @@
       duration_(duration) {
 }
 
-double FloatAnimationCurveAdapter::Duration() const {
-  return duration_.InSecondsF();
+base::TimeDelta FloatAnimationCurveAdapter::Duration() const {
+  return duration_;
 }
 
 scoped_ptr<cc::AnimationCurve> FloatAnimationCurveAdapter::Clone() const {
diff --git a/ui/compositor/float_animation_curve_adapter.h b/ui/compositor/float_animation_curve_adapter.h
index 1c7b8b3..88d5870 100644
--- a/ui/compositor/float_animation_curve_adapter.h
+++ b/ui/compositor/float_animation_curve_adapter.h
@@ -21,7 +21,7 @@
   ~FloatAnimationCurveAdapter() override {}
 
   // FloatAnimationCurve implementation.
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   scoped_ptr<cc::AnimationCurve> Clone() const override;
   float GetValue(double t) const override;
 
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index abf7e02..ea30852 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/debug/trace_event.h"
 #include "base/json/json_writer.h"
+#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "cc/base/scoped_ptr_algorithm.h"
@@ -578,7 +579,7 @@
 
   scoped_refptr<cc::SurfaceLayer> new_layer =
       cc::SurfaceLayer::Create(satisfy_callback, require_callback);
-  new_layer->SetSurfaceId(id);
+  new_layer->SetSurfaceId(id, 1.f, frame_size_in_dip);
   SwitchToLayer(new_layer);
   surface_layer_ = new_layer;
 
diff --git a/ui/compositor/transform_animation_curve_adapter.cc b/ui/compositor/transform_animation_curve_adapter.cc
index fa73140..2c11488 100644
--- a/ui/compositor/transform_animation_curve_adapter.cc
+++ b/ui/compositor/transform_animation_curve_adapter.cc
@@ -22,8 +22,8 @@
 TransformAnimationCurveAdapter::~TransformAnimationCurveAdapter() {
 }
 
-double TransformAnimationCurveAdapter::Duration() const {
-  return duration_.InSecondsF();
+base::TimeDelta TransformAnimationCurveAdapter::Duration() const {
+  return duration_;
 }
 
 scoped_ptr<cc::AnimationCurve> TransformAnimationCurveAdapter::Clone() const {
@@ -86,8 +86,8 @@
 InverseTransformCurveAdapter::~InverseTransformCurveAdapter() {
 }
 
-double InverseTransformCurveAdapter::Duration() const {
-  return duration_.InSeconds();
+base::TimeDelta InverseTransformCurveAdapter::Duration() const {
+  return duration_;
 }
 
 scoped_ptr<cc::AnimationCurve> InverseTransformCurveAdapter::Clone() const {
diff --git a/ui/compositor/transform_animation_curve_adapter.h b/ui/compositor/transform_animation_curve_adapter.h
index 7aa318e..c08024d 100644
--- a/ui/compositor/transform_animation_curve_adapter.h
+++ b/ui/compositor/transform_animation_curve_adapter.h
@@ -25,7 +25,7 @@
   ~TransformAnimationCurveAdapter() override;
 
   // TransformAnimationCurve implementation.
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   scoped_ptr<AnimationCurve> Clone() const override;
   gfx::Transform GetValue(double t) const override;
   bool AnimatedBoundsForBox(const gfx::BoxF& box,
@@ -55,7 +55,7 @@
 
   ~InverseTransformCurveAdapter() override;
 
-  double Duration() const override;
+  base::TimeDelta Duration() const override;
   scoped_ptr<AnimationCurve> Clone() const override;
   gfx::Transform GetValue(double t) const override;
   bool AnimatedBoundsForBox(const gfx::BoxF& box,
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index 641f51d..6968f2c 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -204,6 +204,8 @@
     sources += [
       "gl_context_cgl.cc",
       "gl_context_cgl.h",
+      "gl_fence_apple.cc",
+      "gl_fence_apple.h",
       "gl_image_io_surface.cc",
       "gl_image_io_surface.h",
       "scoped_cgl.cc",
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index 7670ec8..0156806 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -67,6 +67,23 @@
   'names': ['glBindTexture'],
   'arguments': 'GLenum target, GLuint texture', },
 { 'return_type': 'void',
+  'known_as': 'glBindVertexArrayOES',
+  'versions': [{ 'name': 'glBindVertexArray',
+                 'gl_versions': ['gl3', 'gl4', 'es3'] },
+               { 'name': 'glBindVertexArray',
+                 'extensions': ['GL_ARB_vertex_array_object'] },
+               { 'name': 'glBindVertexArrayOES' },
+               { 'name': 'glBindVertexArrayAPPLE',
+                 'extensions': ['GL_APPLE_vertex_array_object'] }],
+  'arguments': 'GLuint array' },
+{ 'return_type': 'void',
+  'known_as': 'glBlendBarrierKHR',
+  'versions': [{ 'name': 'glBlendBarrierNV',
+                 'extensions': ['GL_NV_blend_equation_advanced'] },
+               { 'name': 'glBlendBarrierKHR',
+                 'extensions': ['GL_KHR_blend_equation_advanced'] }],
+  'arguments': 'void' },
+{ 'return_type': 'void',
   'names': ['glBlendColor'],
   'arguments': 'GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha', },
 { 'return_type': 'void',
@@ -88,12 +105,12 @@
                'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
                'GLbitfield mask, GLenum filter', },
 { 'return_type': 'void',
-  'names': ['glBlitFramebufferEXT', 'glBlitFramebuffer'],
+  'names': ['glBlitFramebufferANGLE', 'glBlitFramebuffer'],
   'arguments': 'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, '
                'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
                'GLbitfield mask, GLenum filter', },
 { 'return_type': 'void',
-  'names': ['glBlitFramebufferANGLE', 'glBlitFramebuffer'],
+  'names': ['glBlitFramebufferEXT', 'glBlitFramebuffer'],
   'arguments': 'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, '
                'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
                'GLbitfield mask, GLenum filter', },
@@ -127,6 +144,9 @@
 { 'return_type': 'void',
   'names': ['glClearStencil'],
   'arguments': 'GLint s', },
+{ 'return_type': 'GLenum',
+  'names': ['glClientWaitSync'],
+  'arguments': 'GLsync sync, GLbitfield flags, GLuint64 timeout', },
 { 'return_type': 'void',
   'names': ['glColorMask'],
   'arguments':
@@ -168,6 +188,14 @@
   'names': ['glDeleteBuffersARB', 'glDeleteBuffers'],
   'arguments': 'GLsizei n, const GLuint* buffers', },
 { 'return_type': 'void',
+  'known_as': 'glDeleteFencesAPPLE',
+  'versions': [{ 'name': 'glDeleteFencesAPPLE',
+                 'extensions': ['GL_APPLE_fence'] }],
+  'arguments': 'GLsizei n, const GLuint* fences', },
+{ 'return_type': 'void',
+  'names': ['glDeleteFencesNV'],
+  'arguments': 'GLsizei n, const GLuint* fences', },
+{ 'return_type': 'void',
   'names': ['glDeleteFramebuffersEXT', 'glDeleteFramebuffers'],
   'arguments': 'GLsizei n, const GLuint* framebuffers', },
 { 'return_type': 'void',
@@ -186,9 +214,22 @@
   'names': ['glDeleteShader'],
   'arguments': 'GLuint shader', },
 { 'return_type': 'void',
+  'names': ['glDeleteSync'],
+  'arguments': 'GLsync sync', },
+{ 'return_type': 'void',
   'names': ['glDeleteTextures'],
   'arguments': 'GLsizei n, const GLuint* textures', },
 { 'return_type': 'void',
+  'known_as': 'glDeleteVertexArraysOES',
+  'versions': [{ 'name': 'glDeleteVertexArrays',
+                 'gl_versions': ['gl3', 'gl4', 'es3'] },
+               { 'name': 'glDeleteVertexArrays',
+                 'extensions': ['GL_ARB_vertex_array_object'] },
+               { 'name': 'glDeleteVertexArraysOES' },
+               { 'name': 'glDeleteVertexArraysAPPLE',
+                 'extensions': ['GL_APPLE_vertex_array_object'] }],
+  'arguments': 'GLsizei n, const GLuint* arrays' },
+{ 'return_type': 'void',
   'names': ['glDepthFunc'],
   'arguments': 'GLenum func', },
 { 'return_type': 'void',
@@ -210,9 +251,23 @@
   'names': ['glDisableVertexAttribArray'],
   'arguments': 'GLuint index', },
 { 'return_type': 'void',
+  'known_as': 'glDiscardFramebufferEXT',
+  'versions': [{ 'name': 'glInvalidateFramebuffer',
+                 'gl_versions': ['es3'],
+                 'extensions': [] },
+               { 'name': 'glDiscardFramebufferEXT',
+                 'gl_versions': ['es1', 'es2'] }],
+  'arguments': 'GLenum target, GLsizei numAttachments, '
+      'const GLenum* attachments' },
+{ 'return_type': 'void',
   'names': ['glDrawArrays'],
   'arguments': 'GLenum mode, GLint first, GLsizei count', },
 { 'return_type': 'void',
+  'known_as': 'glDrawArraysInstancedANGLE',
+  'names': ['glDrawArraysInstancedARB', 'glDrawArraysInstancedANGLE',
+            'glDrawArraysInstanced'],
+  'arguments': 'GLenum mode, GLint first, GLsizei count, GLsizei primcount', },
+{ 'return_type': 'void',
   'names': ['glDrawBuffer'],
   'arguments': 'GLenum mode', },
 { 'return_type': 'void',
@@ -223,12 +278,19 @@
   'arguments':
       'GLenum mode, GLsizei count, GLenum type, const void* indices', },
 { 'return_type': 'void',
-  'names': ['glEGLImageTargetTexture2DOES'],
-  'arguments': 'GLenum target, GLeglImageOES image', },
+  'known_as': 'glDrawElementsInstancedANGLE',
+  'names': ['glDrawElementsInstancedARB', 'glDrawElementsInstancedANGLE',
+            'glDrawElementsInstanced'],
+  'arguments':
+      'GLenum mode, GLsizei count, GLenum type, const void* indices, '
+      'GLsizei primcount', },
 { 'return_type': 'void',
   'names': ['glEGLImageTargetRenderbufferStorageOES'],
   'arguments': 'GLenum target, GLeglImageOES image', },
 { 'return_type': 'void',
+  'names': ['glEGLImageTargetTexture2DOES'],
+  'arguments': 'GLenum target, GLeglImageOES image', },
+{ 'return_type': 'void',
   'names': ['glEnable'],
   'arguments': 'GLenum cap', },
 { 'return_type': 'void',
@@ -240,15 +302,29 @@
 { 'return_type': 'void',
   'names': ['glEndQueryARB', 'glEndQueryEXT'],
   'arguments': 'GLenum target', },
+{ 'return_type': 'GLsync',
+  'names': ['glFenceSync'],
+  'arguments': 'GLenum condition, GLbitfield flags', },
 { 'return_type': 'void',
   'names': ['glFinish'],
   'arguments': 'void', },
 { 'return_type': 'void',
+  'known_as': 'glFinishFenceAPPLE',
+  'versions': [{ 'name': 'glFinishFenceAPPLE',
+                 'extensions': ['GL_APPLE_fence'] }],
+  'arguments': 'GLuint fence', },
+{ 'return_type': 'void',
+  'names': ['glFinishFenceNV'],
+  'arguments': 'GLuint fence', },
+{ 'return_type': 'void',
   'names': ['glFlush'],
   'arguments': 'void', },
 { 'return_type': 'void',
+  'names': ['glFlushMappedBufferRange'],
+  'arguments': 'GLenum target, GLintptr offset, GLsizeiptr length', },
+{ 'return_type': 'void',
   'names': ['glFramebufferRenderbufferEXT', 'glFramebufferRenderbuffer'],
-  'arguments': \
+  'arguments':
       'GLenum target, GLenum attachment, GLenum renderbuffertarget, '
       'GLuint renderbuffer', },
 { 'return_type': 'void',
@@ -273,24 +349,42 @@
   'names': ['glGenBuffersARB', 'glGenBuffers'],
   'arguments': 'GLsizei n, GLuint* buffers', },
 { 'return_type': 'void',
+  'names': ['glGenerateMipmapEXT', 'glGenerateMipmap'],
+  'arguments': 'GLenum target', },
+{ 'return_type': 'void',
+  'known_as': 'glGenFencesAPPLE',
+  'versions': [{ 'name': 'glGenFencesAPPLE',
+                 'extensions': ['GL_APPLE_fence'] }],
+  'arguments': 'GLsizei n, GLuint* fences', },
+{ 'return_type': 'void',
+  'names': ['glGenFencesNV'],
+  'arguments': 'GLsizei n, GLuint* fences', },
+{ 'return_type': 'void',
+  'names': ['glGenFramebuffersEXT', 'glGenFramebuffers'],
+  'arguments': 'GLsizei n, GLuint* framebuffers', },
+{ 'return_type': 'void',
   'names': ['glGenQueries'],
   'arguments': 'GLsizei n, GLuint* ids', },
 { 'return_type': 'void',
   'names': ['glGenQueriesARB', 'glGenQueriesEXT'],
   'arguments': 'GLsizei n, GLuint* ids', },
 { 'return_type': 'void',
-  'names': ['glGenerateMipmapEXT', 'glGenerateMipmap'],
-  'arguments': 'GLenum target', },
-{ 'return_type': 'void',
-  'names': ['glGenFramebuffersEXT', 'glGenFramebuffers'],
-  'arguments': 'GLsizei n, GLuint* framebuffers', },
-{ 'return_type': 'void',
   'names': ['glGenRenderbuffersEXT', 'glGenRenderbuffers'],
   'arguments': 'GLsizei n, GLuint* renderbuffers', },
 { 'return_type': 'void',
   'names': ['glGenTextures'],
   'arguments': 'GLsizei n, GLuint* textures', },
 { 'return_type': 'void',
+  'known_as': 'glGenVertexArraysOES',
+  'versions': [{ 'name': 'glGenVertexArrays',
+                 'gl_versions': ['gl3', 'gl4', 'es3'] },
+               { 'name': 'glGenVertexArrays',
+                 'extensions': ['GL_ARB_vertex_array_object'] },
+               { 'name': 'glGenVertexArraysOES' },
+               { 'name': 'glGenVertexArraysAPPLE',
+                 'extensions': ['GL_APPLE_vertex_array_object'] }],
+  'arguments': 'GLsizei n, GLuint* arrays', },
+{ 'return_type': 'void',
   'names': ['glGetActiveAttrib'],
   'arguments':
       'GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, '
@@ -320,6 +414,9 @@
   GL_SERVICE_LOG("GL_RESULT: " << GLES2Util::GetStringError(result));
 """, },
 { 'return_type': 'void',
+  'names': ['glGetFenceivNV'],
+  'arguments': 'GLuint fence, GLenum pname, GLint* params', },
+{ 'return_type': 'void',
   'names': ['glGetFloatv'],
   'arguments': 'GLenum pname, GLfloat* params', },
 { 'return_type': 'void',
@@ -334,12 +431,12 @@
             'glGetGraphicsResetStatus'],
   'arguments': 'void', },
 { 'return_type': 'void',
-  'names': ['glGetIntegerv'],
-  'arguments': 'GLenum pname, GLint* params', },
-{ 'return_type': 'void',
   'names': ['glGetInteger64v'],
   'arguments': 'GLenum pname, GLint64* params', },
 { 'return_type': 'void',
+  'names': ['glGetIntegerv'],
+  'arguments': 'GLenum pname, GLint* params', },
+{ 'return_type': 'void',
   'known_as': 'glGetProgramBinary',
   'versions': [{ 'name': 'glGetProgramBinaryOES' },
                { 'name': 'glGetProgramBinary',
@@ -348,13 +445,13 @@
   'arguments': 'GLuint program, GLsizei bufSize, GLsizei* length, '
                'GLenum* binaryFormat, GLvoid* binary' },
 { 'return_type': 'void',
-  'names': ['glGetProgramiv'],
-  'arguments': 'GLuint program, GLenum pname, GLint* params', },
-{ 'return_type': 'void',
   'names': ['glGetProgramInfoLog'],
   'arguments':
       'GLuint program, GLsizei bufsize, GLsizei* length, char* infolog', },
 { 'return_type': 'void',
+  'names': ['glGetProgramiv'],
+  'arguments': 'GLuint program, GLenum pname, GLint* params', },
+{ 'return_type': 'void',
   'names': ['glGetQueryiv'],
   'arguments': 'GLenum target, GLenum pname, GLint* params', },
 { 'return_type': 'void',
@@ -364,6 +461,10 @@
   'names': ['glGetQueryObjecti64v'],
   'arguments': 'GLuint id, GLenum pname, GLint64* params', },
 { 'return_type': 'void',
+  'names': ['glGetQueryObjectiv', 'glGetQueryObjectivARB',
+            'glGetQueryObjectivEXT'],
+  'arguments': 'GLuint id, GLenum pname, GLint* params', },
+{ 'return_type': 'void',
   'names': ['glGetQueryObjectui64v', 'glGetQueryObjectui64vEXT'],
   'arguments': 'GLuint id, GLenum pname, GLuint64* params', },
 { 'return_type': 'void',
@@ -373,20 +474,16 @@
   'names': ['glGetQueryObjectuivARB', 'glGetQueryObjectuivEXT'],
   'arguments': 'GLuint id, GLenum pname, GLuint* params', },
 { 'return_type': 'void',
-  'names': ['glGetQueryObjectiv', 'glGetQueryObjectivARB',
-            'glGetQueryObjectivEXT'],
-  'arguments': 'GLuint id, GLenum pname, GLint* params', },
-{ 'return_type': 'void',
   'names': ['glGetRenderbufferParameterivEXT', 'glGetRenderbufferParameteriv'],
   'arguments': 'GLenum target, GLenum pname, GLint* params', },
 { 'return_type': 'void',
-  'names': ['glGetShaderiv'],
-  'arguments': 'GLuint shader, GLenum pname, GLint* params', },
-{ 'return_type': 'void',
   'names': ['glGetShaderInfoLog'],
   'arguments':
       'GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog', },
 { 'return_type': 'void',
+  'names': ['glGetShaderiv'],
+  'arguments': 'GLuint shader, GLenum pname, GLint* params', },
+{ 'return_type': 'void',
   'names': ['glGetShaderPrecisionFormat'],
   'arguments': 'GLenum shadertype, GLenum precisiontype, '
                'GLint* range, GLint* precision', },
@@ -398,6 +495,11 @@
   'names': ['glGetString'],
   'arguments': 'GLenum name', },
 { 'return_type': 'void',
+  'names': ['glGetSynciv'],
+  'arguments':
+    'GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length,'
+    'GLint* values', },
+{ 'return_type': 'void',
   'names': ['glGetTexLevelParameterfv'],
   'arguments': 'GLenum target, GLint level, GLenum pname, GLfloat* params', },
 { 'return_type': 'void',
@@ -444,6 +546,14 @@
   'names': ['glIsEnabled'],
   'arguments': 'GLenum cap', },
 { 'return_type': 'GLboolean',
+  'known_as': 'glIsFenceAPPLE',
+  'versions': [{ 'name': 'glIsFenceAPPLE',
+                 'extensions': ['GL_APPLE_fence'] }],
+  'arguments': 'GLuint fence', },
+{ 'return_type': 'GLboolean',
+  'names': ['glIsFenceNV'],
+  'arguments': 'GLuint fence', },
+{ 'return_type': 'GLboolean',
   'names': ['glIsFramebufferEXT', 'glIsFramebuffer'],
   'arguments': 'GLuint framebuffer', },
 { 'return_type': 'GLboolean',
@@ -459,8 +569,21 @@
   'names': ['glIsShader'],
   'arguments': 'GLuint shader', },
 { 'return_type': 'GLboolean',
+  'names': ['glIsSync'],
+  'arguments': 'GLsync sync', },
+{ 'return_type': 'GLboolean',
   'names': ['glIsTexture'],
   'arguments': 'GLuint texture', },
+{ 'return_type': 'GLboolean',
+  'known_as': 'glIsVertexArrayOES',
+  'versions': [{ 'name': 'glIsVertexArray',
+                 'gl_versions': ['gl3', 'gl4'] },
+               { 'name': 'glIsVertexArray',
+                 'extensions': ['GL_ARB_vertex_array_object'] },
+               { 'name': 'glIsVertexArrayOES' },
+               { 'name': 'glIsVertexArrayAPPLE',
+                 'extensions': ['GL_APPLE_vertex_array_object'] }],
+  'arguments': 'GLuint array' },
 { 'return_type': 'void',
   'names': ['glLineWidth'],
   'arguments': 'GLfloat width', },
@@ -476,8 +599,23 @@
   'arguments':
       'GLenum target, GLintptr offset, GLsizeiptr length, GLenum access', },
 { 'return_type': 'void',
-  'names': ['glFlushMappedBufferRange'],
-  'arguments': 'GLenum target, GLintptr offset, GLsizeiptr length', },
+  'known_as': 'glMatrixLoadfEXT',
+  'versions': [{ 'name': 'glMatrixLoadfEXT',
+                 'gl_versions': ['gl4'],
+                 'extensions': ['GL_EXT_direct_state_access'] },
+               { 'name': 'glMatrixLoadfEXT',
+                 'gl_versions': ['es3'],
+                 'extensions': ['GL_NV_path_rendering'] }],
+  'arguments': 'GLenum matrixMode, const GLfloat* m' },
+{ 'return_type': 'void',
+  'known_as': 'glMatrixLoadIdentityEXT',
+  'versions': [{ 'name': 'glMatrixLoadIdentityEXT',
+                 'gl_versions': ['gl4'],
+                 'extensions': ['GL_EXT_direct_state_access'] },
+               { 'name': 'glMatrixLoadIdentityEXT',
+                 'gl_versions': ['es3'],
+                 'extensions': ['GL_NV_path_rendering'] }],
+  'arguments': 'GLenum matrixMode' },
 { 'return_type': 'void',
   'names': ['glPixelStorei'],
   'arguments': 'GLenum pname, GLint param', },
@@ -533,9 +671,18 @@
 # function name appearing multiple times.
 # This is the ES3 function, which requires explicit resolve:
 { 'return_type': 'void',
+  'names': ['glRenderbufferStorageEXT', 'glRenderbufferStorage'],
+  'arguments':
+      'GLenum target, GLenum internalformat, GLsizei width, GLsizei height', },
+{ 'return_type': 'void',
   'names': ['glRenderbufferStorageMultisample'],
   'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
                'GLsizei width, GLsizei height', },
+{ 'return_type': 'void',
+  'names': ['glRenderbufferStorageMultisampleANGLE',
+            'glRenderbufferStorageMultisample'],
+  'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
+               'GLsizei width, GLsizei height', },
 # In desktop GL, EXT and core versions both have an explicit resolve step,
 # though desktop core GL implicitly resolves when drawing to a window.
 # TODO(oetuaho@nvidia.com): Right now this function also doubles as ES2 EXT
@@ -547,25 +694,24 @@
   'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
                'GLsizei width, GLsizei height', },
 { 'return_type': 'void',
-  'names': ['glRenderbufferStorageMultisampleANGLE',
-            'glRenderbufferStorageMultisample'],
-  'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
-               'GLsizei width, GLsizei height', },
-{ 'return_type': 'void',
   'names': ['glRenderbufferStorageMultisampleIMG'],
   'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
                'GLsizei width, GLsizei height', },
 { 'return_type': 'void',
-  'names': ['glRenderbufferStorageEXT', 'glRenderbufferStorage'],
-  'arguments':
-      'GLenum target, GLenum internalformat, GLsizei width, GLsizei height', },
-{ 'return_type': 'void',
   'names': ['glSampleCoverage'],
   'arguments': 'GLclampf value, GLboolean invert', },
 { 'return_type': 'void',
   'names': ['glScissor'],
   'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', },
 { 'return_type': 'void',
+  'known_as': 'glSetFenceAPPLE',
+  'versions': [{ 'name': 'glSetFenceAPPLE',
+                 'extensions': ['GL_APPLE_fence'] }],
+  'arguments': 'GLuint fence', },
+{ 'return_type': 'void',
+  'names': ['glSetFenceNV'],
+  'arguments': 'GLuint fence, GLenum condition', },
+{ 'return_type': 'void',
   'names': ['glShaderBinary'],
   'arguments': 'GLsizei n, const GLuint* shaders, GLenum binaryformat, '
                'const void* binary, GLsizei length', },
@@ -607,6 +753,14 @@
 { 'return_type': 'void',
   'names': ['glStencilOpSeparate'],
   'arguments': 'GLenum face, GLenum fail, GLenum zfail, GLenum zpass', },
+{ 'return_type': 'GLboolean',
+  'known_as': 'glTestFenceAPPLE',
+  'versions': [{ 'name': 'glTestFenceAPPLE',
+                 'extensions': ['GL_APPLE_fence'] }],
+  'arguments': 'GLuint fence', },
+{ 'return_type': 'GLboolean',
+  'names': ['glTestFenceNV'],
+  'arguments': 'GLuint fence', },
 { 'return_type': 'void',
   'names': ['glTexImage2D'],
   'arguments':
@@ -736,150 +890,28 @@
   'names': ['glVertexAttrib4fv'],
   'arguments': 'GLuint indx, const GLfloat* values', },
 { 'return_type': 'void',
-  'names': ['glVertexAttribPointer'],
-  'arguments': 'GLuint indx, GLint size, GLenum type, GLboolean normalized, '
-               'GLsizei stride, const void* ptr', },
-{ 'return_type': 'void',
-  'names': ['glViewport'],
-  'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', },
-{ 'return_type': 'void',
-  'names': ['glGenFencesNV'],
-  'arguments': 'GLsizei n, GLuint* fences', },
-{ 'return_type': 'void',
-  'names': ['glDeleteFencesNV'],
-  'arguments': 'GLsizei n, const GLuint* fences', },
-{ 'return_type': 'void',
-  'names': ['glSetFenceNV'],
-  'arguments': 'GLuint fence, GLenum condition', },
-{ 'return_type': 'GLboolean',
-  'names': ['glTestFenceNV'],
-  'arguments': 'GLuint fence', },
-{ 'return_type': 'void',
-  'names': ['glFinishFenceNV'],
-  'arguments': 'GLuint fence', },
-{ 'return_type': 'GLboolean',
-  'names': ['glIsFenceNV'],
-  'arguments': 'GLuint fence', },
-{ 'return_type': 'void',
-  'names': ['glGetFenceivNV'],
-  'arguments': 'GLuint fence, GLenum pname, GLint* params', },
-{ 'return_type': 'GLsync',
-  'names': ['glFenceSync'],
-  'arguments': 'GLenum condition, GLbitfield flags', },
-{ 'return_type': 'GLboolean',
-  'names': ['glIsSync'],
-  'arguments': 'GLsync sync', },
-{ 'return_type': 'void',
-  'names': ['glDeleteSync'],
-  'arguments': 'GLsync sync', },
-{ 'return_type': 'void',
-  'names': ['glGetSynciv'],
-  'arguments':
-    'GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length,'
-    'GLint* values', },
-{ 'return_type': 'GLenum',
-  'names': ['glClientWaitSync'],
-  'arguments':
-    'GLsync sync, GLbitfield flags, GLuint64 timeout', },
-{ 'return_type': 'GLenum',
-  'names': ['glWaitSync'],
-  'arguments':
-    'GLsync sync, GLbitfield flags, GLuint64 timeout', },
-{ 'return_type': 'void',
-  'known_as': 'glDrawArraysInstancedANGLE',
-  'names': ['glDrawArraysInstancedARB', 'glDrawArraysInstancedANGLE',
-            'glDrawArraysInstanced'],
-  'arguments': 'GLenum mode, GLint first, GLsizei count, GLsizei primcount', },
-{ 'return_type': 'void',
-  'known_as': 'glDrawElementsInstancedANGLE',
-  'names': ['glDrawElementsInstancedARB', 'glDrawElementsInstancedANGLE',
-            'glDrawElementsInstanced'],
-  'arguments':
-      'GLenum mode, GLsizei count, GLenum type, const void* indices, '
-      'GLsizei primcount', },
-{ 'return_type': 'void',
   'known_as': 'glVertexAttribDivisorANGLE',
   'names': ['glVertexAttribDivisorARB', 'glVertexAttribDivisorANGLE',
             'glVertexAttribDivisor'],
   'arguments':
       'GLuint index, GLuint divisor', },
 { 'return_type': 'void',
-  'known_as': 'glGenVertexArraysOES',
-  'versions': [{ 'name': 'glGenVertexArrays',
-                 'gl_versions': ['gl3', 'gl4', 'es3'] },
-               { 'name': 'glGenVertexArrays',
-                 'extensions': ['GL_ARB_vertex_array_object'] },
-               { 'name': 'glGenVertexArraysOES' },
-               { 'name': 'glGenVertexArraysAPPLE',
-                 'extensions': ['GL_APPLE_vertex_array_object'] }],
-  'arguments': 'GLsizei n, GLuint* arrays', },
+  'names': ['glVertexAttribPointer'],
+  'arguments': 'GLuint indx, GLint size, GLenum type, GLboolean normalized, '
+               'GLsizei stride, const void* ptr', },
 { 'return_type': 'void',
-  'known_as': 'glDeleteVertexArraysOES',
-  'versions': [{ 'name': 'glDeleteVertexArrays',
-                 'gl_versions': ['gl3', 'gl4', 'es3'] },
-               { 'name': 'glDeleteVertexArrays',
-                 'extensions': ['GL_ARB_vertex_array_object'] },
-               { 'name': 'glDeleteVertexArraysOES' },
-               { 'name': 'glDeleteVertexArraysAPPLE',
-                 'extensions': ['GL_APPLE_vertex_array_object'] }],
-  'arguments': 'GLsizei n, const GLuint* arrays' },
-{ 'return_type': 'void',
-  'known_as': 'glBindVertexArrayOES',
-  'versions': [{ 'name': 'glBindVertexArray',
-                 'gl_versions': ['gl3', 'gl4', 'es3'] },
-               { 'name': 'glBindVertexArray',
-                 'extensions': ['GL_ARB_vertex_array_object'] },
-               { 'name': 'glBindVertexArrayOES' },
-               { 'name': 'glBindVertexArrayAPPLE',
-                 'extensions': ['GL_APPLE_vertex_array_object'] }],
-  'arguments': 'GLuint array' },
-{ 'return_type': 'GLboolean',
-  'known_as': 'glIsVertexArrayOES',
-  'versions': [{ 'name': 'glIsVertexArray',
-                 'gl_versions': ['gl3', 'gl4'] },
-               { 'name': 'glIsVertexArray',
-                 'extensions': ['GL_ARB_vertex_array_object'] },
-               { 'name': 'glIsVertexArrayOES' },
-               { 'name': 'glIsVertexArrayAPPLE',
-                 'extensions': ['GL_APPLE_vertex_array_object'] }],
-  'arguments': 'GLuint array' },
-{ 'return_type': 'void',
-  'known_as': 'glDiscardFramebufferEXT',
-  'versions': [{ 'name': 'glInvalidateFramebuffer',
-                 'gl_versions': ['es3'],
-                 'extensions': [] },
-               { 'name': 'glDiscardFramebufferEXT',
-                 'gl_versions': ['es1', 'es2'] }],
-  'arguments': 'GLenum target, GLsizei numAttachments, '
-      'const GLenum* attachments' },
-{ 'return_type': 'void',
-  'known_as': 'glMatrixLoadfEXT',
-  'versions': [{ 'name': 'glMatrixLoadfEXT',
-                 'gl_versions': ['gl4'],
-                 'extensions': ['GL_EXT_direct_state_access'] },
-               { 'name': 'glMatrixLoadfEXT',
-                 'gl_versions': ['es3'],
-                 'extensions': ['GL_NV_path_rendering'] }],
-  'arguments': 'GLenum matrixMode, const GLfloat* m' },
-{ 'return_type': 'void',
-  'known_as': 'glMatrixLoadIdentityEXT',
-  'versions': [{ 'name': 'glMatrixLoadIdentityEXT',
-                 'gl_versions': ['gl4'],
-                 'extensions': ['GL_EXT_direct_state_access'] },
-               { 'name': 'glMatrixLoadIdentityEXT',
-                 'gl_versions': ['es3'],
-                 'extensions': ['GL_NV_path_rendering'] }],
-  'arguments': 'GLenum matrixMode' },
-  { 'return_type': 'void',
-    'known_as': 'glBlendBarrierKHR',
-    'versions': [{ 'name': 'glBlendBarrierNV',
-                   'extensions': ['GL_NV_blend_equation_advanced'] },
-                 { 'name': 'glBlendBarrierKHR',
-                   'extensions': ['GL_KHR_blend_equation_advanced'] }],
-    'arguments': 'void' },
+  'names': ['glViewport'],
+  'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', },
+{ 'return_type': 'GLenum',
+  'names': ['glWaitSync'],
+  'arguments':
+    'GLsync sync, GLbitfield flags, GLuint64 timeout', },
 ]
 
 OSMESA_FUNCTIONS = [
+{ 'return_type': 'void',
+  'names': ['OSMesaColorClamp'],
+  'arguments': 'GLboolean enable', },
 { 'return_type': 'OSMesaContext',
   'names': ['OSMesaCreateContext'],
   'arguments': 'GLenum format, OSMesaContext sharelist', },
@@ -892,69 +924,56 @@
   'names': ['OSMesaDestroyContext'],
   'arguments': 'OSMesaContext ctx', },
 { 'return_type': 'GLboolean',
-  'names': ['OSMesaMakeCurrent'],
-  'arguments': 'OSMesaContext ctx, void* buffer, GLenum type, GLsizei width, '
-               'GLsizei height', },
+  'names': ['OSMesaGetColorBuffer'],
+  'arguments': 'OSMesaContext c, GLint* width, GLint* height, GLint* format, '
+               'void** buffer', },
 { 'return_type': 'OSMesaContext',
   'names': ['OSMesaGetCurrentContext'],
   'arguments': 'void', },
-{ 'return_type': 'void',
-  'names': ['OSMesaPixelStore'],
-  'arguments': 'GLint pname, GLint value', },
-{ 'return_type': 'void',
-  'names': ['OSMesaGetIntegerv'],
-  'arguments': 'GLint pname, GLint* value', },
 { 'return_type': 'GLboolean',
   'names': ['OSMesaGetDepthBuffer'],
   'arguments':
       'OSMesaContext c, GLint* width, GLint* height, GLint* bytesPerValue, '
       'void** buffer', },
-{ 'return_type': 'GLboolean',
-  'names': ['OSMesaGetColorBuffer'],
-  'arguments': 'OSMesaContext c, GLint* width, GLint* height, GLint* format, '
-               'void** buffer', },
+{ 'return_type': 'void',
+  'names': ['OSMesaGetIntegerv'],
+  'arguments': 'GLint pname, GLint* value', },
 { 'return_type': 'OSMESAproc',
   'names': ['OSMesaGetProcAddress'],
   'arguments': 'const char* funcName', },
+{ 'return_type': 'GLboolean',
+  'names': ['OSMesaMakeCurrent'],
+  'arguments': 'OSMesaContext ctx, void* buffer, GLenum type, GLsizei width, '
+               'GLsizei height', },
 { 'return_type': 'void',
-  'names': ['OSMesaColorClamp'],
-  'arguments': 'GLboolean enable', },
+  'names': ['OSMesaPixelStore'],
+  'arguments': 'GLint pname, GLint value', },
 ]
 
 EGL_FUNCTIONS = [
-{ 'return_type': 'EGLint',
-  'names': ['eglGetError'],
-  'arguments': 'void', },
-{ 'return_type': 'EGLDisplay',
-  'names': ['eglGetDisplay'],
-  'arguments': 'EGLNativeDisplayType display_id', },
-{ 'return_type': 'EGLDisplay',
-  'known_as': 'eglGetPlatformDisplayEXT',
-  'versions': [{ 'name': 'eglGetPlatformDisplayEXT',
-                 'extensions': ['EGL_ANGLE_platform_angle'] }],
-  'arguments': 'EGLenum platform, void* native_display, '
-               'const EGLint* attrib_list', },
 { 'return_type': 'EGLBoolean',
-  'names': ['eglInitialize'],
-  'arguments': 'EGLDisplay dpy, EGLint* major, EGLint* minor', },
+  'names': ['eglBindAPI'],
+  'arguments': 'EGLenum api', },
 { 'return_type': 'EGLBoolean',
-  'names': ['eglTerminate'],
-  'arguments': 'EGLDisplay dpy', },
-{ 'return_type': 'const char*',
-  'names': ['eglQueryString'],
-  'arguments': 'EGLDisplay dpy, EGLint name', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglGetConfigs'],
-  'arguments': 'EGLDisplay dpy, EGLConfig* configs, EGLint config_size, '
-               'EGLint* num_config', },
+  'names': ['eglBindTexImage'],
+  'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', },
 { 'return_type': 'EGLBoolean',
   'names': ['eglChooseConfig'],
   'arguments': 'EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, '
                'EGLint config_size, EGLint* num_config', },
+{ 'return_type': 'EGLint',
+  'versions': [{ 'name': 'eglClientWaitSyncKHR',
+                 'extensions': ['EGL_KHR_fence_sync'] }],
+  'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, '
+      'EGLTimeKHR timeout' },
 { 'return_type': 'EGLBoolean',
-  'names': ['eglGetConfigAttrib'],
+  'names': ['eglCopyBuffers'],
   'arguments':
-      'EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value', },
+      'EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target', },
+{ 'return_type': 'EGLContext',
+  'names': ['eglCreateContext'],
+  'arguments': 'EGLDisplay dpy, EGLConfig config, EGLContext share_context, '
+              'const EGLint* attrib_list', },
 { 'return_type': 'EGLImageKHR',
   'versions': [{ 'name': 'eglCreateImageKHR',
                  'extensions':
@@ -962,14 +981,11 @@
   'arguments':
       'EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, '
       'const EGLint* attrib_list' },
-{ 'return_type': 'EGLBoolean',
-  'versions': [{ 'name' : 'eglDestroyImageKHR',
-                 'extensions': ['EGL_KHR_image_base'] }],
-  'arguments': 'EGLDisplay dpy, EGLImageKHR image' },
 { 'return_type': 'EGLSurface',
-  'names': ['eglCreateWindowSurface'],
-  'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, '
-               'const EGLint* attrib_list', },
+  'names': ['eglCreatePbufferFromClientBuffer'],
+  'arguments':
+      'EGLDisplay dpy, EGLenum buftype, void* buffer, EGLConfig config, '
+      'const EGLint* attrib_list', },
 { 'return_type': 'EGLSurface',
   'names': ['eglCreatePbufferSurface'],
   'arguments': 'EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list', },
@@ -977,144 +993,184 @@
   'names': ['eglCreatePixmapSurface'],
   'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, '
                'const EGLint* attrib_list', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglDestroySurface'],
-  'arguments': 'EGLDisplay dpy, EGLSurface surface', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglQuerySurface'],
-  'arguments':
-      'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglBindAPI'],
-  'arguments': 'EGLenum api', },
-{ 'return_type': 'EGLenum',
-  'names': ['eglQueryAPI'],
-  'arguments': 'void', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglWaitClient'],
-  'arguments': 'void', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglReleaseThread'],
-  'arguments': 'void', },
+{ 'return_type': 'EGLSyncKHR',
+  'versions': [{ 'name': 'eglCreateSyncKHR',
+                 'extensions': ['EGL_KHR_fence_sync'] }],
+  'arguments': 'EGLDisplay dpy, EGLenum type, const EGLint* attrib_list' },
 { 'return_type': 'EGLSurface',
-  'names': ['eglCreatePbufferFromClientBuffer'],
-  'arguments':
-      'EGLDisplay dpy, EGLenum buftype, void* buffer, EGLConfig config, '
-      'const EGLint* attrib_list', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglSurfaceAttrib'],
-  'arguments':
-      'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglBindTexImage'],
-  'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglReleaseTexImage'],
-  'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglSwapInterval'],
-  'arguments': 'EGLDisplay dpy, EGLint interval', },
-{ 'return_type': 'EGLContext',
-  'names': ['eglCreateContext'],
-  'arguments': 'EGLDisplay dpy, EGLConfig config, EGLContext share_context, '
-              'const EGLint* attrib_list', },
+  'names': ['eglCreateWindowSurface'],
+  'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, '
+               'const EGLint* attrib_list', },
 { 'return_type': 'EGLBoolean',
   'names': ['eglDestroyContext'],
   'arguments': 'EGLDisplay dpy, EGLContext ctx', },
 { 'return_type': 'EGLBoolean',
-  'names': ['eglMakeCurrent'],
+  'versions': [{ 'name' : 'eglDestroyImageKHR',
+                 'extensions': ['EGL_KHR_image_base'] }],
+  'arguments': 'EGLDisplay dpy, EGLImageKHR image' },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglDestroySurface'],
+  'arguments': 'EGLDisplay dpy, EGLSurface surface', },
+{ 'return_type': 'EGLBoolean',
+  'versions': [{ 'name': 'eglDestroySyncKHR',
+                 'extensions': ['EGL_KHR_fence_sync'] }],
+  'arguments': 'EGLDisplay dpy, EGLSyncKHR sync' },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglGetConfigAttrib'],
   'arguments':
-      'EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx', },
+      'EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglGetConfigs'],
+  'arguments': 'EGLDisplay dpy, EGLConfig* configs, EGLint config_size, '
+               'EGLint* num_config', },
 { 'return_type': 'EGLContext',
   'names': ['eglGetCurrentContext'],
   'arguments': 'void', },
+{ 'return_type': 'EGLDisplay',
+  'names': ['eglGetCurrentDisplay'],
+  'arguments': 'void', },
 { 'return_type': 'EGLSurface',
   'names': ['eglGetCurrentSurface'],
   'arguments': 'EGLint readdraw', },
 { 'return_type': 'EGLDisplay',
-  'names': ['eglGetCurrentDisplay'],
+  'names': ['eglGetDisplay'],
+  'arguments': 'EGLNativeDisplayType display_id', },
+{ 'return_type': 'EGLint',
+  'names': ['eglGetError'],
   'arguments': 'void', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglQueryContext'],
-  'arguments':
-      'EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglWaitGL'],
-  'arguments': 'void', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglWaitNative'],
-  'arguments': 'EGLint engine', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglSwapBuffers'],
-  'arguments': 'EGLDisplay dpy, EGLSurface surface', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglCopyBuffers'],
-  'arguments':
-      'EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target', },
+{ 'return_type': 'EGLDisplay',
+  'known_as': 'eglGetPlatformDisplayEXT',
+  'versions': [{ 'name': 'eglGetPlatformDisplayEXT',
+                 'extensions': ['EGL_ANGLE_platform_angle'] }],
+  'arguments': 'EGLenum platform, void* native_display, '
+               'const EGLint* attrib_list', },
 { 'return_type': '__eglMustCastToProperFunctionPointerType',
   'names': ['eglGetProcAddress'],
   'arguments': 'const char* procname', },
 { 'return_type': 'EGLBoolean',
-  'names': ['eglPostSubBufferNV'],
-  'arguments': 'EGLDisplay dpy, EGLSurface surface, '
-    'EGLint x, EGLint y, EGLint width, EGLint height', },
-{ 'return_type': 'EGLBoolean',
-  'names': ['eglQuerySurfacePointerANGLE'],
-  'arguments':
-      'EGLDisplay dpy, EGLSurface surface, EGLint attribute, void** value', },
-{ 'return_type': 'EGLSyncKHR',
-  'versions': [{ 'name': 'eglCreateSyncKHR',
-                 'extensions': ['EGL_KHR_fence_sync'] }],
-  'arguments': 'EGLDisplay dpy, EGLenum type, const EGLint* attrib_list' },
-{ 'return_type': 'EGLint',
-  'versions': [{ 'name': 'eglClientWaitSyncKHR',
-                 'extensions': ['EGL_KHR_fence_sync'] }],
-  'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, '
-      'EGLTimeKHR timeout' },
-{ 'return_type': 'EGLBoolean',
   'versions': [{ 'name': 'eglGetSyncAttribKHR',
                  'extensions': ['EGL_KHR_fence_sync'] }],
   'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, '
       'EGLint* value' },
 { 'return_type': 'EGLBoolean',
-  'versions': [{ 'name': 'eglDestroySyncKHR',
-                 'extensions': ['EGL_KHR_fence_sync'] }],
-  'arguments': 'EGLDisplay dpy, EGLSyncKHR sync' },
-{ 'return_type': 'EGLBoolean',
   'names': ['eglGetSyncValuesCHROMIUM'],
   'arguments':
       'EGLDisplay dpy, EGLSurface surface, '
       'EGLuint64CHROMIUM* ust, EGLuint64CHROMIUM* msc, '
       'EGLuint64CHROMIUM* sbc', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglInitialize'],
+  'arguments': 'EGLDisplay dpy, EGLint* major, EGLint* minor', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglMakeCurrent'],
+  'arguments':
+      'EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglPostSubBufferNV'],
+  'arguments': 'EGLDisplay dpy, EGLSurface surface, '
+    'EGLint x, EGLint y, EGLint width, EGLint height', },
+{ 'return_type': 'EGLenum',
+  'names': ['eglQueryAPI'],
+  'arguments': 'void', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglQueryContext'],
+  'arguments':
+      'EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value', },
+{ 'return_type': 'const char*',
+  'names': ['eglQueryString'],
+  'arguments': 'EGLDisplay dpy, EGLint name', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglQuerySurface'],
+  'arguments':
+      'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglQuerySurfacePointerANGLE'],
+  'arguments':
+      'EGLDisplay dpy, EGLSurface surface, EGLint attribute, void** value', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglReleaseTexImage'],
+  'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglReleaseThread'],
+  'arguments': 'void', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglSurfaceAttrib'],
+  'arguments':
+      'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglSwapBuffers'],
+  'arguments': 'EGLDisplay dpy, EGLSurface surface', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglSwapInterval'],
+  'arguments': 'EGLDisplay dpy, EGLint interval', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglTerminate'],
+  'arguments': 'EGLDisplay dpy', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglWaitClient'],
+  'arguments': 'void', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglWaitGL'],
+  'arguments': 'void', },
+{ 'return_type': 'EGLBoolean',
+  'names': ['eglWaitNative'],
+  'arguments': 'EGLint engine', },
 { 'return_type': 'EGLint',
   'versions': [{ 'name': 'eglWaitSyncKHR',
                  'extensions': ['EGL_KHR_fence_sync', 'EGL_KHR_wait_sync'] }],
-  'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags' }
+  'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags' },
 ]
 
 WGL_FUNCTIONS = [
+{ 'return_type': 'BOOL',
+  'names': ['wglChoosePixelFormatARB'],
+  'arguments':
+      'HDC dc, const int* int_attrib_list, const float* float_attrib_list, '
+      'UINT max_formats, int* formats, UINT* num_formats', },
+{ 'return_type': 'BOOL',
+  'names': ['wglCopyContext'],
+  'arguments': 'HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask', },
 { 'return_type': 'HGLRC',
   'names': ['wglCreateContext'],
   'arguments': 'HDC hdc', },
 { 'return_type': 'HGLRC',
   'names': ['wglCreateLayerContext'],
   'arguments': 'HDC hdc, int iLayerPlane', },
-{ 'return_type': 'BOOL',
-  'names': ['wglCopyContext'],
-  'arguments': 'HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask', },
+{ 'return_type': 'HPBUFFERARB',
+  'names': ['wglCreatePbufferARB'],
+  'arguments': 'HDC hDC, int iPixelFormat, int iWidth, int iHeight, '
+               'const int* piAttribList', },
 { 'return_type': 'BOOL',
   'names': ['wglDeleteContext'],
   'arguments': 'HGLRC hglrc', },
+{ 'return_type': 'BOOL',
+  'names': ['wglDestroyPbufferARB'],
+  'arguments': 'HPBUFFERARB hPbuffer', },
 { 'return_type': 'HGLRC',
   'names': ['wglGetCurrentContext'],
   'arguments': '', },
 { 'return_type': 'HDC',
   'names': ['wglGetCurrentDC'],
   'arguments': '', },
+{ 'return_type': 'const char*',
+  'names': ['wglGetExtensionsStringARB'],
+  'arguments': 'HDC hDC', },
+{ 'return_type': 'const char*',
+  'names': ['wglGetExtensionsStringEXT'],
+  'arguments': '', },
+{ 'return_type': 'HDC',
+  'names': ['wglGetPbufferDCARB'],
+  'arguments': 'HPBUFFERARB hPbuffer', },
 { 'return_type': 'BOOL',
   'names': ['wglMakeCurrent'],
   'arguments': 'HDC hdc, HGLRC hglrc', },
 { 'return_type': 'BOOL',
+  'names': ['wglQueryPbufferARB'],
+  'arguments': 'HPBUFFERARB hPbuffer, int iAttribute, int* piValue', },
+{ 'return_type': 'int',
+  'names': ['wglReleasePbufferDCARB'],
+  'arguments': 'HPBUFFERARB hPbuffer, HDC hDC', },
+{ 'return_type': 'BOOL',
   'names': ['wglShareLists'],
   'arguments': 'HGLRC hglrc1, HGLRC hglrc2', },
 { 'return_type': 'BOOL',
@@ -1123,43 +1179,25 @@
 { 'return_type': 'BOOL',
   'names': ['wglSwapLayerBuffers'],
   'arguments': 'HDC hdc, UINT fuPlanes', },
-{ 'return_type': 'const char*',
-  'names': ['wglGetExtensionsStringARB'],
-  'arguments': 'HDC hDC', },
-{ 'return_type': 'const char*',
-  'names': ['wglGetExtensionsStringEXT'],
-  'arguments': '', },
-{ 'return_type': 'BOOL',
-  'names': ['wglChoosePixelFormatARB'],
-  'arguments':
-      'HDC dc, const int* int_attrib_list, const float* float_attrib_list, '
-      'UINT max_formats, int* formats, UINT* num_formats', },
-{ 'return_type': 'HPBUFFERARB',
-  'names': ['wglCreatePbufferARB'],
-  'arguments': 'HDC hDC, int iPixelFormat, int iWidth, int iHeight, '
-               'const int* piAttribList', },
-{ 'return_type': 'HDC',
-  'names': ['wglGetPbufferDCARB'],
-  'arguments': 'HPBUFFERARB hPbuffer', },
-{ 'return_type': 'int',
-  'names': ['wglReleasePbufferDCARB'],
-  'arguments': 'HPBUFFERARB hPbuffer, HDC hDC', },
-{ 'return_type': 'BOOL',
-  'names': ['wglDestroyPbufferARB'],
-  'arguments': 'HPBUFFERARB hPbuffer', },
-{ 'return_type': 'BOOL',
-  'names': ['wglQueryPbufferARB'],
-  'arguments': 'HPBUFFERARB hPbuffer, int iAttribute, int* piValue', },
 ]
 
 GLX_FUNCTIONS = [
-{ 'return_type': 'int',
-  'names': ['glXWaitVideoSyncSGI'],
-  'arguments': 'int divisor, int remainder, unsigned int* count', },
+{ 'return_type': 'void',
+  'names': ['glXBindTexImageEXT'],
+  'arguments':
+      'Display* dpy, GLXDrawable drawable, int buffer, int* attribList', },
+{ 'return_type': 'GLXFBConfig*',
+  'names': ['glXChooseFBConfig'],
+  'arguments':
+      'Display* dpy, int screen, const int* attribList, int* nitems', },
 { 'return_type': 'XVisualInfo*',
   'names': ['glXChooseVisual'],
   'arguments': 'Display* dpy, int screen, int* attribList', },
 { 'return_type': 'void',
+  'names': ['glXCopyContext'],
+  'arguments':
+      'Display* dpy, GLXContext src, GLXContext dst, unsigned long mask', },
+{ 'return_type': 'void',
   'names': ['glXCopySubBufferMESA'],
   'arguments': 'Display* dpy, GLXDrawable drawable, '
                'int x, int y, int width, int height', },
@@ -1167,152 +1205,143 @@
   'names': ['glXCreateContext'],
   'arguments':
       'Display* dpy, XVisualInfo* vis, GLXContext shareList, int direct', },
-{ 'return_type': 'void',
-  'names': ['glXBindTexImageEXT'],
+{ 'return_type': 'GLXContext',
+  'names': ['glXCreateContextAttribsARB'],
   'arguments':
-      'Display* dpy, GLXDrawable drawable, int buffer, int* attribList', },
-{ 'return_type': 'void',
-  'names': ['glXReleaseTexImageEXT'],
-  'arguments': 'Display* dpy, GLXDrawable drawable, int buffer', },
-{ 'return_type': 'void',
-  'names': ['glXDestroyContext'],
-  'arguments': 'Display* dpy, GLXContext ctx', },
-{ 'return_type': 'int',
-  'names': ['glXMakeCurrent'],
-  'arguments': 'Display* dpy, GLXDrawable drawable, GLXContext ctx', },
-{ 'return_type': 'void',
-  'names': ['glXCopyContext'],
-  'arguments':
-      'Display* dpy, GLXContext src, GLXContext dst, unsigned long mask', },
-{ 'return_type': 'void',
-  'names': ['glXSwapBuffers'],
-  'arguments': 'Display* dpy, GLXDrawable drawable', },
+      'Display* dpy, GLXFBConfig config, GLXContext share_context, int direct, '
+      'const int* attrib_list', },
 { 'return_type': 'GLXPixmap',
   'names': ['glXCreateGLXPixmap'],
   'arguments': 'Display* dpy, XVisualInfo* visual, Pixmap pixmap', },
+{ 'return_type': 'GLXContext',
+  'names': ['glXCreateNewContext'],
+  'arguments': 'Display* dpy, GLXFBConfig config, int renderType, '
+               'GLXContext shareList, int direct', },
+{ 'return_type': 'GLXPbuffer',
+  'names': ['glXCreatePbuffer'],
+  'arguments': 'Display* dpy, GLXFBConfig config, const int* attribList', },
+{ 'return_type': 'GLXPixmap',
+  'names': ['glXCreatePixmap'],
+  'arguments': 'Display* dpy, GLXFBConfig config, '
+               'Pixmap pixmap, const int* attribList', },
+{ 'return_type': 'GLXWindow',
+  'names': ['glXCreateWindow'],
+  'arguments':
+      'Display* dpy, GLXFBConfig config, Window win, const int* attribList', },
+{ 'return_type': 'void',
+  'names': ['glXDestroyContext'],
+  'arguments': 'Display* dpy, GLXContext ctx', },
 { 'return_type': 'void',
   'names': ['glXDestroyGLXPixmap'],
   'arguments': 'Display* dpy, GLXPixmap pixmap', },
-{ 'return_type': 'int',
-  'names': ['glXQueryExtension'],
-  'arguments': 'Display* dpy, int* errorb, int* event', },
-{ 'return_type': 'int',
-  'names': ['glXQueryVersion'],
-  'arguments': 'Display* dpy, int* maj, int* min', },
-{ 'return_type': 'int',
-  'names': ['glXIsDirect'],
-  'arguments': 'Display* dpy, GLXContext ctx', },
+{ 'return_type': 'void',
+  'names': ['glXDestroyPbuffer'],
+  'arguments': 'Display* dpy, GLXPbuffer pbuf', },
+{ 'return_type': 'void',
+  'names': ['glXDestroyPixmap'],
+  'arguments': 'Display* dpy, GLXPixmap pixmap', },
+{ 'return_type': 'void',
+  'names': ['glXDestroyWindow'],
+  'arguments': 'Display* dpy, GLXWindow window', },
+{ 'return_type': 'const char*',
+  'names': ['glXGetClientString'],
+  'arguments': 'Display* dpy, int name', },
 { 'return_type': 'int',
   'names': ['glXGetConfig'],
   'arguments': 'Display* dpy, XVisualInfo* visual, int attrib, int* value', },
 { 'return_type': 'GLXContext',
   'names': ['glXGetCurrentContext'],
   'arguments': 'void', },
+{ 'return_type': 'Display*',
+  'names': ['glXGetCurrentDisplay'],
+  'arguments': 'void', },
 { 'return_type': 'GLXDrawable',
   'names': ['glXGetCurrentDrawable'],
   'arguments': 'void', },
-{ 'return_type': 'void',
-  'names': ['glXWaitGL'],
+{ 'return_type': 'GLXDrawable',
+  'names': ['glXGetCurrentReadDrawable'],
   'arguments': 'void', },
+{ 'return_type': 'int',
+  'names': ['glXGetFBConfigAttrib'],
+  'arguments': 'Display* dpy, GLXFBConfig config, int attribute, int* value', },
+{ 'return_type': 'GLXFBConfig',
+  'names': ['glXGetFBConfigFromVisualSGIX'],
+  'arguments': 'Display* dpy, XVisualInfo* visualInfo', },
+{ 'return_type': 'GLXFBConfig*',
+  'names': ['glXGetFBConfigs'],
+  'arguments': 'Display* dpy, int screen, int* nelements', },
+{ 'return_type': 'bool',
+  'names': ['glXGetMscRateOML'],
+  'arguments':
+      'Display* dpy, GLXDrawable drawable, int32* numerator, '
+      'int32* denominator' },
 { 'return_type': 'void',
-  'names': ['glXWaitX'],
-  'arguments': 'void', },
+  'names': ['glXGetSelectedEvent'],
+  'arguments': 'Display* dpy, GLXDrawable drawable, unsigned long* mask', },
+{ 'return_type': 'bool',
+  'names': ['glXGetSyncValuesOML'],
+  'arguments':
+      'Display* dpy, GLXDrawable drawable, int64* ust, int64* msc, '
+      'int64* sbc' },
+{ 'return_type': 'XVisualInfo*',
+  'names': ['glXGetVisualFromFBConfig'],
+  'arguments': 'Display* dpy, GLXFBConfig config', },
+{ 'return_type': 'int',
+  'names': ['glXIsDirect'],
+  'arguments': 'Display* dpy, GLXContext ctx', },
+{ 'return_type': 'int',
+  'names': ['glXMakeContextCurrent'],
+  'arguments':
+      'Display* dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx', },
+{ 'return_type': 'int',
+  'names': ['glXMakeCurrent'],
+  'arguments': 'Display* dpy, GLXDrawable drawable, GLXContext ctx', },
+{ 'return_type': 'int',
+  'names': ['glXQueryContext'],
+  'arguments': 'Display* dpy, GLXContext ctx, int attribute, int* value', },
 { 'return_type': 'void',
-  'names': ['glXUseXFont'],
-  'arguments': 'Font font, int first, int count, int list', },
+  'names': ['glXQueryDrawable'],
+  'arguments':
+      'Display* dpy, GLXDrawable draw, int attribute, unsigned int* value', },
+{ 'return_type': 'int',
+  'names': ['glXQueryExtension'],
+  'arguments': 'Display* dpy, int* errorb, int* event', },
 { 'return_type': 'const char*',
   'names': ['glXQueryExtensionsString'],
   'arguments': 'Display* dpy, int screen', },
 { 'return_type': 'const char*',
   'names': ['glXQueryServerString'],
   'arguments': 'Display* dpy, int screen, int name', },
-{ 'return_type': 'const char*',
-  'names': ['glXGetClientString'],
-  'arguments': 'Display* dpy, int name', },
-{ 'return_type': 'Display*',
-  'names': ['glXGetCurrentDisplay'],
-  'arguments': 'void', },
-{ 'return_type': 'GLXFBConfig*',
-  'names': ['glXChooseFBConfig'],
-  'arguments':
-      'Display* dpy, int screen, const int* attribList, int* nitems', },
 { 'return_type': 'int',
-  'names': ['glXGetFBConfigAttrib'],
-  'arguments': 'Display* dpy, GLXFBConfig config, int attribute, int* value', },
-{ 'return_type': 'GLXFBConfig*',
-  'names': ['glXGetFBConfigs'],
-  'arguments': 'Display* dpy, int screen, int* nelements', },
-{ 'return_type': 'XVisualInfo*',
-  'names': ['glXGetVisualFromFBConfig'],
-  'arguments': 'Display* dpy, GLXFBConfig config', },
-{ 'return_type': 'GLXWindow',
-  'names': ['glXCreateWindow'],
-  'arguments':
-      'Display* dpy, GLXFBConfig config, Window win, const int* attribList', },
+  'names': ['glXQueryVersion'],
+  'arguments': 'Display* dpy, int* maj, int* min', },
 { 'return_type': 'void',
-  'names': ['glXDestroyWindow'],
-  'arguments': 'Display* dpy, GLXWindow window', },
-{ 'return_type': 'GLXPixmap',
-  'names': ['glXCreatePixmap'],
-  'arguments': 'Display* dpy, GLXFBConfig config, '
-               'Pixmap pixmap, const int* attribList', },
-{ 'return_type': 'void',
-  'names': ['glXDestroyPixmap'],
-  'arguments': 'Display* dpy, GLXPixmap pixmap', },
-{ 'return_type': 'GLXPbuffer',
-  'names': ['glXCreatePbuffer'],
-  'arguments': 'Display* dpy, GLXFBConfig config, const int* attribList', },
-{ 'return_type': 'void',
-  'names': ['glXDestroyPbuffer'],
-  'arguments': 'Display* dpy, GLXPbuffer pbuf', },
-{ 'return_type': 'void',
-  'names': ['glXQueryDrawable'],
-  'arguments':
-      'Display* dpy, GLXDrawable draw, int attribute, unsigned int* value', },
-{ 'return_type': 'GLXContext',
-  'names': ['glXCreateNewContext'],
-  'arguments': 'Display* dpy, GLXFBConfig config, int renderType, '
-               'GLXContext shareList, int direct', },
-{ 'return_type': 'int',
-  'names': ['glXMakeContextCurrent'],
-  'arguments':
-      'Display* dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx', },
-{ 'return_type': 'GLXDrawable',
-  'names': ['glXGetCurrentReadDrawable'],
-  'arguments': 'void', },
-{ 'return_type': 'int',
-  'names': ['glXQueryContext'],
-  'arguments': 'Display* dpy, GLXContext ctx, int attribute, int* value', },
+  'names': ['glXReleaseTexImageEXT'],
+  'arguments': 'Display* dpy, GLXDrawable drawable, int buffer', },
 { 'return_type': 'void',
   'names': ['glXSelectEvent'],
   'arguments': 'Display* dpy, GLXDrawable drawable, unsigned long mask', },
 { 'return_type': 'void',
-  'names': ['glXGetSelectedEvent'],
-  'arguments': 'Display* dpy, GLXDrawable drawable, unsigned long* mask', },
+  'names': ['glXSwapBuffers'],
+  'arguments': 'Display* dpy, GLXDrawable drawable', },
+{ 'return_type': 'void',
+  'names': ['glXSwapIntervalEXT'],
+  'arguments': 'Display* dpy, GLXDrawable drawable, int interval', },
 { 'return_type': 'void',
   'names': ['glXSwapIntervalMESA'],
   'arguments': 'unsigned int interval', },
 { 'return_type': 'void',
-  'names': ['glXSwapIntervalEXT'],
-  'arguments': 'Display* dpy, GLXDrawable drawable, int interval', },
-{ 'return_type': 'GLXFBConfig',
-  'names': ['glXGetFBConfigFromVisualSGIX'],
-  'arguments': 'Display* dpy, XVisualInfo* visualInfo', },
-{ 'return_type': 'GLXContext',
-  'names': ['glXCreateContextAttribsARB'],
-  'arguments':
-      'Display* dpy, GLXFBConfig config, GLXContext share_context, int direct, '
-      'const int* attrib_list', },
-{ 'return_type': 'bool',
-  'names': ['glXGetSyncValuesOML'],
-  'arguments':
-      'Display* dpy, GLXDrawable drawable, int64* ust, int64* msc, '
-      'int64* sbc' },
-{ 'return_type': 'bool',
-  'names': ['glXGetMscRateOML'],
-  'arguments':
-      'Display* dpy, GLXDrawable drawable, int32* numerator, '
-      'int32* denominator' },
+  'names': ['glXUseXFont'],
+  'arguments': 'Font font, int first, int count, int list', },
+{ 'return_type': 'void',
+  'names': ['glXWaitGL'],
+  'arguments': 'void', },
+{ 'return_type': 'int',
+  'names': ['glXWaitVideoSyncSGI'],
+  'arguments': 'int divisor, int remainder, unsigned int* count', },
+{ 'return_type': 'void',
+  'names': ['glXWaitX'],
+  'arguments': 'void', },
 ]
 
 FUNCTION_SETS = [
@@ -1339,6 +1368,7 @@
   [GLX_FUNCTIONS, 'glx', ['GL/glx.h', 'GL/glxext.h'], []],
 ]
 
+
 def GenerateHeader(file, functions, set_name, used_extensions):
   """Generates gl_bindings_autogen_x.h"""
 
@@ -2028,6 +2058,7 @@
   parser = optparse.OptionParser()
   parser.add_option('--inputs', action='store_true')
   parser.add_option('--header-paths')
+  parser.add_option('--verify-order', action='store_true')
 
   options, args = parser.parse_args(argv)
 
@@ -2056,6 +2087,16 @@
       if 'names' in func:
         del func['names']
 
+    # Check function names in each set is sorted in alphabetical order.
+    for index in range(len(functions) - 1):
+      func_name = functions[index]['known_as']
+      next_func_name = functions[index + 1]['known_as']
+      if func_name.lower() > next_func_name.lower():
+        raise Exception(
+            'function %s is not in alphabetical order' % next_func_name)
+    if options.verify_order:
+      continue
+
     extension_headers = [ResolveHeader(h, options.header_paths)
                          for h in extension_headers]
     used_extensions = FillExtensionsFromHeaders(
@@ -2077,20 +2118,21 @@
     GenerateSource(source_file, functions, set_name, used_extensions)
     source_file.close()
 
-  header_file = open(
-      os.path.join(directory, 'gl_mock_autogen_gl.h'), 'wb')
-  GenerateMockHeader(header_file, GL_FUNCTIONS, 'gl')
-  header_file.close()
+  if not options.verify_order:
+    header_file = open(
+        os.path.join(directory, 'gl_mock_autogen_gl.h'), 'wb')
+    GenerateMockHeader(header_file, GL_FUNCTIONS, 'gl')
+    header_file.close()
 
-  header_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.h'),
-                     'wb')
-  GenerateMockBindingsHeader(header_file, GL_FUNCTIONS)
-  header_file.close()
+    header_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.h'),
+                       'wb')
+    GenerateMockBindingsHeader(header_file, GL_FUNCTIONS)
+    header_file.close()
 
-  source_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.cc'),
-                     'wb')
-  GenerateMockBindingsSource(source_file, GL_FUNCTIONS)
-  source_file.close()
+    source_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.cc'),
+                       'wb')
+    GenerateMockBindingsSource(source_file, GL_FUNCTIONS)
+    source_file.close()
   return 0
 
 
diff --git a/ui/gl/gl.gyp b/ui/gl/gl.gyp
index cd0a852..cd33d7a 100644
--- a/ui/gl/gl.gyp
+++ b/ui/gl/gl.gyp
@@ -263,6 +263,8 @@
           'sources': [
             'gl_context_cgl.cc',
             'gl_context_cgl.h',
+            'gl_fence_apple.cc',
+            'gl_fence_apple.h',
             'gl_image_io_surface.cc',
             'gl_image_io_surface.h',
             'scoped_cgl.cc',
@@ -310,14 +312,6 @@
             '../android/ui_android.gyp:ui_java',
           ],
         }],
-        ['ubsan==1', {
-          # Due to a bug in LLVM (http://llvm.org/bugs/show_bug.cgi?id=21349),
-          # compilation hangs for some GL source files. Disable -O2 temporarily
-          # until http://crbug.com/426271 is fixed.
-          'cflags!': [
-            '-O2',
-          ],
-        }],
       ],
     },
     {
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h
index dd737f4..aea47fc 100644
--- a/ui/gl/gl_bindings.h
+++ b/ui/gl/gl_bindings.h
@@ -143,6 +143,10 @@
 #define GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM         0x9249
 #define GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM         0x924A
 
+// GL_CHROMIUM_subscribe_uniforms
+#define GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM             0x924B
+#define GL_MOUSE_POSITION_CHROMIUM                       0x924C
+
 // GL_OES_texure_3D
 #define GL_SAMPLER_3D_OES                                0x8B5F
 
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc
index 41c10dc..733ad8d 100644
--- a/ui/gl/gl_context_egl.cc
+++ b/ui/gl/gl_context_egl.cc
@@ -183,8 +183,6 @@
   if (!eglSwapInterval(display_, interval)) {
     LOG(ERROR) << "eglSwapInterval failed with error "
                << GetLastEGLErrorString();
-  } else {
-    GLSurface::GetCurrent()->SetSwapInterval(interval);
   }
 }
 
diff --git a/ui/gl/gl_fence.cc b/ui/gl/gl_fence.cc
index 5186f23..c254411 100644
--- a/ui/gl/gl_fence.cc
+++ b/ui/gl/gl_fence.cc
@@ -13,6 +13,10 @@
 #include "ui/gl/gl_gl_api_implementation.h"
 #include "ui/gl/gl_version_info.h"
 
+#if defined(OS_MACOSX)
+#include "ui/gl/gl_fence_apple.h"
+#endif
+
 namespace gfx {
 
 namespace {
@@ -27,7 +31,10 @@
   if (g_driver_gl.ext.b_GL_ARB_sync ||
       GetGLVersionInfo()->is_es3) {
     fence.reset(new GLFenceARB(flush));
-#if !defined(OS_MACOSX)
+#if defined(OS_MACOSX)
+  } else if (g_driver_gl.ext.b_GL_APPLE_fence) {
+    fence.reset(new GLFenceAPPLE(flush));
+#else
   } else if (g_driver_egl.ext.b_EGL_KHR_fence_sync) {
     fence.reset(new GLFenceEGL(flush));
 #endif
@@ -50,7 +57,9 @@
 bool GLFence::IsSupported() {
   DCHECK(GetGLVersionInfo());
   return g_driver_gl.ext.b_GL_ARB_sync || GetGLVersionInfo()->is_es3 ||
-#if !defined(OS_MACOSX)
+#if defined(OS_MACOSX)
+         g_driver_gl.ext.b_GL_APPLE_fence ||
+#else
          g_driver_egl.ext.b_EGL_KHR_fence_sync ||
 #endif
          g_driver_gl.ext.b_GL_NV_fence;
diff --git a/ui/gl/gl_fence_apple.cc b/ui/gl/gl_fence_apple.cc
new file mode 100644
index 0000000..9df0cad
--- /dev/null
+++ b/ui/gl/gl_fence_apple.cc
@@ -0,0 +1,47 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gl/gl_fence_apple.h"
+
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+
+namespace gfx {
+
+GLFenceAPPLE::GLFenceAPPLE(bool flush) {
+  glGenFencesAPPLE(1, &fence_);
+  glSetFenceAPPLE(fence_);
+  DCHECK(glIsFenceAPPLE(fence_));
+  if (flush) {
+    glFlush();
+  } else {
+    flush_event_ = GLContext::GetCurrent()->SignalFlush();
+  }
+}
+
+bool GLFenceAPPLE::HasCompleted() {
+  DCHECK(glIsFenceAPPLE(fence_));
+  return !!glTestFenceAPPLE(fence_);
+}
+
+void GLFenceAPPLE::ClientWait() {
+  DCHECK(glIsFenceAPPLE(fence_));
+  if (!flush_event_.get() || flush_event_->IsSignaled()) {
+    glFinishFenceAPPLE(fence_);
+  } else {
+    LOG(ERROR) << "Trying to wait for uncommitted fence. Skipping...";
+  }
+}
+
+void GLFenceAPPLE::ServerWait() {
+  DCHECK(glIsFenceAPPLE(fence_));
+  ClientWait();
+}
+
+GLFenceAPPLE::~GLFenceAPPLE() {
+  DCHECK(glIsFenceAPPLE(fence_));
+  glDeleteFencesAPPLE(1, &fence_);
+}
+
+}  // namespace gfx
diff --git a/ui/gl/gl_fence_apple.h b/ui/gl/gl_fence_apple.h
new file mode 100644
index 0000000..6c8633d
--- /dev/null
+++ b/ui/gl/gl_fence_apple.h
@@ -0,0 +1,34 @@
+// 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 UI_GL_GL_FENCE_APPLE_H_
+#define UI_GL_GL_FENCE_APPLE_H_
+
+#include "base/macros.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_fence.h"
+
+namespace gfx {
+
+class GL_EXPORT GLFenceAPPLE : public GLFence {
+ public:
+  GLFenceAPPLE(bool flush);
+  ~GLFenceAPPLE() override;
+
+  // GLFence implementation:
+  bool HasCompleted() override;
+  void ClientWait() override;
+  void ServerWait() override;
+
+ private:
+  GLuint fence_;
+  scoped_refptr<GLContext::FlushEvent> flush_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(GLFenceAPPLE);
+};
+
+}  // namespace gfx
+
+#endif  // UI_GL_GL_FENCE_APPLE_H_
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index a818a60..4459d48 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -266,9 +266,6 @@
   return extensions.find(delimited_name) != std::string::npos;
 }
 
-void GLSurface::SetSwapInterval(int interval) {
-}
-
 GLSurfaceAdapter::GLSurfaceAdapter(GLSurface* surface) : surface_(surface) {}
 
 bool GLSurfaceAdapter::Initialize() {
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 0a7607f..d458063 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -134,8 +134,6 @@
 
   static GLSurface* GetCurrent();
 
-  virtual void SetSwapInterval(int interval);
-
  protected:
   virtual ~GLSurface();
   static bool InitializeOneOffImplementation(GLImplementation impl,
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index c34ca0e..19119a9 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -45,8 +45,11 @@
 #if !defined(EGL_PLATFORM_ANGLE_TYPE_ANGLE)
 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
 #endif
-#if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE)
-#define EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206
+#if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3207
+#endif
+#if !defined(EGL_PLATFORM_ANGLE_USE_WARP_ANGLE)
+#define EGL_PLATFORM_ANGLE_USE_WARP_ANGLE 0x3208
 #endif
 #endif  // defined(OS_WIN)
 
@@ -54,8 +57,6 @@
 
 namespace gfx {
 
-unsigned int NativeViewGLSurfaceEGL::current_swap_generation_ = 0;
-
 namespace {
 
 EGLConfig g_config;
@@ -252,8 +253,8 @@
 
 #if defined(OS_WIN)
 static const EGLint kDisplayAttribsWarp[] {
-  EGL_PLATFORM_ANGLE_TYPE_ANGLE,
-  EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE,
+  EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+  EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_TRUE,
   EGL_NONE
 };
 
@@ -288,9 +289,7 @@
       surface_(NULL),
       supports_post_sub_buffer_(false),
       config_(NULL),
-      size_(1, 1),
-      swap_interval_(1),
-      swap_generation_(0) {
+      size_(1, 1) {
 #if defined(OS_ANDROID)
   if (window)
     ANativeWindow_acquire(window);
@@ -454,37 +453,12 @@
       "width", GetSize().width(),
       "height", GetSize().height());
 
-#if defined(OS_WIN)
-  bool force_no_vsync = false;
-  if (swap_interval_ != 0) {
-    // This code is a simple way of enforcing that only one surface actually
-    // vsyncs per frame. This provides single window cases a stable refresh
-    // while allowing multi-window cases to not slow down due to multiple syncs
-    // on a single thread. A better way to fix this problem would be to have
-    // each surface present on its own thread.
-    if (current_swap_generation_ == swap_generation_) {
-      current_swap_generation_++;
-    } else {
-      force_no_vsync = true;
-      eglSwapInterval(GetDisplay(), 0);
-    }
-
-    swap_generation_ = current_swap_generation_;
-  }
-#endif
-
   if (!eglSwapBuffers(GetDisplay(), surface_)) {
     DVLOG(1) << "eglSwapBuffers failed with error "
              << GetLastEGLErrorString();
     return false;
   }
 
-#if defined(OS_WIN)
-  if (force_no_vsync) {
-    eglSwapInterval(GetDisplay(), swap_interval_);
-  }
-#endif
-
   return true;
 }
 
@@ -559,10 +533,6 @@
   return vsync_provider_.get();
 }
 
-void NativeViewGLSurfaceEGL::SetSwapInterval(int interval) {
-  swap_interval_ = interval;
-}
-
 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
   Destroy();
 #if defined(OS_ANDROID)
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h
index b832ef6..952ccad 100644
--- a/ui/gl/gl_surface_egl.h
+++ b/ui/gl/gl_surface_egl.h
@@ -82,8 +82,6 @@
 
   EGLNativeWindowType window_;
 
-  virtual void SetSwapInterval(int interval) override;
-
  private:
   EGLSurface surface_;
   bool supports_post_sub_buffer_;
@@ -92,10 +90,6 @@
 
   scoped_ptr<VSyncProvider> vsync_provider_;
 
-  int swap_interval_;
-  unsigned int swap_generation_;
-  static unsigned int current_swap_generation_;
-
   DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceEGL);
 };
 
diff --git a/ui/gl/gl_surface_win.cc b/ui/gl/gl_surface_win.cc
index c424e87..5cf68af 100644
--- a/ui/gl/gl_surface_win.cc
+++ b/ui/gl/gl_surface_win.cc
@@ -31,8 +31,11 @@
 #if !defined(EGL_PLATFORM_ANGLE_TYPE_ANGLE)
 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
 #endif
-#if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE)
-#define EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206
+#if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3207
+#endif
+#if !defined(EGL_PLATFORM_ANGLE_USE_WARP_ANGLE)
+#define EGL_PLATFORM_ANGLE_USE_WARP_ANGLE 0x3208
 #endif
 
 namespace gfx {