Update from https://crrev.com/308331

Fix ui/compositor/compositor.(h|cpp) based on http://crrev.com/738983002

Fix sky/engine based on current Blink code

R=qsr@chromium.org

Review URL: https://codereview.chromium.org/812543002
diff --git a/DEPS b/DEPS
index b65d15f..79ed2f1 100644
--- a/DEPS
+++ b/DEPS
@@ -22,19 +22,19 @@
   'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d',
   'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95',
   'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
-  'skia_revision': '3054be16dfdb0d06233770cbfc338958edef44ea',
+  'skia_revision': '912ed6ebb8e2813e72ed7a3dec3b6710ba7e7405',
   # 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': 'a2359f44508afdb9abe8cb89cdfb02a7b48095b2',
+  'v8_revision': '74869d9a9122e26952e517bcc7ad990078644047',
   # 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": "16545669136028420f67ac496c45c2e9a32ed5a9",
+  "angle_revision": "797ff4c0ecf1b4950f6948175ea38ccbe888de7f",
   # 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': '05dd6a24723170d7c6ff35b537ee02947f619891',
+  'buildtools_revision': '4995faa4a7ad968f1fa1917c26edd5cea295582f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -78,7 +78,7 @@
    Var('chromium_git') + '/angle/angle.git' + '@' +  Var('angle_revision'),
 
   'src/third_party/icu':
-   Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '53ecf0f68b27a004bef5526553b8e5f6c235b80b',
+   Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'b0932a04c79198b0fd44282304eb48a5c1850ea3',
 
   'src/third_party/libc++/trunk':
    Var('chromium_git') + '/chromium/llvm-project/libcxx.git' + '@' +  Var('libcxx_revision'),
@@ -152,7 +152,7 @@
         Var('chromium_git') + '/external/jsr-305.git' + '@' + '642c508235471f7220af6d5df2d3210e3bfc0919',
 
     'src/third_party/android_tools':
-     Var('chromium_git') + '/android_tools.git' + '@' + '4f723e2a5fa5b7b8a198072ac19b92344be2b271',
+     Var('chromium_git') + '/android_tools.git' + '@' + '8fe116f93f350dcf73c6fe70db893985bf1b91d5',
 
     'src/third_party/freetype':
        Var('chromium_git') + '/chromium/src/third_party/freetype.git' + '@' + 'a2b9955b49034a51dfbc8bf9f4e9d312149cecac',
diff --git a/base/BUILD.gn b/base/BUILD.gn
index fe03aac..de464f9 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -121,6 +121,8 @@
     "cancelable_callback.h",
     "command_line.cc",
     "command_line.h",
+    "chromeos/memory_pressure_observer_chromeos.cc",
+    "chromeos/memory_pressure_observer_chromeos.h",
     "compiler_specific.h",
     "containers/adapters.h",
     "containers/hash_tables.h",
@@ -249,6 +251,8 @@
     "ios/ios_util.mm",
     "ios/scoped_critical_action.h",
     "ios/scoped_critical_action.mm",
+    "ios/weak_nsobject.h",
+    "ios/weak_nsobject.mm",
     "json/json_file_value_serializer.cc",
     "json/json_file_value_serializer.h",
     "json/json_parser.cc",
@@ -771,6 +775,12 @@
     "//third_party/modp_b64",
   ]
 
+  # Allow more direct string conversions on platforms with native utf8
+  # strings
+  if (is_mac || is_ios || is_chromeos) {
+    defines += [ "SYSTEM_NATIVE_UTF8" ]
+  }
+
   if (is_android) {
     sources += [
       "memory/discardable_memory_ashmem_allocator.cc",
@@ -1187,6 +1197,7 @@
     "i18n/time_formatting_unittest.cc",
     "i18n/timezone_unittest.cc",
     "ios/device_util_unittest.mm",
+    "ios/weak_nsobject_unittest.mm",
     "json/json_parser_unittest.cc",
     "json/json_reader_unittest.cc",
     "json/json_value_converter_unittest.cc",
diff --git a/base/base.gyp b/base/base.gyp
index ec5444a..d3a55b8 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -519,6 +519,7 @@
         'i18n/time_formatting_unittest.cc',
         'i18n/timezone_unittest.cc',
         'ios/device_util_unittest.mm',
+        'ios/weak_nsobject_unittest.mm',
         'json/json_parser_unittest.cc',
         'json/json_reader_unittest.cc',
         'json/json_value_converter_unittest.cc',
diff --git a/base/base.gypi b/base/base.gypi
index f945166..5ec4142 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -122,6 +122,8 @@
           'callback_internal.h',
           'callback_list.h',
           'cancelable_callback.h',
+          'chromeos/memory_pressure_observer_chromeos.cc',
+          'chromeos/memory_pressure_observer_chromeos.h',
           'command_line.cc',
           'command_line.h',
           'compiler_specific.h',
@@ -251,6 +253,8 @@
           'ios/ios_util.mm',
           'ios/scoped_critical_action.h',
           'ios/scoped_critical_action.mm',
+          'ios/weak_nsobject.h',
+          'ios/weak_nsobject.mm',
           'json/json_file_value_serializer.cc',
           'json/json_file_value_serializer.h',
           'json/json_parser.cc',
@@ -979,6 +983,11 @@
           ['OS == "win" and >(nacl_untrusted_build)==1', {
               'sources/': [ ['exclude', '\\.h$'] ],
           }],
+          # Enable more direct string conversions on platforms with native utf8
+          # strings
+          ['OS=="mac" or OS=="ios" or <(chromeos)==1 or <(chromecast)==1', {
+            'defines': ['SYSTEM_NATIVE_UTF8'],
+          }],
         ],
       }],
       ['base_i18n_target==1', {
diff --git a/base/chromeos/OWNERS b/base/chromeos/OWNERS
new file mode 100644
index 0000000..8fda46a
--- /dev/null
+++ b/base/chromeos/OWNERS
@@ -0,0 +1,3 @@
+skuhne@chromium.org
+oshima@chromium.org
+
diff --git a/base/chromeos/memory_pressure_observer_chromeos.cc b/base/chromeos/memory_pressure_observer_chromeos.cc
new file mode 100644
index 0000000..d991e3f
--- /dev/null
+++ b/base/chromeos/memory_pressure_observer_chromeos.cc
@@ -0,0 +1,116 @@
+// 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 "base/chromeos/memory_pressure_observer_chromeos.h"
+
+#include "base/process/process_metrics.h"
+#include "base/time/time.h"
+
+namespace base {
+
+namespace {
+
+// The time between memory pressure checks.
+const int kMemoryPressureIntervalInMS = 1000;
+
+// Converts free percent of memory into a memory pressure value.
+MemoryPressureObserverChromeOS::MemoryPressureLevel
+GetMemoryPressureLevelFromFillLevel(
+    int memory_fill_level) {
+  if (memory_fill_level < 50)
+    return MemoryPressureObserverChromeOS::MEMORY_PRESSURE_LEVEL_LOW;
+  if (memory_fill_level < 75)
+    return MemoryPressureObserverChromeOS::MEMORY_PRESSURE_LEVEL_MODERATE;
+  if (memory_fill_level < 90)
+    return MemoryPressureObserverChromeOS::MEMORY_PRESSURE_LEVEL_HIGH;
+  return MemoryPressureObserverChromeOS::MEMORY_PRESSURE_LEVEL_CRITICAL;
+}
+
+// Gets the used ChromeOS memory in percent.
+int GetUsedMemoryInPercent() {
+  base::SystemMemoryInfoKB info;
+  if (!base::GetSystemMemoryInfo(&info)) {
+    VLOG(1) << "Cannot determine the free memory of the system.";
+    return 0;
+  }
+  // TODO(skuhne): Instead of adding the kernel memory pressure calculation
+  // logic here, we should have a kernel mechanism similar to the low memory
+  // notifier in ChromeOS which offers multiple pressure states.
+  // To track this, we have crbug.com/381196.
+
+  // The available memory consists of "real" and virtual (z)ram memory.
+  // Since swappable memory uses a non pre-deterministic compression and
+  // the compression creates its own "dynamic" in the system, it gets
+  // de-emphasized by the |kSwapWeight| factor.
+  const int kSwapWeight = 4;
+
+  // The total memory we have is the "real memory" plus the virtual (z)ram.
+  int total_memory = info.total + info.swap_total / kSwapWeight;
+
+  // The kernel internally uses 50MB.
+  const int kMinFileMemory = 50 * 1024;
+
+  // Most file memory can be easily reclaimed.
+  int file_memory = info.active_file + info.inactive_file;
+  // unless it is dirty or it's a minimal portion which is required.
+  file_memory -= info.dirty + kMinFileMemory;
+
+  // Available memory is the sum of free, swap and easy reclaimable memory.
+  int available_memory =
+      info.free + info.swap_free / kSwapWeight + file_memory;
+
+  DCHECK(available_memory < total_memory);
+  int percentage = ((total_memory - available_memory) * 100) / total_memory;
+  return percentage;
+}
+
+}  // namespace
+
+MemoryPressureObserverChromeOS::MemoryPressureObserverChromeOS()
+    : current_memory_pressure_level_(MEMORY_PRESSURE_LEVEL_LOW) {
+  StartObserving();
+}
+
+MemoryPressureObserverChromeOS::~MemoryPressureObserverChromeOS() {
+  StopObserving();
+}
+
+void MemoryPressureObserverChromeOS::StartObserving() {
+  timer_.Start(FROM_HERE,
+               base::TimeDelta::FromMilliseconds(kMemoryPressureIntervalInMS),
+               base::Bind(&MemoryPressureObserverChromeOS::CheckMemoryPressure,
+                          base::Unretained(this)));
+}
+
+void MemoryPressureObserverChromeOS::StopObserving() {
+  // If StartObserving failed, StopObserving will still get called.
+  timer_.Stop();
+}
+
+void MemoryPressureObserverChromeOS::CheckMemoryPressure() {
+  MemoryPressureLevel old_pressure = current_memory_pressure_level_;
+  MemoryPressureLevel new_pressure =
+      GetMemoryPressureLevelFromFillLevel(GetUsedMemoryInPercent());
+  if (old_pressure != new_pressure) {
+    current_memory_pressure_level_ = new_pressure;
+    switch (new_pressure) {
+      case MEMORY_PRESSURE_LEVEL_LOW:
+        // The |MemoryPressureListener| does currently not support this.
+        break;
+      case MEMORY_PRESSURE_LEVEL_MODERATE:
+        MemoryPressureListener::NotifyMemoryPressure(
+            MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
+        break;
+      case MEMORY_PRESSURE_LEVEL_HIGH:
+        // The |MemoryPressureListener| does currently not support this.
+        break;
+      case MEMORY_PRESSURE_LEVEL_CRITICAL:
+        MemoryPressureListener::NotifyMemoryPressure(
+            MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+        break;
+    }
+  }
+}
+
+}  // namespace base
diff --git a/base/chromeos/memory_pressure_observer_chromeos.h b/base/chromeos/memory_pressure_observer_chromeos.h
new file mode 100644
index 0000000..92b1c48
--- /dev/null
+++ b/base/chromeos/memory_pressure_observer_chromeos.h
@@ -0,0 +1,81 @@
+// 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 BASE_CHROMEOS_MEMORY_PRESSURE_OBSERVER_CHROMEOS_H_
+#define BASE_CHROMEOS_MEMORY_PRESSURE_OBSERVER_CHROMEOS_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/timer/timer.h"
+
+namespace base {
+
+////////////////////////////////////////////////////////////////////////////////
+// MemoryPressureObserverChromeOS
+//
+// A class to handle the observation of our free memory. It notifies the
+// MemoryPressureListener of memory fill level changes, so that it can take
+// action to reduce memory resources accordingly.
+//
+class BASE_EXPORT MemoryPressureObserverChromeOS {
+ public:
+  // This is like the |MemoryPressureListener::MemoryPressureLevel| but it has
+  // more states to allow for a finer grained control as well as a request for
+  // the current status.
+  // TODO(skuhne): If the |MemoryPressureListener| will get extended to support
+  // all these levels, this can be removed.
+  enum MemoryPressureLevel {
+    // There is enough memory available to use.
+    MEMORY_PRESSURE_LEVEL_LOW = 0,
+
+    // Modules are advised to free buffers that are cheap to re-allocate and not
+    // immediately needed.
+    MEMORY_PRESSURE_LEVEL_MODERATE = 1,
+
+    // Modules are advised that they might get unloaded dependent on the OS.
+    // As such they should start to release more memory if possible.
+    MEMORY_PRESSURE_LEVEL_HIGH = 2,
+
+    // At this level, modules are advised to free all possible memory.  The
+    // alternative is to be killed by the system, which means all memory will
+    // have to be re-created, plus the cost of a cold start.
+    MEMORY_PRESSURE_LEVEL_CRITICAL = 3,
+  };
+
+  MemoryPressureObserverChromeOS();
+  ~MemoryPressureObserverChromeOS();
+
+  // Get the current memory pressure level.
+  MemoryPressureLevel GetCurrentPressureLevel() {
+    return current_memory_pressure_level_;
+  }
+
+ private:
+  // Starts observing the memory fill level.
+  // Calls to StartObserving should always be matched with calls to
+  // StopObserving.
+  void StartObserving();
+
+  // Stop observing the memory fill level.
+  // May be safely called if StartObserving has not been called.
+  void StopObserving();
+
+  // The function which gets periodically be called to check any changes in the
+  // memory pressure.
+  void CheckMemoryPressure();
+
+  // The current memory pressure.
+  MemoryPressureLevel current_memory_pressure_level_;
+
+  // A periodic timer to check for resource pressure changes. This will get
+  // replaced by a kernel triggered event system (see crbug.com/381196).
+  base::RepeatingTimer<MemoryPressureObserverChromeOS> timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureObserverChromeOS);
+};
+
+}  // namespace base
+
+#endif  // BASE_CHROMEOS_MEMORY_PRESSURE_OBSERVER_CHROMEOS_H_
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
index 1a64eb0..4591286 100644
--- a/base/debug/trace_event_impl.cc
+++ b/base/debug/trace_event_impl.cc
@@ -2358,24 +2358,6 @@
           str.at(str.length() - 1) == ' ';
 }
 
-bool CategoryFilter::DoesCategoryGroupContainCategory(
-    const char* category_group,
-    const char* category) const {
-  DCHECK(category);
-  CStringTokenizer category_group_tokens(category_group,
-                          category_group + strlen(category_group), ",");
-  while (category_group_tokens.GetNext()) {
-    std::string category_group_token = category_group_tokens.token();
-    // Don't allow empty tokens, nor tokens with leading or trailing space.
-    DCHECK(!CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
-        category_group_token))
-        << "Disallowed category string";
-    if (MatchPattern(category_group_token.c_str(), category))
-      return true;
-  }
-  return false;
-}
-
 CategoryFilter::CategoryFilter(const std::string& filter_string) {
   if (!filter_string.empty())
     Initialize(filter_string);
@@ -2483,30 +2465,61 @@
     const char* category_group_name) const {
   // TraceLog should call this method only as  part of enabling/disabling
   // categories.
+
+  bool had_enabled_by_default = false;
+  DCHECK(category_group_name);
+  CStringTokenizer category_group_tokens(
+      category_group_name, category_group_name + strlen(category_group_name),
+      ",");
+  while (category_group_tokens.GetNext()) {
+    std::string category_group_token = category_group_tokens.token();
+    // Don't allow empty tokens, nor tokens with leading or trailing space.
+    DCHECK(!CategoryFilter::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+               category_group_token))
+        << "Disallowed category string";
+    if (IsCategoryEnabled(category_group_token.c_str())) {
+      return true;
+    }
+    if (!MatchPattern(category_group_token.c_str(),
+                      TRACE_DISABLED_BY_DEFAULT("*")))
+      had_enabled_by_default = true;
+  }
+  // Do a second pass to check for explicitly disabled categories
+  // (those explicitly enabled have priority due to first pass).
+  category_group_tokens.Reset();
+  while (category_group_tokens.GetNext()) {
+    std::string category_group_token = category_group_tokens.token();
+    for (StringList::const_iterator ci = excluded_.begin();
+         ci != excluded_.end(); ++ci) {
+      if (MatchPattern(category_group_token.c_str(), ci->c_str()))
+        return false;
+    }
+  }
+  // If the category group is not excluded, and there are no included patterns
+  // we consider this category group enabled, as long as it had categories
+  // other than disabled-by-default.
+  return included_.empty() && had_enabled_by_default;
+}
+
+bool CategoryFilter::IsCategoryEnabled(const char* category_name) const {
   StringList::const_iterator ci;
 
   // Check the disabled- filters and the disabled-* wildcard first so that a
   // "*" filter does not include the disabled.
   for (ci = disabled_.begin(); ci != disabled_.end(); ++ci) {
-    if (DoesCategoryGroupContainCategory(category_group_name, ci->c_str()))
+    if (MatchPattern(category_name, ci->c_str()))
       return true;
   }
-  if (DoesCategoryGroupContainCategory(category_group_name,
-                                       TRACE_DISABLED_BY_DEFAULT("*")))
+
+  if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
     return false;
 
   for (ci = included_.begin(); ci != included_.end(); ++ci) {
-    if (DoesCategoryGroupContainCategory(category_group_name, ci->c_str()))
+    if (MatchPattern(category_name, ci->c_str()))
       return true;
   }
 
-  for (ci = excluded_.begin(); ci != excluded_.end(); ++ci) {
-    if (DoesCategoryGroupContainCategory(category_group_name, ci->c_str()))
-      return false;
-  }
-  // If the category group is not excluded, and there are no included patterns
-  // we consider this pattern enabled.
-  return included_.empty();
+  return false;
 }
 
 bool CategoryFilter::HasIncludedPatterns() const {
diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h
index ce2e017..c80826c 100644
--- a/base/debug/trace_event_impl.h
+++ b/base/debug/trace_event_impl.h
@@ -320,8 +320,8 @@
   // categories are distinguished from included categories by the prefix '-'.
   std::string ToString() const;
 
-  // Determines whether category group would be enabled or
-  // disabled by this category filter.
+  // Returns true if at least one category in the list is enabled by this
+  // category filter.
   bool IsCategoryGroupEnabled(const char* category_group) const;
 
   // Return a list of the synthetic delays specified in this category filter.
@@ -341,6 +341,9 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture, CategoryFilter);
 
+  // Returns true if category is enable according to this filter.
+  bool IsCategoryEnabled(const char* category_name) const;
+
   static bool IsEmptyOrContainsLeadingOrTrailingWhitespace(
       const std::string& str);
 
@@ -351,9 +354,6 @@
   void WriteString(const StringList& delays, std::string* out) const;
   bool HasIncludedPatterns() const;
 
-  bool DoesCategoryGroupContainCategory(const char* category_group,
-                                        const char* category) const;
-
   StringList included_;
   StringList disabled_;
   StringList excluded_;
diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc
index 0904954..85cf4eb 100644
--- a/base/debug/trace_event_unittest.cc
+++ b/base/debug/trace_event_unittest.cc
@@ -1615,6 +1615,22 @@
     EXPECT_FIND_("disabled-by-default-cc");
     EXPECT_FIND_("other_included");
   }
+
+  Clear();
+
+  BeginSpecificTrace("other_included");
+  TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc") ",other_included",
+                       "first", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("other_included," TRACE_DISABLED_BY_DEFAULT("cc"),
+                       "second", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+
+  {
+    const DictionaryValue* item = NULL;
+    ListValue& trace_parsed = trace_parsed_;
+    EXPECT_FIND_("disabled-by-default-cc,other_included");
+    EXPECT_FIND_("other_included,disabled-by-default-cc");
+  }
 }
 
 TEST_F(TraceEventTestFixture, NormallyNoDeepCopy) {
diff --git a/base/files/file_path.cc b/base/files/file_path.cc
index bf37be6..33d5ca1 100644
--- a/base/files/file_path.cc
+++ b/base/files/file_path.cc
@@ -593,7 +593,7 @@
 }
 
 std::string FilePath::AsUTF8Unsafe() const {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(SYSTEM_NATIVE_UTF8)
   return value();
 #else
   return WideToUTF8(SysNativeMBToWide(value()));
@@ -601,7 +601,7 @@
 }
 
 string16 FilePath::AsUTF16Unsafe() const {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(SYSTEM_NATIVE_UTF8)
   return UTF8ToUTF16(value());
 #else
   return WideToUTF16(SysNativeMBToWide(value()));
@@ -610,7 +610,7 @@
 
 // static
 FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(SYSTEM_NATIVE_UTF8)
   return FilePath(utf8);
 #else
   return FilePath(SysWideToNativeMB(UTF8ToWide(utf8)));
@@ -619,7 +619,7 @@
 
 // static
 FilePath FilePath::FromUTF16Unsafe(const string16& utf16) {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(SYSTEM_NATIVE_UTF8)
   return FilePath(UTF16ToUTF8(utf16));
 #else
   return FilePath(SysWideToNativeMB(UTF16ToWide(utf16)));
diff --git a/base/ios/weak_nsobject.h b/base/ios/weak_nsobject.h
new file mode 100644
index 0000000..46aecb5
--- /dev/null
+++ b/base/ios/weak_nsobject.h
@@ -0,0 +1,166 @@
+// 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 BASE_IOS_WEAK_NSOBJECT_H_
+#define BASE_IOS_WEAK_NSOBJECT_H_
+
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread_checker.h"
+
+// WeakNSObject<> is patterned after scoped_nsobject<>, but instead of
+// maintaining ownership of an NSObject subclass object, it will nil itself out
+// when the object is deallocated.
+//
+// WeakNSProtocol<> has the same behavior as WeakNSObject, but can be used
+// with protocols.
+//
+// Example usage (base::WeakNSObject<T>):
+//   scoped_nsobject<Foo> foo([[Foo alloc] init]);
+//   WeakNSObject<Foo> weak_foo;  // No pointer
+//   weak_foo.reset(foo)  // Now a weak reference is kept.
+//   [weak_foo description];  // Returns [foo description].
+//   foo.reset();  // The reference is released.
+//   [weak_foo description];  // Returns nil, as weak_foo is pointing to nil.
+//
+//
+// Implementation wise a WeakNSObject keeps a reference to a refcounted
+// WeakContainer. There is one unique instance of a WeakContainer per watched
+// NSObject, this relationship is maintained via the ObjectiveC associated
+// object API, indirectly via an ObjectiveC CRBWeakNSProtocolSentinel class.
+//
+// The implementation assumes that the tracked object will be released on the
+// same thread that the WeakNSObject is created on.
+//
+namespace base {
+
+// WeakContainer keeps a weak pointer to an object and clears it when it
+// receives nullify() from the object's sentinel.
+class WeakContainer : public base::RefCountedThreadSafe<WeakContainer> {
+ public:
+  WeakContainer(id object) : object_(object) {}
+  id object() { return object_; }
+  void nullify() {
+    DCHECK(checker_.CalledOnValidThread());
+    object_ = nil;
+  }
+
+ private:
+  friend base::RefCountedThreadSafe<WeakContainer>;
+  ~WeakContainer() {}
+  base::ThreadChecker checker_;
+  id object_;
+};
+
+}  // namespace base
+
+// Sentinel for observing the object contained in the weak pointer. The object
+// will be deleted when the weak object is deleted and will notify its
+// container.
+@interface CRBWeakNSProtocolSentinel : NSObject
+// Return the only associated container for this object. There can be only one.
+// Will return null if object is nil .
++ (scoped_refptr<base::WeakContainer>)containerForObject:(id)object;
+@end
+
+namespace base {
+
+// Base class for all WeakNSObject derivatives.
+template <typename NST>
+class WeakNSProtocol : public base::NonThreadSafe {
+ public:
+  explicit WeakNSProtocol(NST object = nil) {
+    container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
+  }
+
+  WeakNSProtocol(const WeakNSProtocol<NST>& that) {
+    container_ = that.container_;
+  }
+
+  ~WeakNSProtocol() {
+    // A WeakNSProtocol object can be allocated on one thread and released on
+    // another. This is not the case for the contained object.
+    DetachFromThread();
+  }
+
+  void reset(NST object = nil) {
+    DCHECK(CalledOnValidThread());
+    container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
+  }
+
+  NST get() const {
+    DCHECK(CalledOnValidThread());
+    if (!container_.get())
+      return nil;
+    return container_->object();
+  }
+
+  WeakNSProtocol& operator=(const WeakNSProtocol<NST>& that) {
+    DCHECK(CalledOnValidThread());
+    container_ = that.container_;
+    return *this;
+  }
+
+  bool operator==(NST that) const {
+    DCHECK(CalledOnValidThread());
+    return get() == that;
+  }
+
+  bool operator!=(NST that) const { return get() != that; }
+
+  operator NST() const { return get(); }
+
+ private:
+  // Refecounted reference to the container tracking the ObjectiveC object this
+  // class encapsulates.
+  scoped_refptr<base::WeakContainer> container_;
+};
+
+// Free functions
+template <class NST>
+bool operator==(NST p1, const WeakNSProtocol<NST>& p2) {
+  return p1 == p2.get();
+}
+
+template <class NST>
+bool operator!=(NST p1, const WeakNSProtocol<NST>& p2) {
+  return p1 != p2.get();
+}
+
+template <typename NST>
+class WeakNSObject : public WeakNSProtocol<NST*> {
+ public:
+  explicit WeakNSObject(NST* object = nil) : WeakNSProtocol<NST*>(object) {}
+
+  WeakNSObject(const WeakNSObject<NST>& that) : WeakNSProtocol<NST*>(that) {}
+
+  WeakNSObject& operator=(const WeakNSObject<NST>& that) {
+    WeakNSProtocol<NST*>::operator=(that);
+    return *this;
+  }
+};
+
+// Specialization to make WeakNSObject<id> work.
+template <>
+class WeakNSObject<id> : public WeakNSProtocol<id> {
+ public:
+  explicit WeakNSObject(id object = nil) : WeakNSProtocol<id>(object) {}
+
+  WeakNSObject(const WeakNSObject<id>& that) : WeakNSProtocol<id>(that) {}
+
+  WeakNSObject& operator=(const WeakNSObject<id>& that) {
+    WeakNSProtocol<id>::operator=(that);
+    return *this;
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_IOS_WEAK_NSOBJECT_H_
diff --git a/base/ios/weak_nsobject.mm b/base/ios/weak_nsobject.mm
new file mode 100644
index 0000000..36f9d3e
--- /dev/null
+++ b/base/ios/weak_nsobject.mm
@@ -0,0 +1,61 @@
+// 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 "base/ios/weak_nsobject.h"
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+
+namespace {
+// The key needed by objc_setAssociatedObject.
+char sentinelObserverKey_;
+}
+
+@interface CRBWeakNSProtocolSentinel ()
+// Container to notify on dealloc.
+@property(readonly, assign) scoped_refptr<base::WeakContainer> container;
+// Designed initializer.
+- (id)initWithContainer:(scoped_refptr<base::WeakContainer>)container;
+@end
+
+@implementation CRBWeakNSProtocolSentinel
+
+@synthesize container = container_;
+
++ (scoped_refptr<base::WeakContainer>)containerForObject:(id)object {
+  if (object == nil)
+    return nullptr;
+  // The autoreleasePool is needed here as the call to objc_getAssociatedObject
+  // returns an autoreleased object which is better released sooner than later.
+  base::mac::ScopedNSAutoreleasePool pool;
+  CRBWeakNSProtocolSentinel* sentinel =
+      objc_getAssociatedObject(object, &sentinelObserverKey_);
+  if (!sentinel) {
+    base::scoped_nsobject<CRBWeakNSProtocolSentinel> newSentinel(
+        [[CRBWeakNSProtocolSentinel alloc]
+            initWithContainer:new base::WeakContainer(object)]);
+    sentinel = newSentinel;
+    objc_setAssociatedObject(object, &sentinelObserverKey_, sentinel,
+                             OBJC_ASSOCIATION_RETAIN);
+    // The retain count is 2. One retain is due to the alloc, the other to the
+    // association with the weak object.
+    DCHECK_EQ(2u, [sentinel retainCount]);
+  }
+  return [sentinel container];
+}
+
+- (id)initWithContainer:(scoped_refptr<base::WeakContainer>)container {
+  DCHECK(container.get());
+  self = [super init];
+  if (self)
+    container_ = container;
+  return self;
+}
+
+- (void)dealloc {
+  self.container->nullify();
+  [super dealloc];
+}
+
+@end
diff --git a/base/ios/weak_nsobject_unittest.mm b/base/ios/weak_nsobject_unittest.mm
new file mode 100644
index 0000000..9758aed
--- /dev/null
+++ b/base/ios/weak_nsobject_unittest.mm
@@ -0,0 +1,97 @@
+// 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 "base/basictypes.h"
+#include "base/ios/weak_nsobject.h"
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::WeakNSObject;
+
+namespace {
+
+TEST(WeakNSObjectTest, WeakNSObject) {
+  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  EXPECT_TRUE(w1);
+  p1.reset();
+  EXPECT_FALSE(w1);
+}
+
+TEST(WeakNSObjectTest, MultipleWeakNSObject) {
+  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  WeakNSObject<NSObject> w2(w1);
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE(w2);
+  EXPECT_TRUE(w1.get() == w2.get());
+  p1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_FALSE(w2);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectDies) {
+  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  {
+    WeakNSObject<NSObject> w1(p1);
+    EXPECT_TRUE(w1);
+  }
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectReset) {
+  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  EXPECT_TRUE(w1);
+  w1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_TRUE(p1);
+  EXPECT_TRUE([p1 description]);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectResetWithObject) {
+  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  base::scoped_nsobject<NSObject> p2([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  EXPECT_TRUE(w1);
+  w1.reset(p2);
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE([p1 description]);
+  EXPECT_TRUE([p2 description]);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectEmpty) {
+  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1;
+  EXPECT_FALSE(w1);
+  w1.reset(p1);
+  EXPECT_TRUE(w1);
+  p1.reset();
+  EXPECT_FALSE(w1);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectCopy) {
+  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  WeakNSObject<NSObject> w2(w1);
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE(w2);
+  p1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_FALSE(w2);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectAssignment) {
+  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  WeakNSObject<NSObject> w2;
+  EXPECT_FALSE(w2);
+  w2 = w1;
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE(w2);
+  p1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_FALSE(w2);
+}
+
+}  // namespace
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
index fa6df4d..f606dab 100644
--- a/base/mac/sdk_forward_declarations.h
+++ b/base/mac/sdk_forward_declarations.h
@@ -334,6 +334,10 @@
 @property (copy) NSDictionary* userInfo;
 @property (copy) NSURL* webpageURL;
 
+- (instancetype)initWithActivityType:(NSString*)activityType;
+- (void)becomeCurrent;
+- (void)invalidate;
+
 @end
 
 BASE_EXPORT extern "C" NSString* const NSUserActivityTypeBrowsingWeb;
diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc
index 6533048..851f1ad 100644
--- a/base/memory/discardable_shared_memory.cc
+++ b/base/memory/discardable_shared_memory.cc
@@ -224,6 +224,7 @@
 }
 
 void DiscardableSharedMemory::Close() {
+  shared_memory_.Unmap();
   shared_memory_.Close();
 }
 
diff --git a/base/memory/shared_memory.h b/base/memory/shared_memory.h
index 7254950..d76e01c 100644
--- a/base/memory/shared_memory.h
+++ b/base/memory/shared_memory.h
@@ -200,7 +200,8 @@
   SharedMemoryId id() const { return inode_; }
 #endif
 
-  // Closes the open shared memory segment.
+  // Closes the open shared memory segment. The memory will remain mapped if
+  // it was previously mapped.
   // It is safe to call Close repeatedly.
   void Close();
 
diff --git a/base/memory/shared_memory_nacl.cc b/base/memory/shared_memory_nacl.cc
index 39625ee..8435b2b 100644
--- a/base/memory/shared_memory_nacl.cc
+++ b/base/memory/shared_memory_nacl.cc
@@ -46,6 +46,7 @@
 }
 
 SharedMemory::~SharedMemory() {
+  Unmap();
   Close();
 }
 
@@ -125,7 +126,6 @@
 }
 
 void SharedMemory::Close() {
-  Unmap();
   if (mapped_file_ > 0) {
     if (close(mapped_file_) < 0)
       DPLOG(ERROR) << "close";
@@ -159,8 +159,10 @@
   new_handle->fd = new_fd;
   new_handle->auto_close = true;
 
-  if (close_self)
+  if (close_self) {
+    Unmap();
     Close();
+  }
   return true;
 }
 
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
index 0358e63..fd26ad1 100644
--- a/base/memory/shared_memory_posix.cc
+++ b/base/memory/shared_memory_posix.cc
@@ -80,6 +80,7 @@
 }
 
 SharedMemory::~SharedMemory() {
+  Unmap();
   Close();
 }
 
@@ -331,8 +332,6 @@
 }
 
 void SharedMemory::Close() {
-  Unmap();
-
   if (mapped_file_ > 0) {
     if (close(mapped_file_) < 0)
       PLOG(ERROR) << "close";
@@ -468,8 +467,10 @@
   new_handle->fd = new_fd;
   new_handle->auto_close = true;
 
-  if (close_self)
+  if (close_self) {
+    Unmap();
     Close();
+  }
 
   return true;
 }
diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc
index 0b3fd7b..265179a 100644
--- a/base/memory/shared_memory_unittest.cc
+++ b/base/memory/shared_memory_unittest.cc
@@ -260,6 +260,29 @@
 }
 #endif
 
+// Check that memory is still mapped after its closed.
+TEST(SharedMemoryTest, CloseNoUnmap) {
+  const size_t kDataSize = 4096;
+
+  SharedMemory memory;
+  ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
+  char* ptr = static_cast<char*>(memory.memory());
+  ASSERT_NE(ptr, static_cast<void*>(NULL));
+  memset(ptr, 'G', kDataSize);
+
+  memory.Close();
+
+  EXPECT_EQ(ptr, memory.memory());
+  EXPECT_EQ(SharedMemory::NULLHandle(), memory.handle());
+
+  for (size_t i = 0; i < kDataSize; i++) {
+    EXPECT_EQ('G', ptr[i]);
+  }
+
+  memory.Unmap();
+  EXPECT_EQ(nullptr, memory.memory());
+}
+
 // Create a set of N threads to each open a shared memory segment and write to
 // it. Verify that they are always reading/writing consistent data.
 TEST(SharedMemoryTest, MultipleThreads) {
diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc
index 5d2fa2a..20659ab 100644
--- a/base/memory/shared_memory_win.cc
+++ b/base/memory/shared_memory_win.cc
@@ -71,6 +71,7 @@
 }
 
 SharedMemory::~SharedMemory() {
+  Unmap();
   Close();
   if (lock_ != NULL)
     CloseHandle(lock_);
@@ -249,11 +250,6 @@
 
 
 void SharedMemory::Close() {
-  if (memory_ != NULL) {
-    UnmapViewOfFile(memory_);
-    memory_ = NULL;
-  }
-
   if (mapped_file_ != NULL) {
     CloseHandle(mapped_file_);
     mapped_file_ = NULL;
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
index 2ca32d6..9e5b013 100644
--- a/base/message_loop/incoming_task_queue.cc
+++ b/base/message_loop/incoming_task_queue.cc
@@ -6,16 +6,36 @@
 
 #include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/time/time.h"
 
 namespace base {
 namespace internal {
 
+namespace {
+
+// Returns true if MessagePump::ScheduleWork() must be called one
+// time for every task that is added to the MessageLoop incoming queue.
+bool AlwaysNotifyPump(MessageLoop::Type type) {
+#if defined(OS_ANDROID)
+  // The Android UI message loop needs to get notified each time a task is
+  // added
+  // to the incoming queue.
+  return type == MessageLoop::TYPE_UI || type == MessageLoop::TYPE_JAVA;
+#else
+  return false;
+#endif
+}
+
+}  // namespace
+
 IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)
     : high_res_task_count_(0),
       message_loop_(message_loop),
-      next_sequence_num_(0) {
+      next_sequence_num_(0),
+      message_loop_scheduled_(false),
+      always_schedule_work_(AlwaysNotifyPump(message_loop_->type())) {
 }
 
 bool IncomingTaskQueue::AddToIncomingQueue(
@@ -56,9 +76,14 @@
 
   // Acquire all we can from the inter-thread queue with one lock acquisition.
   AutoLock lock(incoming_queue_lock_);
-  if (!incoming_queue_.empty())
+  if (incoming_queue_.empty()) {
+    // If the loop attempts to reload but there are no tasks in the incoming
+    // queue, that means it will go to sleep waiting for more work. If the
+    // incoming queue becomes nonempty we need to schedule it again.
+    message_loop_scheduled_ = false;
+  } else {
     incoming_queue_.Swap(work_queue);
-
+  }
   // Reset the count of high resolution tasks since our queue is now empty.
   int high_res_tasks = high_res_task_count_;
   high_res_task_count_ = 0;
@@ -109,8 +134,16 @@
   incoming_queue_.push(*pending_task);
   pending_task->task.Reset();
 
-  // Wake up the pump.
-  message_loop_->ScheduleWork(was_empty);
+  if (always_schedule_work_ || (!message_loop_scheduled_ && was_empty)) {
+    // Wake up the message loop.
+    message_loop_->ScheduleWork();
+    // After we've scheduled the message loop, we do not need to do so again
+    // until we know it has processed all of the work in our queue and is
+    // waiting for more work again. The message loop will always attempt to
+    // reload from the incoming queue before waiting again so we clear this flag
+    // in ReloadWorkQueue().
+    message_loop_scheduled_ = true;
+  }
 
   return true;
 }
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
index 30f2603..72e1f30 100644
--- a/base/message_loop/incoming_task_queue.h
+++ b/base/message_loop/incoming_task_queue.h
@@ -84,6 +84,14 @@
   // The next sequence number to use for delayed tasks.
   int next_sequence_num_;
 
+  // True if our message loop has already been scheduled and does not need to be
+  // scheduled again until an empty reload occurs.
+  bool message_loop_scheduled_;
+
+  // True if we always need to call ScheduleWork when receiving a new task, even
+  // if the incoming queue was not empty.
+  const bool always_schedule_work_;
+
   DISALLOW_COPY_AND_ASSIGN(IncomingTaskQueue);
 };
 
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 2f4a03c..8180733 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -86,18 +86,6 @@
 
 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL;
 
-// Returns true if MessagePump::ScheduleWork() must be called one
-// time for every task that is added to the MessageLoop incoming queue.
-bool AlwaysNotifyPump(MessageLoop::Type type) {
-#if defined(OS_ANDROID)
-  // The Android UI message loop needs to get notified each time a task is added
-  // to the incoming queue.
-  return type == MessageLoop::TYPE_UI || type == MessageLoop::TYPE_JAVA;
-#else
-  return false;
-#endif
-}
-
 #if defined(OS_IOS)
 typedef MessagePumpIOSForIO MessagePumpForIO;
 #elif defined(OS_NACL_SFI)
@@ -512,9 +500,8 @@
   }
 }
 
-void MessageLoop::ScheduleWork(bool was_empty) {
-  if (was_empty || AlwaysNotifyPump(type_))
-    pump_->ScheduleWork();
+void MessageLoop::ScheduleWork() {
+  pump_->ScheduleWork();
 }
 
 //------------------------------------------------------------------------------
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 47df69a..32e826d 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -391,7 +391,7 @@
 
   // Wakes up the message pump. Can be called on any thread. The caller is
   // responsible for synchronizing ScheduleWork() calls.
-  void ScheduleWork(bool was_empty);
+  void ScheduleWork();
 
   // Returns the TaskAnnotator which is used to add debug information to posted
   // tasks.
diff --git a/base/message_loop/message_pump_perftest.cc b/base/message_loop/message_pump_perftest.cc
index 9fca465..39ed5a8 100644
--- a/base/message_loop/message_pump_perftest.cc
+++ b/base/message_loop/message_pump_perftest.cc
@@ -39,7 +39,7 @@
     uint64_t schedule_calls = 0u;
     do {
       for (size_t i = 0; i < kBatchSize; ++i) {
-        target_message_loop()->ScheduleWork(true);
+        target_message_loop()->ScheduleWork();
         schedule_calls++;
       }
       now = base::TimeTicks::HighResNow();
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
index ad89b7f..3f94c80 100644
--- a/base/message_loop/message_pump_win.cc
+++ b/base/message_loop/message_pump_win.cc
@@ -10,6 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/process/memory.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/strings/stringprintf.h"
 #include "base/win/wrapped_window_proc.h"
 
@@ -319,6 +320,11 @@
 }
 
 bool MessagePumpForUI::ProcessNextWindowsMessage() {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 <<MessagePumpForUI::ProcessNextWindowsMessage>>"));
+
   // If there are sent messages in the queue then PeekMessage internally
   // dispatches the message and returns false. We return true in this
   // case to ensure that the message loop peeks again instead of calling
diff --git a/base/port.h b/base/port.h
index 0a04d55..56c4d4e 100644
--- a/base/port.h
+++ b/base/port.h
@@ -26,18 +26,6 @@
 #define GG_INT64_C(x)   GG_LONGLONG(x)
 #define GG_UINT64_C(x)  GG_ULONGLONG(x)
 
-// It's possible for functions that use a va_list, such as StringPrintf, to
-// invalidate the data in it upon use.  The fix is to make a copy of the
-// structure before using it and use that copy instead.  va_copy is provided
-// for this purpose.  MSVC does not provide va_copy, so define an
-// implementation here.  It is not guaranteed that assignment is a copy, so the
-// StringUtil.VariableArgsFunc unit test tests this capability.
-#if defined(COMPILER_GCC)
-#define GG_VA_COPY(a, b) (va_copy(a, b))
-#elif defined(COMPILER_MSVC)
-#define GG_VA_COPY(a, b) (a = b)
-#endif
-
 // Define an OS-neutral wrapper for shared library entry points
 #if defined(OS_WIN)
 #define API_CALL __stdcall
diff --git a/base/process/process.h b/base/process/process.h
index 50ccf8d..ad8f8ee 100644
--- a/base/process/process.h
+++ b/base/process/process.h
@@ -9,6 +9,7 @@
 #include "base/basictypes.h"
 #include "base/move.h"
 #include "base/process/process_handle.h"
+#include "base/time/time.h"
 #include "build/build_config.h"
 
 #if defined(OS_WIN)
@@ -81,6 +82,13 @@
   // NOTE: On POSIX |result_code| is ignored.
   void Terminate(int result_code);
 
+  // Waits for the process to exit. Returns true on success.
+  // On POSIX, if the process has been signaled then |exit_code| is set to -1.
+  bool WaitForExit(int* exit_code);
+
+  // Same as WaitForExit() but only waits for up to |timeout|.
+  bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code);
+
   // A process is backgrounded when it's priority is lower than normal.
   // Return true if this process is backgrounded, false otherwise.
   bool IsProcessBackgrounded() const;
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc
index 270438e..58852bc 100644
--- a/base/process/process_posix.cc
+++ b/base/process/process_posix.cc
@@ -89,6 +89,18 @@
   KillProcess(process_, result_code, false);
 }
 
+bool Process::WaitForExit(int* exit_code) {
+  // TODO(rvargas) crbug.com/417532: Remove this constant.
+  const int kNoTimeout = -1;
+  return WaitForExitWithTimeout(TimeDelta::FromMilliseconds(kNoTimeout),
+                                exit_code);
+}
+
+bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
+  // TODO(rvargas) crbug.com/417532: Move the implementation here.
+  return base::WaitForExitCodeWithTimeout(Handle(), exit_code, timeout);
+}
+
 #if !defined(OS_LINUX)
 bool Process::IsProcessBackgrounded() const {
   // See SetProcessBackgrounded().
diff --git a/base/process/process_unittest.cc b/base/process/process_unittest.cc
index a5ba834..5180f64 100644
--- a/base/process/process_unittest.cc
+++ b/base/process/process_unittest.cc
@@ -135,6 +135,34 @@
 #endif
 }
 
+MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess) {
+  PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 10);
+  return 0;
+}
+
+TEST_F(ProcessTest, WaitForExit) {
+  Process process(SpawnChild("FastSleepyChildProcess"));
+  ASSERT_TRUE(process.IsValid());
+
+  const int kDummyExitCode = 42;
+  int exit_code = kDummyExitCode;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_EQ(0, exit_code);
+}
+
+TEST_F(ProcessTest, WaitForExitWithTimeout) {
+  Process process(SpawnChild("SleepyChildProcess"));
+  ASSERT_TRUE(process.IsValid());
+
+  const int kDummyExitCode = 42;
+  int exit_code = kDummyExitCode;
+  TimeDelta timeout = TestTimeouts::tiny_timeout();
+  EXPECT_FALSE(process.WaitForExitWithTimeout(timeout, &exit_code));
+  EXPECT_EQ(kDummyExitCode, exit_code);
+
+  process.Terminate(kDummyExitCode);
+}
+
 // Ensure that the priority of a process is restored correctly after
 // backgrounding and restoring.
 // Note: a platform may not be willing or able to lower the priority of
diff --git a/base/process/process_win.cc b/base/process/process_win.cc
index 3e0d79f..96556a9 100644
--- a/base/process/process_win.cc
+++ b/base/process/process_win.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/process/kill.h"
 #include "base/win/windows_version.h"
 
 namespace base {
@@ -110,6 +111,18 @@
   terminate_process(Handle(), result_code);
 }
 
+bool Process::WaitForExit(int* exit_code) {
+  return WaitForExitWithTimeout(TimeDelta::FromMilliseconds(INFINITE),
+                                exit_code);
+}
+
+bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
+  // TODO(rvargas) crbug.com/417532: Move the implementation here.
+  if (timeout > TimeDelta::FromMilliseconds(INFINITE))
+    timeout = TimeDelta::FromMilliseconds(INFINITE);
+  return base::WaitForExitCodeWithTimeout(Handle(), exit_code, timeout);
+}
+
 bool Process::IsProcessBackgrounded() const {
   DCHECK(IsValid());
   DWORD priority = GetPriority();
diff --git a/base/profiler/tracked_time.cc b/base/profiler/tracked_time.cc
index 7791c3a..0121038 100644
--- a/base/profiler/tracked_time.cc
+++ b/base/profiler/tracked_time.cc
@@ -46,7 +46,7 @@
 TrackedTime::TrackedTime() : ms_(0) {}
 TrackedTime::TrackedTime(int32 ms) : ms_(ms) {}
 TrackedTime::TrackedTime(const base::TimeTicks& time)
-    : ms_((time - base::TimeTicks()).InMilliseconds()) {
+    : ms_(static_cast<int32>((time - base::TimeTicks()).InMilliseconds())) {
 }
 
 // static
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
index 923116d..d887c0b 100644
--- a/base/strings/string_util_unittest.cc
+++ b/base/strings/string_util_unittest.cc
@@ -669,39 +669,6 @@
   EXPECT_EQ(15, HexDigitToInt('f'));
 }
 
-// This checks where we can use the assignment operator for a va_list. We need
-// a way to do this since Visual C doesn't support va_copy, but assignment on
-// va_list is not guaranteed to be a copy. See StringAppendVT which uses this
-// capability.
-static void VariableArgsFunc(const char* format, ...) {
-  va_list org;
-  va_start(org, format);
-
-  va_list dup;
-  GG_VA_COPY(dup, org);
-  int i1 = va_arg(org, int);
-  int j1 = va_arg(org, int);
-  char* s1 = va_arg(org, char*);
-  double d1 = va_arg(org, double);
-  va_end(org);
-
-  int i2 = va_arg(dup, int);
-  int j2 = va_arg(dup, int);
-  char* s2 = va_arg(dup, char*);
-  double d2 = va_arg(dup, double);
-
-  EXPECT_EQ(i1, i2);
-  EXPECT_EQ(j1, j2);
-  EXPECT_STREQ(s1, s2);
-  EXPECT_EQ(d1, d2);
-
-  va_end(dup);
-}
-
-TEST(StringUtilTest, VAList) {
-  VariableArgsFunc("%d %d %s %lf", 45, 92, "This is interesting", 9.21);
-}
-
 // Test for Tokenize
 template <typename STR>
 void TokenizeTest() {
diff --git a/base/strings/stringprintf.cc b/base/strings/stringprintf.cc
index 3d024fa..f3a57b3 100644
--- a/base/strings/stringprintf.cc
+++ b/base/strings/stringprintf.cc
@@ -48,7 +48,7 @@
   typename StringType::value_type stack_buf[1024];
 
   va_list ap_copy;
-  GG_VA_COPY(ap_copy, ap);
+  va_copy(ap_copy, ap);
 
 #if !defined(OS_WIN)
   ScopedClearErrno clear_errno;
@@ -94,7 +94,7 @@
 
     // NOTE: You can only use a va_list once.  Since we're in a while loop, we
     // need to make a new copy each time so we don't use up the original.
-    GG_VA_COPY(ap_copy, ap);
+    va_copy(ap_copy, ap);
     result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
     va_end(ap_copy);
 
diff --git a/base/strings/sys_string_conversions_posix.cc b/base/strings/sys_string_conversions_posix.cc
index 1e926bb..3b18456 100644
--- a/base/strings/sys_string_conversions_posix.cc
+++ b/base/strings/sys_string_conversions_posix.cc
@@ -24,11 +24,10 @@
   return out;
 }
 
-#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if defined(SYSTEM_NATIVE_UTF8) || defined(OS_ANDROID)
 // TODO(port): Consider reverting the OS_ANDROID when we have wcrtomb()
 // support and a better understanding of what calls these routines.
 
-// ChromeOS always runs in UTF-8 locale.
 std::string SysWideToNativeMB(const std::wstring& wide) {
   return WideToUTF8(wide);
 }
diff --git a/base/supports_user_data.h b/base/supports_user_data.h
index 6d515d7..711ee7d 100644
--- a/base/supports_user_data.h
+++ b/base/supports_user_data.h
@@ -61,7 +61,7 @@
 template <typename T>
 class UserDataAdapter : public base::SupportsUserData::Data {
  public:
-  static T* Get(SupportsUserData* supports_user_data, const void* key) {
+  static T* Get(const SupportsUserData* supports_user_data, const void* key) {
     UserDataAdapter* data =
       static_cast<UserDataAdapter*>(supports_user_data->GetUserData(key));
     return data ? static_cast<T*>(data->object_.get()) : NULL;
diff --git a/build/all.gyp b/build/all.gyp
index 149ac0a..5f06ae0 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -846,6 +846,7 @@
             '../tools/android/android_tools.gyp:android_tools',
             '../tools/android/android_tools.gyp:memconsumer',
             '../tools/android/findbugs_plugin/findbugs_plugin.gyp:findbugs_plugin_test',
+            '../ui/android/ui_android.gyp:ui_android_unittests',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
             '../ui/events/events.gyp:events_unittests',
             '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
@@ -874,6 +875,7 @@
             '../sql/sql.gyp:sql_unittests_apk',
             '../sync/sync.gyp:sync_unit_tests_apk',
             '../tools/android/heap_profiler/heap_profiler.gyp:heap_profiler_unittests_apk',
+            '../ui/android/ui_android.gyp:ui_android_unittests_apk',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests_apk',
             '../ui/events/events.gyp:events_unittests_apk',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests_apk',
@@ -883,7 +885,6 @@
             ['enable_webrtc==1 and "<(libpeer_target_type)"=="static_library"', {
               'dependencies': [
                 '../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
-                '../components/devtools_bridge.gyp:libdevtools_bridge_browsertests',
               ],
             }],
           ],
@@ -899,7 +900,6 @@
             '../tools/android/android_tools.gyp:memconsumer',
             # Unit test bundles packaged as an apk.
             '../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
-            '../components/devtools_bridge.gyp:libdevtools_bridge_browsertests',
             '../content/content_shell_and_tests.gyp:content_browsertests_apk',
           ],
         },  # target_name: android_builder_chromium_webrtc
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py
index a72a0c7..08bccc9 100755
--- a/build/android/buildbot/bb_device_status_check.py
+++ b/build/android/buildbot/bb_device_status_check.py
@@ -46,10 +46,10 @@
   """
 
   device_adb = device_utils.DeviceUtils(serial)
-  device_type = device_adb.GetProp('ro.build.product')
-  device_build = device_adb.GetProp('ro.build.id')
-  device_build_type = device_adb.GetProp('ro.build.type')
-  device_product_name = device_adb.GetProp('ro.product.name')
+  device_type = device_adb.build_product
+  device_build = device_adb.build_id
+  device_build_type = device_adb.build_type
+  device_product_name = device_adb.product_name
 
   try:
     battery_info = device_adb.old_interface.GetBatteryInfo()
@@ -71,7 +71,7 @@
                         lambda x: x[-6:])
   report = ['Device %s (%s)' % (serial, device_type),
             '  Build: %s (%s)' %
-              (device_build, device_adb.GetProp('ro.build.fingerprint')),
+              (device_build, device_adb.build_fingerprint),
             '  Current Battery Service state: ',
             '\n'.join(['    %s: %s' % (k, v)
                        for k, v in battery_info.iteritems()]),
diff --git a/build/android/findbugs_filter/findbugs_known_bugs.txt b/build/android/findbugs_filter/findbugs_known_bugs.txt
index 6ad2b3a..cbc5e30 100644
--- a/build/android/findbugs_filter/findbugs_known_bugs.txt
+++ b/build/android/findbugs_filter/findbugs_known_bugs.txt
@@ -23,3 +23,10 @@
 M V EI2: org.chromium.content_public.browser.LoadUrlParams.setPostData(byte[]) may expose internal representation by storing an externally mutable object into LoadUrlParams.mPostData  At LoadUrlParams.java
 M V EI: org.chromium.content_public.browser.LoadUrlParams.getPostData() may expose internal representation by returning LoadUrlParams.mPostData  At LoadUrlParams.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
+M D UrF: Unread public/protected field: org.chromium.chrome.browser.tabmodel.document.DocumentTabModel$Entry.initialUrl  At DocumentTabModel.java
+M D UrF: Unread public/protected field: org.chromium.chrome.browser.tabmodel.document.DocumentTabModel$Entry.isTabStateReady  At DocumentTabModel.java
+M D UrF: Unread public/protected field: org.chromium.chrome.browser.tabmodel.document.DocumentTabModel$Entry.tabState  At DocumentTabModel.java
+M D UuF: Unused public or protected field: org.chromium.chrome.browser.tabmodel.document.DocumentTabModel$Entry.canGoBack  In DocumentTabModel.java
+M D UuF: Unused public or protected field: org.chromium.chrome.browser.tabmodel.document.DocumentTabModel$Entry.currentUrl  In DocumentTabModel.java
+M D UuF: Unused public or protected field: org.chromium.chrome.browser.tabmodel.document.DocumentTabModel$Entry.isDirty  In DocumentTabModel.java
+M D UuF: Unused public or protected field: org.chromium.chrome.browser.tabmodel.document.DocumentTabModel$Entry.placeholderTab  In DocumentTabModel.java
diff --git a/build/android/pylib/base/environment_factory.py b/build/android/pylib/base/environment_factory.py
index c96d199..3ad39fc 100644
--- a/build/android/pylib/base/environment_factory.py
+++ b/build/android/pylib/base/environment_factory.py
@@ -2,10 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from pylib.remote.device import remote_device_environment
 
-def CreateEnvironment(_args, error_func):
+def CreateEnvironment(args, error_func):
 
   # TODO(jbudorick) Add local device environment.
   # TODO(jbudorick) Add local machine environment.
-  error_func('No environments currently supported.')
 
+  if args.environment == 'remote_device':
+    return remote_device_environment.RemoteDeviceEnvironment(args,
+                                                             error_func)
+  error_func('Unable to create %s environment.' % args.environment)
diff --git a/build/android/pylib/base/test_instance_factory.py b/build/android/pylib/base/test_instance_factory.py
index 5204b2e..af989ef 100644
--- a/build/android/pylib/base/test_instance_factory.py
+++ b/build/android/pylib/base/test_instance_factory.py
@@ -5,6 +5,8 @@
 from pylib import constants
 from pylib.gtest import gtest_test_instance
 from pylib.utils import isolator
+from pylib.uirobot import uirobot_test_instance
+
 
 
 def CreateTestInstance(args, error_func):
@@ -12,7 +14,8 @@
   if args.command == 'gtest':
     return gtest_test_instance.GtestTestInstance(
         args, isolator.Isolator(constants.ISOLATE_DEPS_DIR))
+  if args.command == 'uirobot':
+    return uirobot_test_instance.UirobotTestInstance(args)
   # TODO(jbudorick) Add instrumentation test instance.
 
   error_func('Unable to create %s test instance.' % args.command)
-
diff --git a/build/android/pylib/base/test_run.py b/build/android/pylib/base/test_run.py
index 2c594fd..7380e78 100644
--- a/build/android/pylib/base/test_run.py
+++ b/build/android/pylib/base/test_run.py
@@ -24,7 +24,7 @@
   def SetUp(self):
     raise NotImplementedError
 
-  def RunTest(self):
+  def RunTests(self):
     raise NotImplementedError
 
   def TearDown(self):
diff --git a/build/android/pylib/base/test_run_factory.py b/build/android/pylib/base/test_run_factory.py
index 6ccfb37..550b4cf 100644
--- a/build/android/pylib/base/test_run_factory.py
+++ b/build/android/pylib/base/test_run_factory.py
@@ -2,9 +2,17 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-def CreateTestRun(_args, _env, _test_instance, error_func):
+from pylib.remote.device import remote_device_gtest_run
+from pylib.remote.device import remote_device_uirobot_run
 
+def CreateTestRun(args, env, test_instance, error_func):
+  if args.environment == 'remote_device':
+      if test_instance.TestType() == 'gtest':
+        return remote_device_gtest_run.RemoteDeviceGtestRun(env, test_instance)
+      if test_instance.TestType() == 'uirobot':
+        return remote_device_uirobot_run.RemoteDeviceUirobotRun(
+            env, test_instance)
   # TODO(jbudorick) Add local gtest test runs
   # TODO(jbudorick) Add local instrumentation test runs.
-  error_func('No test runs are currently supported.')
-
+  error_func('Unable to create %s test run in %s environment' % (
+      test_instance.TestType(), args.environment))
diff --git a/build/android/pylib/cmd_helper.py b/build/android/pylib/cmd_helper.py
index e3abab7..f881553 100644
--- a/build/android/pylib/cmd_helper.py
+++ b/build/android/pylib/cmd_helper.py
@@ -115,14 +115,20 @@
   return output
 
 
-def _LogCommand(args, cwd=None):
-  if not isinstance(args, basestring):
+def _ValidateAndLogCommand(args, cwd, shell):
+  if isinstance(args, basestring):
+    if not shell:
+      raise Exception('string args must be run with shell=True')
+  else:
+    if shell:
+      raise Exception('array args must be run with shell=False')
     args = ' '.join(SingleQuote(c) for c in args)
   if cwd is None:
     cwd = ''
   else:
     cwd = ':' + cwd
   logging.info('[host]%s> %s', cwd, args)
+  return args
 
 
 def GetCmdStatusAndOutput(args, cwd=None, shell=False):
@@ -133,18 +139,13 @@
       the string or the first item in the args sequence.
     cwd: If not None, the subprocess's current directory will be changed to
       |cwd| before it's executed.
-    shell: Whether to execute args as a shell command.
+    shell: Whether to execute args as a shell command. Must be True if args
+      is a string and False if args is a sequence.
 
   Returns:
     The 2-tuple (exit code, output).
   """
-  if isinstance(args, basestring):
-    if not shell:
-      raise Exception('string args must be run with shell=True')
-  elif shell:
-    raise Exception('array args must be run with shell=False')
-
-  _LogCommand(args, cwd)
+  _ValidateAndLogCommand(args, cwd, shell)
   pipe = Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                shell=shell, cwd=cwd)
   stdout, stderr = pipe.communicate()
@@ -162,44 +163,16 @@
   pass
 
 
-def GetCmdStatusAndOutputWithTimeout(args, timeout, cwd=None, shell=False,
-                                     logfile=None):
-  """Executes a subprocess with a timeout.
-
-  Args:
-    args: List of arguments to the program, the program to execute is the first
-      element.
-    timeout: the timeout in seconds or None to wait forever.
-    cwd: If not None, the subprocess's current directory will be changed to
-      |cwd| before it's executed.
-    shell: Whether to execute args as a shell command.
-    logfile: Optional file-like object that will receive output from the
-      command as it is running.
-
-  Returns:
-    The 2-tuple (exit code, output).
-  """
+def _IterProcessStdout(process, timeout=None, buffer_size=4096,
+                       poll_interval=1):
   assert fcntl, 'fcntl module is required'
-  if isinstance(args, basestring):
-    if not shell:
-      raise Exception('string args must be run with shell=True')
-  elif shell:
-    raise Exception('array args must be run with shell=False')
-
-  _LogCommand(args, cwd)
-  process = Popen(args, cwd=cwd, shell=shell, stdout=subprocess.PIPE,
-                  stderr=subprocess.STDOUT)
   try:
-    end_time = (time.time() + timeout) if timeout else None
-    poll_interval = 1
-    buffer_size = 4096
-    child_fd = process.stdout.fileno()
-    output = StringIO.StringIO()
-
     # Enable non-blocking reads from the child's stdout.
+    child_fd = process.stdout.fileno()
     fl = fcntl.fcntl(child_fd, fcntl.F_GETFL)
     fcntl.fcntl(child_fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
 
+    end_time = (time.time() + timeout) if timeout else None
     while True:
       if end_time and time.time() > end_time:
         raise TimeoutError
@@ -208,9 +181,7 @@
         data = os.read(child_fd, buffer_size)
         if not data:
           break
-        if logfile:
-          logfile.write(data)
-        output.write(data)
+        yield data
       if process.poll() is not None:
         break
   finally:
@@ -221,4 +192,70 @@
     except OSError:
       pass
     process.wait()
+
+
+def GetCmdStatusAndOutputWithTimeout(args, timeout, cwd=None, shell=False,
+                                     logfile=None):
+  """Executes a subprocess with a timeout.
+
+  Args:
+    args: List of arguments to the program, the program to execute is the first
+      element.
+    timeout: the timeout in seconds or None to wait forever.
+    cwd: If not None, the subprocess's current directory will be changed to
+      |cwd| before it's executed.
+    shell: Whether to execute args as a shell command. Must be True if args
+      is a string and False if args is a sequence.
+    logfile: Optional file-like object that will receive output from the
+      command as it is running.
+
+  Returns:
+    The 2-tuple (exit code, output).
+  """
+  _ValidateAndLogCommand(args, cwd, shell)
+  output = StringIO.StringIO()
+  process = Popen(args, cwd=cwd, shell=shell, stdout=subprocess.PIPE,
+                  stderr=subprocess.STDOUT)
+  for data in _IterProcessStdout(process, timeout=timeout):
+    if logfile:
+      logfile.write(data)
+    output.write(data)
   return process.returncode, output.getvalue()
+
+
+def IterCmdOutputLines(args, timeout=None, cwd=None, shell=False,
+                       check_status=True):
+  """Executes a subprocess and continuously yields lines from its output.
+
+  Args:
+    args: List of arguments to the program, the program to execute is the first
+      element.
+    cwd: If not None, the subprocess's current directory will be changed to
+      |cwd| before it's executed.
+    shell: Whether to execute args as a shell command. Must be True if args
+      is a string and False if args is a sequence.
+    check_status: A boolean indicating whether to check the exit status of the
+      process after all output has been read.
+
+  Yields:
+    The output of the subprocess, line by line.
+
+  Raises:
+    CalledProcessError if check_status is True and the process exited with a
+      non-zero exit status.
+  """
+  cmd = _ValidateAndLogCommand(args, cwd, shell)
+  process = Popen(args, cwd=cwd, shell=shell, stdout=subprocess.PIPE,
+                  stderr=subprocess.STDOUT)
+  buffer_output = ''
+  for data in _IterProcessStdout(process, timeout=timeout):
+    buffer_output += data
+    has_incomplete_line = buffer_output[-1] not in '\r\n'
+    lines = buffer_output.splitlines()
+    buffer_output = lines.pop() if has_incomplete_line else ''
+    for line in lines:
+      yield line
+  if buffer_output:
+    yield buffer_output
+  if check_status and process.returncode:
+    raise subprocess.CalledProcessError(process.returncode, cmd)
diff --git a/build/android/pylib/cmd_helper_test.py b/build/android/pylib/cmd_helper_test.py
index 8b5680d..5155cea 100644
--- a/build/android/pylib/cmd_helper_test.py
+++ b/build/android/pylib/cmd_helper_test.py
@@ -5,11 +5,10 @@
 """Tests for the cmd_helper module."""
 
 import unittest
+import subprocess
 
 from pylib import cmd_helper
 
-# TODO(jbudorick) Make these tests run on the bots.
-
 
 class CmdHelperSingleQuoteTest(unittest.TestCase):
 
@@ -51,3 +50,34 @@
     cmd = 'TEST_VAR=world; echo %s' % cmd_helper.DoubleQuote(test_string)
     self.assertEquals('hello world',
                       cmd_helper.GetCmdOutput(cmd, shell=True).rstrip())
+
+
+class CmdHelperIterCmdOutputLinesTest(unittest.TestCase):
+  """Test IterCmdOutputLines with some calls to the unix 'seq' command."""
+
+  def testIterCmdOutputLines_success(self):
+    for num, line in enumerate(
+        cmd_helper.IterCmdOutputLines(['seq', '10']), 1):
+      self.assertEquals(num, int(line))
+
+  def testIterCmdOutputLines_exitStatusFail(self):
+    with self.assertRaises(subprocess.CalledProcessError):
+      for num, line in enumerate(
+          cmd_helper.IterCmdOutputLines('seq 10 && false', shell=True), 1):
+        self.assertEquals(num, int(line))
+      # after reading all the output we get an exit status of 1
+
+  def testIterCmdOutputLines_exitStatusIgnored(self):
+    for num, line in enumerate(
+        cmd_helper.IterCmdOutputLines('seq 10 && false', shell=True,
+                                      check_status=False), 1):
+      self.assertEquals(num, int(line))
+
+  def testIterCmdOutputLines_exitStatusSkipped(self):
+    for num, line in enumerate(
+        cmd_helper.IterCmdOutputLines('seq 10 && false', shell=True), 1):
+      self.assertEquals(num, int(line))
+      # no exception will be raised because we don't attempt to read past
+      # the end of the output and, thus, the status never gets checked
+      if num == 10:
+        break
diff --git a/build/android/pylib/constants.py b/build/android/pylib/constants.py
index ac57969..50dc075 100644
--- a/build/android/pylib/constants.py
+++ b/build/android/pylib/constants.py
@@ -187,6 +187,7 @@
   'pylib_py_unittests': {
     'path': os.path.join(DIR_SOURCE_ROOT, 'build', 'android'),
     'test_modules': [
+      'pylib.cmd_helper_test',
       'pylib.device.device_utils_test',
       'pylib.results.json_results_test',
       'pylib.utils.md5sum_test',
@@ -201,9 +202,9 @@
 }
 
 LOCAL_MACHINE_TESTS = ['junit', 'python']
-VALID_ENVIRONMENTS = ['local']
+VALID_ENVIRONMENTS = ['local', 'remote_device']
 VALID_TEST_TYPES = ['gtest', 'instrumentation', 'junit', 'linker', 'monkey',
-                    'perf', 'python', 'uiautomator']
+                    'perf', 'python', 'uiautomator', 'uirobot']
 
 
 def GetBuildType():
diff --git a/build/android/pylib/content_settings.py b/build/android/pylib/content_settings.py
index f00553f..f039c96 100644
--- a/build/android/pylib/content_settings.py
+++ b/build/android/pylib/content_settings.py
@@ -14,13 +14,9 @@
 
   def __init__(self, table, device):
     super(ContentSettings, self).__init__()
-    sdk_version_string = device.GetProp('ro.build.version.sdk')
-    try:
-      sdk_version = int(sdk_version_string)
-      assert sdk_version >= constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN, (
-          'ContentSettings supported only on SDK 16 and later')
-    except ValueError:
-      assert False, ('Unknown SDK version %s' % sdk_version_string)
+    assert (device.build_version_sdk
+            >= constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN), (
+        'ContentSettings supported only on SDK 16 and later')
     self._table = table
     self._device = device
 
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index 39fe706..4006a21 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -56,15 +56,22 @@
 
   # pylint: disable=unused-argument
   @classmethod
-  @decorators.WithTimeoutAndRetries
-  def _RunAdbCmd(cls, args, timeout=None, retries=None, device_serial=None,
-                 check_error=True):
+  def _BuildAdbCmd(cls, args, device_serial):
     cmd = [constants.GetAdbPath()]
     if device_serial is not None:
       cmd.extend(['-s', device_serial])
     cmd.extend(args)
+    return cmd
+  # pylint: enable=unused-argument
+
+  # pylint: disable=unused-argument
+  @classmethod
+  @decorators.WithTimeoutAndRetries
+  def _RunAdbCmd(cls, args, timeout=None, retries=None, device_serial=None,
+                 check_error=True):
     status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
-        cmd, timeout_retry.CurrentTimeoutThread().GetRemainingTime())
+        cls._BuildAdbCmd(args, device_serial),
+        timeout_retry.CurrentTimeoutThread().GetRemainingTime())
     if status != 0:
       raise device_errors.AdbCommandFailedError(
           args, output, status, device_serial)
@@ -93,6 +100,19 @@
                            device_serial=self._device_serial,
                            check_error=check_error)
 
+  def _IterRunDeviceAdbCmd(self, args, timeout):
+    """Runs an adb command and returns an iterator over its output lines.
+
+    Args:
+      args: A list of arguments to adb.
+      timeout: Timeout in seconds.
+
+    Yields:
+      The output of the command line by line.
+    """
+    return cmd_helper.IterCmdOutputLines(
+      self._BuildAdbCmd(args, self._device_serial), timeout=timeout)
+
   def __eq__(self, other):
     """Consider instances equal if they refer to the same device.
 
@@ -242,22 +262,20 @@
           cmd, 'path does not specify an accessible directory in the device',
           device_serial=self._device_serial)
 
-  def Logcat(self, filter_spec=None, timeout=_DEFAULT_TIMEOUT,
-             retries=_DEFAULT_RETRIES):
-    """Get the logcat output.
+  def Logcat(self, filter_spec=None, timeout=None):
+    """Get an iterator over the logcat output.
 
     Args:
       filter_spec: (optional) Spec to filter the logcat.
       timeout: (optional) Timeout per try in seconds.
-      retries: (optional) Number of retries to attempt.
 
-    Returns:
-      logcat output as a string.
+    Yields:
+      logcat output line by line.
     """
     cmd = ['logcat']
     if filter_spec is not None:
       cmd.append(filter_spec)
-    return self._RunDeviceAdbCmd(cmd, timeout, retries, check_error=False)
+    return self._IterRunDeviceAdbCmd(cmd, timeout)
 
   def Forward(self, local, remote, timeout=_DEFAULT_TIMEOUT,
               retries=_DEFAULT_RETRIES):
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index 1624ccc..f461b28 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -34,6 +34,11 @@
 _DEFAULT_TIMEOUT = 30
 _DEFAULT_RETRIES = 3
 
+# A sentinel object for default values
+# TODO(jbudorick,perezju): revisit how default values are handled by
+# the timeout_retry decorators.
+DEFAULT = object()
+
 
 @decorators.WithExplicitTimeoutAndRetries(
     _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
@@ -146,7 +151,7 @@
     except device_errors.AdbCommandFailedError:
       return False
 
-  def NeedsSU(self, timeout=None, retries=None):
+  def NeedsSU(self, timeout=DEFAULT, retries=DEFAULT):
     """Checks whether 'su' is needed to access protected resources.
 
     Args:
@@ -165,8 +170,10 @@
     """
     if 'needs_su' not in self._cache:
       try:
-        self.RunShellCommand('su -c ls /root && ! ls /root', check_return=True,
-                             timeout=timeout, retries=retries)
+        self.RunShellCommand(
+            'su -c ls /root && ! ls /root', check_return=True,
+            timeout=self._default_timeout if timeout is DEFAULT else timeout,
+            retries=self._default_retries if retries is DEFAULT else retries)
         self._cache['needs_su'] = True
       except device_errors.AdbCommandFailedError:
         self._cache['needs_su'] = False
@@ -249,8 +256,14 @@
     Returns:
       Path to the apk on the device if it exists, None otherwise.
     """
+    # 'pm path' is liable to incorrectly exit with a nonzero number starting
+    # in Lollipop.
+    # TODO(jbudorick): Check if this is fixed as new Android versions are
+    # released to put an upper bound on this.
+    should_check_return = (self.build_version_sdk <
+                           constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP)
     output = self.RunShellCommand(['pm', 'path', package], single_line=True,
-                                  check_return=True)
+                                  check_return=should_check_return)
     if not output:
       return None
     if not output.startswith('package:'):
@@ -994,12 +1007,77 @@
     """
     return self.old_interface.SetJavaAssertsEnabled(enabled)
 
+
+  @property
+  def build_description(self):
+    """Returns the build description of the system.
+
+    For example:
+      nakasi-user 4.4.4 KTU84P 1227136 release-keys
+    """
+    return self.GetProp('ro.build.description', cache=True)
+
+  @property
+  def build_fingerprint(self):
+    """Returns the build fingerprint of the system.
+
+    For example:
+      google/nakasi/grouper:4.4.4/KTU84P/1227136:user/release-keys
+    """
+    return self.GetProp('ro.build.fingerprint', cache=True)
+
+  @property
+  def build_id(self):
+    """Returns the build ID of the system (e.g. 'KTU84P')."""
+    return self.GetProp('ro.build.id', cache=True)
+
+  @property
+  def build_product(self):
+    """Returns the build product of the system (e.g. 'grouper')."""
+    return self.GetProp('ro.build.product', cache=True)
+
   @property
   def build_type(self):
-    """Returns the build type of the system (e.g. userdebug)."""
+    """Returns the build type of the system (e.g. 'user')."""
     return self.GetProp('ro.build.type', cache=True)
 
-  def GetProp(self, property_name, cache=False, timeout=None, retries=None):
+  @property
+  def build_version_sdk(self):
+    """Returns the build version sdk of the system as a number (e.g. 19).
+
+    For version code numbers see:
+    http://developer.android.com/reference/android/os/Build.VERSION_CODES.html
+
+    For named constants see:
+    pylib.constants.ANDROID_SDK_VERSION_CODES
+
+    Raises:
+      CommandFailedError if the build version sdk is not a number.
+    """
+    value = self.GetProp('ro.build.version.sdk', cache=True)
+    try:
+      return int(value)
+    except ValueError:
+      raise device_errors.CommandFailedError(
+          'Invalid build version sdk: %r' % value)
+
+  @property
+  def product_cpu_abi(self):
+    """Returns the product cpu abi of the device (e.g. 'armeabi-v7a')."""
+    return self.GetProp('ro.product.cpu.abi', cache=True)
+
+  @property
+  def product_model(self):
+    """Returns the name of the product model (e.g. 'Nexus 7')."""
+    return self.GetProp('ro.product.model', cache=True)
+
+  @property
+  def product_name(self):
+    """Returns the product name of the device (e.g. 'nakasi')."""
+    return self.GetProp('ro.product.name', cache=True)
+
+  def GetProp(self, property_name, cache=False, timeout=DEFAULT,
+              retries=DEFAULT):
     """Gets a property from the device.
 
     Args:
@@ -1024,9 +1102,10 @@
     else:
       # timeout and retries are handled down at run shell, because we don't
       # want to apply them in the other branch when reading from the cache
-      value = self.RunShellCommand(['getprop', property_name],
-                                   single_line=True, check_return=True,
-                                   timeout=timeout, retries=retries)
+      value = self.RunShellCommand(
+          ['getprop', property_name], single_line=True, check_return=True,
+          timeout=self._default_timeout if timeout is DEFAULT else timeout,
+          retries=self._default_retries if retries is DEFAULT else retries)
       if cache or cache_key in self._cache:
         self._cache[cache_key] = value
       return value
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index 2646bfb..16699ad 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -370,19 +370,25 @@
 class DeviceUtilsGetApplicationPathTest(DeviceUtilsNewImplTest):
 
   def testGetApplicationPath_exists(self):
-    with self.assertCall(self.call.adb.Shell('pm path android'),
-                         'package:/path/to/android.apk\n'):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.version.sdk'), '19\n'),
+        (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.assertCall(self.call.adb.Shell('pm path not.installed.app'), ''):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.version.sdk'), '19\n'),
+        (self.call.adb.Shell('pm path not.installed.app'), '')):
       self.assertEquals(None,
                         self.device.GetApplicationPath('not.installed.app'))
 
   def testGetApplicationPath_fails(self):
-    with self.assertCall(self.call.adb.Shell('pm path android'),
-        self.CommandError('ERROR. Is package manager running?\n')):
+    with self.assertCalls(
+        (self.call.adb.Shell('getprop ro.build.version.sdk'), '19\n'),
+        (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')
 
diff --git a/build/android/pylib/device_settings.py b/build/android/pylib/device_settings.py
index 246c1d1..73ffa72 100644
--- a/build/android/pylib/device_settings.py
+++ b/build/android/pylib/device_settings.py
@@ -6,6 +6,7 @@
 
 from pylib import constants
 from pylib import content_settings
+from pylib.device import device_errors
 
 _LOCK_SCREEN_SETTINGS_PATH = '/data/system/locksettings.db'
 _ALTERNATE_LOCK_SCREEN_SETTINGS_PATH = (
@@ -29,17 +30,16 @@
         settings to configure.
   """
   try:
-    sdk_version = int(device.GetProp('ro.build.version.sdk'))
-  except ValueError:
-    logging.error('Skipping content settings configuration, unknown sdk %s',
-                  device.GetProp('ro.build.version.sdk'))
+    sdk_version = device.build_version_sdk
+  except device_errors.CommandFailedError as exc:
+    logging.error('Skipping content settings configuration: %s', str(exc))
     return
 
   if sdk_version < constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN:
     logging.error('Skipping content settings configuration due to outdated sdk')
     return
 
-  if device.GetProp('ro.build.type') == 'userdebug':
+  if device.build_type == 'userdebug':
     for table, key_value in desired_settings:
       settings = content_settings.ContentSettings(table, device)
       for key, value in key_value:
@@ -68,7 +68,7 @@
   Raises:
     Exception if the setting was not properly set.
   """
-  if device.GetProp('ro.build.type') != 'userdebug':
+  if device.build_type != 'userdebug':
     logging.warning('Unable to disable lockscreen on user builds.')
     return
 
diff --git a/build/android/pylib/gtest/filter/unit_tests_disabled b/build/android/pylib/gtest/filter/unit_tests_disabled
index 6e7be1a..93defbe 100644
--- a/build/android/pylib/gtest/filter/unit_tests_disabled
+++ b/build/android/pylib/gtest/filter/unit_tests_disabled
@@ -67,7 +67,6 @@
 PermissionsUpdaterTest.*
 ImageLoaderTest.*
 ImageLoadingTrackerTest.*
-ScriptBadgeControllerTest.*
 ExtensionSettingsFrontendTest.*
 ExtensionSettingsSyncTest.*
 ExtensionUpdaterTest.*
diff --git a/build/android/pylib/gtest/gtest_config.py b/build/android/pylib/gtest/gtest_config.py
index 20aaf68..cf72d65 100644
--- a/build/android/pylib/gtest/gtest_config.py
+++ b/build/android/pylib/gtest/gtest_config.py
@@ -35,6 +35,7 @@
     'sandbox_linux_unittests',
     'sql_unittests',
     'sync_unit_tests',
+    'ui_android_unittests',
     'ui_base_unittests',
     'ui_touch_selection_unittests',
     'unit_tests',
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py
index 1e87693..f4623e4 100644
--- a/build/android/pylib/gtest/gtest_test_instance.py
+++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -42,9 +42,12 @@
 
   def __init__(self, options, isolate_delegate):
     super(GtestTestInstance, self).__init__()
+    # TODO(jbudorick): Support multiple test suites.
+    if len(options.suite_name) > 1:
+      raise ValueError('Platform mode currently supports only 1 gtest suite')
     self._apk_path = os.path.join(
-        constants.GetOutDirectory(), '%s_apk' % options.suite_name,
-        '%s-debug.apk' % options.suite_name)
+        constants.GetOutDirectory(), '%s_apk' % options.suite_name[0],
+        '%s-debug.apk' % options.suite_name[0])
     self._data_deps = []
     self._gtest_filter = options.test_filter
     if options.isolate_file_path:
diff --git a/build/android/pylib/instrumentation/test_jar.py b/build/android/pylib/instrumentation/test_jar.py
index 4473810..c3faef3 100644
--- a/build/android/pylib/instrumentation/test_jar.py
+++ b/build/android/pylib/instrumentation/test_jar.py
@@ -215,12 +215,10 @@
 
     # Filter out any tests with SDK level requirements that don't match the set
     # of attached devices.
-    sdk_versions = [
-        int(v) for v in
-        device_utils.DeviceUtils.parallel().GetProp(
-            'ro.build.version.sdk').pGet(None)]
+    devices = device_utils.DeviceUtils.parallel()
+    min_sdk_version = min(devices.build_version_sdk.pGet(None))
     tests = [t for t in tests
-             if self._IsTestValidForSdkRange(t, min(sdk_versions))]
+             if self._IsTestValidForSdkRange(t, min_sdk_version)]
 
     return tests
 
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py
index 92d80f97..fe444e9 100644
--- a/build/android/pylib/instrumentation/test_runner.py
+++ b/build/android/pylib/instrumentation/test_runner.py
@@ -299,8 +299,8 @@
     if 'SmallTest' in annotations:
       return 1 * 60
 
-    logging.warn(("Test size not found in annotations for test '{0}', using " +
-                  "1 minute for timeout.").format(test))
+    logging.warn(("Test size not found in annotations for test '%s', using " +
+                  "1 minute for timeout.") % test)
     return 1 * 60
 
   def _RunTest(self, test, timeout):
@@ -443,7 +443,7 @@
     timeout = (self._GetIndividualTestTimeoutSecs(test) *
                self._GetIndividualTestTimeoutScale(test) *
                self.tool.GetTimeoutScale())
-    if (self.device.GetProp('ro.build.version.sdk')
+    if (self.device.build_version_sdk
         < constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN):
       timeout *= 10
 
diff --git a/build/android/pylib/perf/perf_control.py b/build/android/pylib/perf/perf_control.py
index 0da1bcf..97fa4a7 100644
--- a/build/android/pylib/perf/perf_control.py
+++ b/build/android/pylib/perf/perf_control.py
@@ -36,7 +36,7 @@
       atexit.register(logging.warning, message)
       return
 
-    product_model = self._device.old_interface.GetProductModel()
+    product_model = self._device.product_model
     # TODO(epenner): Enable on all devices (http://crbug.com/383566)
     if 'Nexus 4' == product_model:
       self._ForceAllCpusOnline(True)
@@ -66,7 +66,7 @@
     """Sets the performance mode for the device to its default mode."""
     if not self._device.old_interface.IsRootEnabled():
       return
-    product_model = self._device.old_interface.GetProductModel()
+    product_model = self._device.product_model
     if 'Nexus 5' == product_model:
       if self._AllCpusAreOnline():
         self._SetScalingMaxFreq(2265600)
diff --git a/build/android/pylib/remote/__init__.py b/build/android/pylib/remote/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/remote/__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/remote/device/__init__.py b/build/android/pylib/remote/device/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/remote/device/__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/remote/device/remote_device_environment.py b/build/android/pylib/remote/device/remote_device_environment.py
new file mode 100644
index 0000000..871c0a8
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_environment.py
@@ -0,0 +1,151 @@
+# 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.
+
+"""Environment setup and teardown for remote devices."""
+
+import os
+import sys
+
+from pylib import constants
+from pylib.base import environment
+from pylib.remote.device import remote_device_helper
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'requests', 'src'))
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'appurify-python', 'src'))
+import appurify.api
+
+
+class RemoteDeviceEnvironment(environment.Environment):
+  """An environment for running on remote devices."""
+
+  def __init__(self, args, error_func):
+    """Constructor.
+
+    Args:
+      args: Command line arguments.
+      error_func: error to show when using bad command line arguments.
+    """
+    super(RemoteDeviceEnvironment, self).__init__()
+
+    if args.api_key_file:
+      with open(args.api_key_file) as api_key_file:
+        self._api_key = api_key_file.read().strip()
+    elif args.api_key:
+      self._api_key = args.api_key
+    else:
+      error_func('Must set api key with --api-key or --api-key-file')
+
+    if args.api_secret_file:
+      with open(args.api_secret_file) as api_secret_file:
+        self._api_secret = api_secret_file.read().strip()
+    elif args.api_secret:
+      self._api_secret = args.api_secret
+    else:
+      error_func('Must set api secret with --api-secret or --api-secret-file')
+
+    if not args.api_protocol:
+      error_func('Must set api protocol with --api-protocol. Example: http')
+    self._api_protocol = args.api_protocol
+
+    if not args.api_address:
+      error_func('Must set api address with --api-address')
+    self._api_address = args.api_address
+
+    if not args.api_port:
+      error_func('Must set api port with --api-port.')
+    self._api_port = args.api_port
+
+    self._access_token = ''
+    self._results_path = args.results_path
+    self._remote_device = args.remote_device
+    self._remote_device_os = args.remote_device_os
+    self._runner_package = args.runner_package
+    self._runner_type = args.runner_type
+    self._device = ''
+    if not args.trigger and not args.collect:
+      self._trigger = True
+      self._collect = True
+    else:
+      self._trigger = args.trigger
+      self._collect = args.collect
+
+  def SetUp(self):
+    """Set up the test environment."""
+    os.environ['APPURIFY_API_PROTO'] = self._api_protocol
+    os.environ['APPURIFY_API_HOST'] = self._api_address
+    os.environ['APPURIFY_API_PORT'] = self._api_port
+    self._GetAccessToken()
+    if self._trigger:
+      self._device = self._SelectDevice()
+
+  def TearDown(self):
+    """Teardown the test environment."""
+    self._RevokeAccessToken()
+
+  def __enter__(self):
+    """Set up the test run when used as a context manager."""
+    self.SetUp()
+    return self
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    """Tears down the test run when used as a context manager."""
+    self.TearDown()
+
+  def _GetAccessToken(self):
+    """Generates access token for remote device service."""
+    access_token_results = appurify.api.access_token_generate(
+        self._api_key, self._api_secret)
+    remote_device_helper.TestHttpResponse(access_token_results,
+                                          'Unable to generate access token.')
+    self._access_token = access_token_results.json()['response']['access_token']
+
+  def _RevokeAccessToken(self):
+    """Destroys access token for remote device service."""
+    revoke_token_results = appurify.api.access_token_revoke(self._access_token)
+    remote_device_helper.TestHttpResponse(revoke_token_results,
+                                          'Unable to revoke access token.')
+
+  def _SelectDevice(self):
+    """Select which device to use."""
+    dev_list_res = appurify.api.devices_list(self._access_token)
+    remote_device_helper.TestHttpResponse(dev_list_res,
+                                          'Unable to generate access token.')
+    device_list = dev_list_res.json()['response']
+    for device in device_list:
+      if (device['name'] == self._remote_device
+          and device['os_version'] == self._remote_device_os):
+        return device['device_type_id']
+    raise remote_device_helper.RemoteDeviceError(
+        'No device found: %s %s' % (self._remote_device,
+        self._remote_device_os))
+
+  @property
+  def device(self):
+    return self._device
+
+  @property
+  def token(self):
+    return self._access_token
+
+  @property
+  def results_path(self):
+    return self._results_path
+
+  @property
+  def runner_type(self):
+    return self._runner_type
+
+  @property
+  def runner_package(self):
+    return self._runner_package
+
+  @property
+  def trigger(self):
+    return self._trigger
+
+  @property
+  def collect(self):
+    return self._collect
diff --git a/build/android/pylib/remote/device/remote_device_gtest_run.py b/build/android/pylib/remote/device/remote_device_gtest_run.py
new file mode 100644
index 0000000..fa8d5f9
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_gtest_run.py
@@ -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.
+
+"""Run specific test on specific environment."""
+
+import logging
+import os
+import sys
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.remote.device import remote_device_test_run
+from pylib.remote.device import remote_device_helper
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'requests', 'src'))
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'appurify-python', 'src'))
+import appurify.api
+import appurify.utils
+
+class RemoteDeviceGtestRun(remote_device_test_run.RemoteDeviceTestRun):
+  """Run gtests and uirobot tests on a remote device."""
+
+  DEFAULT_RUNNER_TYPE = 'robotium'
+  DEFAULT_RUNNER_PACKAGE = (
+      'org.chromium.native_test.ChromiumNativeTestInstrumentationTestRunner')
+
+  def TestPackage(self):
+    pass
+
+  #override
+  def _TriggerSetUp(self):
+    """Set up the triggering of a test run."""
+    self._app_id = self._UploadAppToDevice(self._test_instance.apk)
+
+    if not self._env.runner_type:
+      runner_type = self.DEFAULT_RUNNER_TYPE
+      logging.info('Using default runner type: %s', self.DEFAULT_RUNNER_TYPE)
+    else:
+      runner_type = self._env.runner_type
+
+    if not self._env.runner_package:
+      runner_package = self.DEFAULT_RUNNER_PACKAGE
+      logging.info('Using default runner package: %s',
+                    self.DEFAULT_RUNNER_TYPE)
+    else:
+      runner_package = self._env.runner_package
+
+    self._test_id = self._UploadTestToDevice(runner_type)
+    config_body = {'runner': runner_package}
+    self._SetTestConfig(runner_type, config_body)
+
+  #override
+  def _ParseTestResults(self):
+    # TODO(rnephew): Populate test results object.
+    results = base_test_result.TestRunResults()
+    return results
diff --git a/build/android/pylib/remote/device/remote_device_helper.py b/build/android/pylib/remote/device/remote_device_helper.py
new file mode 100644
index 0000000..a4cd488
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_helper.py
@@ -0,0 +1,21 @@
+# 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.
+
+"""Common functions and Exceptions for remote_device_*"""
+
+
+class RemoteDeviceError(Exception):
+  """Exception to throw when problems occur with remote device service."""
+  pass
+
+
+def TestHttpResponse(response, error_msg):
+  """Checks the Http response from remote device service.
+
+  Args:
+      response: response dict from the remote device service.
+      error_msg: Error message to display if bad response is seen.
+  """
+  if response.status_code != 200:
+    raise RemoteDeviceError(error_msg)
diff --git a/build/android/pylib/remote/device/remote_device_test_run.py b/build/android/pylib/remote/device/remote_device_test_run.py
new file mode 100644
index 0000000..97e44b0
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_test_run.py
@@ -0,0 +1,176 @@
+# 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.
+
+"""Run specific test on specific environment."""
+
+import logging
+import os
+import sys
+import tempfile
+import time
+
+from pylib import constants
+from pylib.base import test_run
+from pylib.remote.device import remote_device_helper
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'requests', 'src'))
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'appurify-python', 'src'))
+import appurify.api
+import appurify.utils
+
+class RemoteDeviceTestRun(test_run.TestRun):
+  """Run gtests and uirobot tests on a remote device."""
+
+  WAIT_TIME = 5
+  COMPLETE = 'complete'
+
+  def __init__(self, env, test_instance):
+    """Constructor.
+
+    Args:
+      env: Environment the tests will run in.
+      test_instance: The test that will be run.
+    """
+    super(RemoteDeviceTestRun, self).__init__(env, test_instance)
+    self._env = env
+    self._test_instance = test_instance
+    self._app_id = ''
+    self._test_id = ''
+    self._results = ''
+
+  def TestPackage(self):
+    pass
+
+  #override
+  def RunTests(self):
+    """Run the test."""
+    if self._env.trigger:
+      test_start_res = appurify.api.tests_run(
+          self._env.token, self._env.device, self._app_id, self._test_id)
+      remote_device_helper.TestHttpResponse(
+        test_start_res, 'Unable to run test.')
+      test_run_id = test_start_res.json()['response']['test_run_id']
+      if not self._env.collect:
+        assert isinstance(self._env.trigger, basestring), (
+                          'File for storing test_run_id must be a string.')
+        with open(self._env.trigger, 'w') as test_run_id_file:
+          test_run_id_file.write(test_run_id)
+
+    if self._env.collect:
+      if not self._env.trigger:
+        assert isinstance(self._env.trigger, basestring), (
+                          'File for storing test_run_id must be a string.')
+        with open(self._env.collect, 'r') as test_run_id_file:
+          test_run_id = test_run_id_file.read()
+      while self._GetTestStatus(test_run_id) != self.COMPLETE:
+        time.sleep(self.WAIT_TIME)
+      self._DownloadTestResults(self._env.results_path)
+      return self._ParseTestResults()
+
+  #override
+  def TearDown(self):
+    """Tear down the test run."""
+    pass
+
+  def __enter__(self):
+    """Set up the test run when used as a context manager."""
+    self.SetUp()
+    return self
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    """Tear down the test run when used as a context manager."""
+    self.TearDown()
+
+  #override
+  def SetUp(self):
+    """Set up a test run."""
+    if self._env.trigger:
+      self._TriggerSetUp()
+
+  def _TriggerSetUp(self):
+    """Set up the triggering of a test run."""
+    raise NotImplementedError
+
+  def _ParseTestResults(self):
+    raise NotImplementedError
+
+  def _GetTestByName(self, test_name):
+    """Gets test_id for specific test.
+
+    Args:
+      test_name: Test to find the ID of.
+    """
+    test_list_res = appurify.api.tests_list(self._env.token)
+    remote_device_helper.TestHttpResponse(test_list_res,
+                                          'Unable to get tests list.')
+    for test in test_list_res.json()['response']:
+      if test['test_type'] == test_name:
+        return test['test_id']
+    raise remote_device_helper.RemoteDeviceError(
+        'No test found with name %s' % (test_name))
+
+  def _DownloadTestResults(self, results_path):
+    """Download the test results from remote device service.
+
+    Args:
+      results_path: path to download results to.
+    """
+    if results_path:
+      if not os.path.exists(os.path.basename(results_path)):
+        os.makedirs(os.path.basename(results_path))
+      appurify.utils.wget(self._results['results']['url'], results_path)
+
+  def _GetTestStatus(self, test_run_id):
+    """Checks the state of the test, and sets self._results
+
+    Args:
+      test_run_id: Id of test on on remote service.
+    """
+
+    test_check_res = appurify.api.tests_check_result(self._env.token,
+                                                     test_run_id)
+    remote_device_helper.TestHttpResponse(test_check_res,
+                                          'Unable to get test status.')
+    self._results = test_check_res.json()['response']
+    return self._results['status']
+
+  def _UploadAppToDevice(self, apk_path):
+    """Upload app to device."""
+    apk_name = os.path.basename(apk_path)
+    with open(apk_path, 'rb') as apk_src:
+      upload_results = appurify.api.apps_upload(self._env.token,
+                                                apk_src, 'raw', name=apk_name)
+      remote_device_helper.TestHttpResponse(
+          upload_results, 'Unable to upload %s.' %(apk_path))
+      return upload_results.json()['response']['app_id']
+
+  def _UploadTestToDevice(self, test_type):
+    """Upload test to device
+    Args:
+      test_type: Type of test that is being uploaded. Ex. uirobot, gtest..
+    """
+    with open(self._test_instance.apk, 'rb') as test_src:
+      upload_results = appurify.api.tests_upload(
+          self._env.token, test_src, 'raw', test_type, app_id=self._app_id)
+      remote_device_helper.TestHttpResponse(upload_results,
+          'Unable to upload %s.' %(self._test_instance.apk))
+      return upload_results.json()['response']['test_id']
+
+  def _SetTestConfig(self, runner_type, body):
+    """Generates and uploads config file for test.
+    Args:
+      extras: Extra arguments to set in the config file.
+    """
+    with tempfile.TemporaryFile() as config:
+      config_data = ['[appurify]', '[%s]' % runner_type]
+      config_data.extend('%s=%s' % (k, v) for k, v in body.iteritems())
+      config.write(''.join('%s\n' % l for l in config_data))
+      config.flush()
+      config.seek(0)
+      config_response = appurify.api.config_upload(self._env.token,
+                                                   config, self._test_id)
+      remote_device_helper.TestHttpResponse(config_response,
+                                            'Unable to upload test config.')
diff --git a/build/android/pylib/remote/device/remote_device_uirobot_run.py b/build/android/pylib/remote/device/remote_device_uirobot_run.py
new file mode 100644
index 0000000..d2d6f36
--- /dev/null
+++ b/build/android/pylib/remote/device/remote_device_uirobot_run.py
@@ -0,0 +1,58 @@
+# 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.
+
+"""Run specific test on specific environment."""
+
+import logging
+import os
+import sys
+
+from pylib import constants
+from pylib.base import base_test_result
+from pylib.remote.device import remote_device_test_run
+from pylib.remote.device import remote_device_helper
+
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'requests', 'src'))
+sys.path.append(os.path.join(
+    constants.DIR_SOURCE_ROOT, 'third_party', 'appurify-python', 'src'))
+import appurify.api
+import appurify.utils
+
+class RemoteDeviceUirobotRun(remote_device_test_run.RemoteDeviceTestRun):
+  """Run uirobot tests on a remote device."""
+
+  DEFAULT_RUNNER_TYPE = 'android_robot'
+
+  def __init__(self, env, test_instance):
+    """Constructor.
+
+    Args:
+      env: Environment the tests will run in.
+      test_instance: The test that will be run.
+    """
+    super(RemoteDeviceUirobotRun, self).__init__(env, test_instance)
+
+  def TestPackage(self):
+    pass
+
+  #override
+  def _TriggerSetUp(self):
+    """Set up the triggering of a test run."""
+    self._app_id = self._UploadAppToDevice(self._test_instance.apk_under_test)
+    if not self._env.runner_type:
+      runner_type = self.DEFAULT_RUNNER_TYPE
+      logging.info('Using default runner type: %s', self.DEFAULT_RUNNER_TYPE)
+    else:
+      runner_type = self._env.runner_type
+    self._test_id = self._GetTestByName(runner_type)
+    config_body = {'duration': self._test_instance.minutes}
+    self._SetTestConfig(runner_type, config_body)
+
+  #override
+  def _ParseTestResults(self):
+    # TODO(rnephew): Populate test results object.
+    results = remote_device_test_run.TestRunResults()
+    return results
+
diff --git a/build/android/pylib/uirobot/__init__.py b/build/android/pylib/uirobot/__init__.py
new file mode 100644
index 0000000..5cac026
--- /dev/null
+++ b/build/android/pylib/uirobot/__init__.py
@@ -0,0 +1,4 @@
+# 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/uirobot/uirobot_test_instance.py b/build/android/pylib/uirobot/uirobot_test_instance.py
new file mode 100644
index 0000000..b129f89
--- /dev/null
+++ b/build/android/pylib/uirobot/uirobot_test_instance.py
@@ -0,0 +1,51 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+
+from pylib import constants
+from pylib.base import test_instance
+
+class UirobotTestInstance(test_instance.TestInstance):
+
+  def __init__(self, args):
+    """Constructor.
+
+    Args:
+      args: Command line arguments.
+    """
+    super(UirobotTestInstance, self).__init__()
+    self._apk_under_test = os.path.join(
+        constants.GetOutDirectory(), args.apk_under_test)
+    self._minutes = args.minutes
+
+  #override
+  def TestType(self):
+    """Returns type of test."""
+    return 'uirobot'
+
+  #override
+  def SetUp(self):
+    """Setup for test."""
+    pass
+
+  #override
+  def TearDown(self):
+    """Teardown for test."""
+    pass
+
+  @property
+  def apk_under_test(self):
+    """Returns the app to run the test on."""
+    return self._apk_under_test
+
+  @property
+  def suite(self):
+    """Returns the test suite, none for uirobot."""
+    return None
+
+  @property
+  def minutes(self):
+    """Returns the number of minutes to run the uirobot for."""
+    return self._minutes
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 68827b9..657e7c2 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -119,6 +119,45 @@
     os.environ['PATH'] = adb_dir + os.pathsep + os.environ['PATH']
 
 
+def AddRemoteDeviceOptions(parser):
+  group = parser.add_argument_group('Remote Device Options')
+
+  group.add_argument('--trigger', default='',
+                   help=('Only triggers the test if set. Stores test_run_id '
+                         'in given file path. '))
+  group.add_argument('--collect', default='',
+                   help=('Only collects the test results if set. '
+                         'Gets test_run_id from given file path.'))
+  group.add_argument('--remote-device', default='Nexus 5',
+                   help=('Device type to run test on.'))
+  group.add_argument('--remote-device-os', default='4.4.2',
+                   help=('OS to have on the device.'))
+  group.add_argument('--results-path', default='',
+                   help=('File path to download results to.'))
+  group.add_argument('--api-protocol',
+                   help=('HTTP protocol to use. (http or https)'))
+  group.add_argument('--api-address', help=('Address to send HTTP requests.'))
+  group.add_argument('--api-port', help=('Port to send HTTP requests to.'))
+  group.add_argument('--runner-type', default='',
+                   help=('Type of test to run as.'))
+  group.add_argument('--runner-package', default='',
+                   help=('Package name of test.'))
+  group.add_argument('--apk-under-test', default='apks/Chrome.apk',
+                   help=('APK to run tests on.'))
+
+  api_secret_group = group.add_mutually_exclusive_group()
+  api_secret_group.add_argument('--api-secret', default='',
+                   help=('API secret for remote devices.'))
+  api_secret_group.add_argument('--api-secret-file', default='',
+                   help=('Path to file that contains API secret.'))
+
+  api_key_group = group.add_mutually_exclusive_group()
+  api_key_group.add_argument('--api-key', default='',
+                   help=('API key for remote devices.'))
+  api_key_group.add_argument('--api-key-file', default='',
+                   help=('Path to file that contains API key.'))
+
+
 def AddDeviceOptions(parser):
   """Adds device options to |parser|."""
   group = parser.add_argument_group(title='Device Options')
@@ -166,6 +205,7 @@
                           'path')
   AddDeviceOptions(parser)
   AddCommonOptions(parser)
+  AddRemoteDeviceOptions(parser)
 
 
 def AddLinkerTestOptions(parser):
@@ -426,7 +466,6 @@
   AddCommonOptions(parser)
   AddDeviceOptions(parser)
 
-
 def ProcessMonkeyTestOptions(args):
   """Processes all monkey test options.
 
@@ -452,6 +491,17 @@
       args.seed,
       args.extra_args)
 
+def AddUirobotTestOptions(parser):
+  """Adds uirobot test options to |option_parser|."""
+  group = parser.add_argument_group('Uirobot Test Options')
+
+  group.add_argument(
+      '--minutes', default=5, type=int,
+      help='Number of minutes to run uirobot test [default: %default].')
+
+  AddCommonOptions(parser)
+  AddDeviceOptions(parser)
+  AddRemoteDeviceOptions(parser)
 
 def AddPerfTestOptions(parser):
   """Adds perf test options to |parser|."""
@@ -812,7 +862,7 @@
   ProcessCommonOptions(args)
 
   if args.enable_platform_mode:
-    return RunTestsInPlatformMode(args, parser.error)
+    return RunTestsInPlatformMode(args, parser)
 
   if command in constants.LOCAL_MACHINE_TESTS:
     devices = []
@@ -845,7 +895,7 @@
 
 _SUPPORTED_IN_PLATFORM_MODE = [
   # TODO(jbudorick): Add support for more test types.
-  'gtest',
+  'gtest', 'uirobot',
 ]
 
 
@@ -860,6 +910,9 @@
           args, env, test, parser.error) as test_run:
         results = test_run.RunTests()
 
+        if args.trigger:
+          return 0 # Not returning results, only triggering.
+
         report_results.LogFull(
             results=results,
             test_type=test.TestType(),
@@ -871,7 +924,7 @@
           json_results.GenerateJsonResultsFile(
               results, args.json_results_file)
 
-  return results
+  return 0 if results.DidRunPass() else 1
 
 
 CommandConfigTuple = collections.namedtuple(
@@ -902,6 +955,9 @@
     'linker': CommandConfigTuple(
         AddLinkerTestOptions,
         'Linker tests'),
+    'uirobot': CommandConfigTuple(
+        AddUirobotTestOptions,
+        'Uirobot test'),
 }
 
 
diff --git a/build/android/tombstones.py b/build/android/tombstones.py
index fd060ad..a78d89f 100755
--- a/build/android/tombstones.py
+++ b/build/android/tombstones.py
@@ -173,7 +173,7 @@
   device_now = _GetDeviceDateTime(device)
   for tombstone_file, tombstone_time in tombstones:
     ret += [{'serial': str(device),
-             'device_abi': device.GetProp('ro.product.cpu.abi'),
+             'device_abi': device.product_cpu_abi,
              'device_now': device_now,
              'time': tombstone_time,
              'file': tombstone_file,
diff --git a/build/common.gypi b/build/common.gypi
index c899e14..30239f1 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -619,7 +619,7 @@
       # completion, but only actually requires them for layout tests. However,
       # we need to maintain all the old behaviors while the plumbing is put in
       # place on both sides of the repo boundary.
-      'enable_load_completion_hacks%': 1,
+      'enable_load_completion_hacks%': 0,
 
       # Automatically select platforms under ozone. Turn this off to
       # build only explicitly selected platforms.
@@ -706,6 +706,13 @@
           'use_dbus%': 0,
         }],
 
+        # Libxkbcommon usage.
+        ['use_ozone==1 and embedded==0', {
+          'use_xkbcommon%': 1,
+        }, {
+          'use_xkbcommon%': 0,
+        }],
+
         # We always use skia text rendering in Aura on Windows, since GDI
         # doesn't agree with our BackingStore.
         # TODO(beng): remove once skia text rendering is on by default.
@@ -1087,6 +1094,7 @@
     'use_cairo%': '<(use_cairo)',
     'use_ozone%': '<(use_ozone)',
     'use_ozone_evdev%': '<(use_ozone_evdev)',
+    'use_xkbcommon%': '<(use_xkbcommon)',
     'use_clipboard_aurax11%': '<(use_clipboard_aurax11)',
     'desktop_linux%': '<(desktop_linux)',
     'use_x11%': '<(use_x11)',
@@ -2521,6 +2529,9 @@
         # code generated by flex (used in angle) contains that keyword.
         # http://crbug.com/255186
         '-Wno-deprecated-register',
+
+        # TODO(hans): Get this cleaned up.
+        '-Wno-inconsistent-missing-override',
       ],
     },
     'includes': [ 'set_clang_warning_flags.gypi', ],
@@ -4185,6 +4196,13 @@
                 ],
               }],
             ],
+            'conditions': [
+              ['OS=="mac"', {
+                'cflags': [
+                  '-mllvm -asan-globals=0',  # http://crbug.com/352073
+                ],
+              }],
+            ],
           }],
           ['ubsan==1', {
             'target_conditions': [
@@ -4235,7 +4253,7 @@
             'target_conditions': [
               ['_toolset=="target"', {
                 'cflags': [
-                  '-mllvm -asan-coverage=<(asan_coverage)',
+                  '-fsanitize-coverage=<(asan_coverage)',
                 ],
               }],
             ],
@@ -4606,16 +4624,6 @@
                   # TODO(eugenis): find a way to reenable this.
                   '-mllvm -asan-globals=0',
                 ],
-                'conditions': [
-                  ['target_arch=="arm"', {
-                    'ldflags': [
-                      # TODO(hans): The ASan runtime is no longer automatically
-                      # added to the link line when using -nostdlib. Can we
-                      # stop adding -nostdlib? (crbug.com/423429)
-                      '<!(cd <(DEPTH) && pwd -P)/<(make_clang_dir)/lib/clang/3.6.0/lib/linux/libclang_rt.asan-arm-android.so',
-                    ],
-                  }],
-                ],
               }],
               ['android_webview_build==0', {
                 'defines': [
@@ -4900,6 +4908,7 @@
             'xcode_settings': {
               'OTHER_CFLAGS': [
                 '-fsanitize=address',
+                '-mllvm -asan-globals=0',  # http://crbug.com/352073
                 '-gline-tables-only',
               ],
             },
@@ -4908,7 +4917,7 @@
             'target_conditions': [
               ['_toolset=="target"', {
                 'cflags': [
-                  '-mllvm -asan-coverage=<(asan_coverage)',
+                  '-fsanitize-coverage=<(asan_coverage)',
                 ],
               }],
             ],
diff --git a/build/config/OWNERS b/build/config/OWNERS
index 9b79b9a..bd53091 100644
--- a/build/config/OWNERS
+++ b/build/config/OWNERS
@@ -1,2 +1,6 @@
-set noparent
 brettw@chromium.org
+dpranke@chromium.org
+scottmg@chromium.org
+
+per-file BUILDCONFIG.gn=brettw@chromium.org
+per-file BUILDCONFIG.gn=set noparent
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 81269d6..c221ddd 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -762,6 +762,9 @@
 
         # TODO(thakis): Remove, http://crbug.com/263960
         "-Wno-reserved-user-defined-literal",
+
+        # TODO(hans): Get this cleaned up.
+        "-Wno-inconsistent-missing-override",
       ]
     }
     if (gcc_version >= 48) {
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
index 0d9faa0..b8d3caa 100644
--- a/build/ios/grit_whitelist.txt
+++ b/build/ios/grit_whitelist.txt
@@ -464,8 +464,6 @@
 IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_DESCRIPTION
 IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_HIGH_DPI
 IDS_FLAGS_COMPOSITING_FOR_FIXED_POSITION_NAME
-IDS_FLAGS_COMPOSITING_FOR_TRANSITION_DESCRIPTION
-IDS_FLAGS_COMPOSITING_FOR_TRANSITION_NAME
 IDS_FLAGS_CONFLICTS_CHECK_DESCRIPTION
 IDS_FLAGS_CONFLICTS_CHECK_NAME
 IDS_FLAGS_DEBUG_PACKED_APP_DESCRIPTION
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index cd0288b..09ee713 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -465,6 +465,27 @@
         },
       ],
     }],
+    ['use_xkbcommon==1', {
+      'targets': [
+        {
+          'target_name': 'xkbcommon',
+          'type': 'none',
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags xkbcommon)'
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other xkbcommon)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l xkbcommon)',
+            ],
+          },
+        },
+      ],
+    }],
     ['ozone_platform_gbm==1', {
       'targets': [
         {
diff --git a/build/sanitizers/sanitizer_options.cc b/build/sanitizers/sanitizer_options.cc
index 614a4a6..af78bf8 100644
--- a/build/sanitizers/sanitizer_options.cc
+++ b/build/sanitizers/sanitizer_options.cc
@@ -72,7 +72,7 @@
 const char *kAsanDefaultOptions =
     "strict_memcmp=0 replace_intrin=0 check_printf=1 use_sigaltstack=1 "
     "strip_path_prefix=Release/../../ fast_unwind_on_fatal=1 "
-    "detect_stack_use_after_return=1 ";
+    "detect_stack_use_after_return=1 detect_odr_violation=0 ";
 static const char kNaClDefaultOptions[] = "handle_segv=0";
 static const char kNaClFlag[] = "--type=nacl-loader";
 #endif  // OS_LINUX
diff --git a/build/toolchain/OWNERS b/build/toolchain/OWNERS
index 9b79b9a..c6cda3f 100644
--- a/build/toolchain/OWNERS
+++ b/build/toolchain/OWNERS
@@ -1,2 +1,3 @@
-set noparent
 brettw@chromium.org
+dpranke@chromium.org
+scottmg@chromium.org
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py
index 6b7ea7a..e8826b0 100644
--- a/build/toolchain/win/setup_toolchain.py
+++ b/build/toolchain/win/setup_toolchain.py
@@ -67,7 +67,8 @@
     # We only support x64-hosted tools.
     # TODO(scottmg|dpranke): Non-depot_tools toolchain: need to get Visual
     # Studio install location from registry.
-    return [os.path.normpath(os.path.join(FIND_VS_IN_REG, 'VC/vcvarsall.bat')),
+    return [os.path.normpath(os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
+                                          'VC/vcvarsall.bat')),
             'amd64_x86' if target_arch == 'x86' else 'amd64']
 
 
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index fb7e142..5373f03 100644
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -202,7 +202,7 @@
       os.environ['WINDOWSSDKDIR'],
       os.environ['GYP_MSVS_VERSION'],
       os.environ.get('WDK_DIR', ''),
-      ';'.join(runtime_dll_dirs))
+      ';'.join(runtime_dll_dirs or ['None']))
 
 
 def main():
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index 526203f..192677e 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -145,3 +145,5 @@
 Oh god the bots are red! I'm blind! Mmmm, cronuts.
 
 If you stand on your head, you will get footprints in your hair.
+
+sigh
\ No newline at end of file
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 592fd6e..13e974d 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -581,6 +581,8 @@
     "test/fake_tile_manager_client.h",
     "test/fake_ui_resource_layer_tree_host_impl.cc",
     "test/fake_ui_resource_layer_tree_host_impl.h",
+    "test/failure_output_surface.cc",
+    "test/failure_output_surface.h",
     "test/geometry_test_utils.cc",
     "test/geometry_test_utils.h",
     "test/test_in_process_context_provider.cc",
diff --git a/cc/base/tiling_data.cc b/cc/base/tiling_data.cc
index 7b39878..95fd68b 100644
--- a/cc/base/tiling_data.cc
+++ b/cc/base/tiling_data.cc
@@ -293,40 +293,39 @@
       max_texture_size_.height(), tiling_size_.height(), border_texels_);
 }
 
-TilingData::BaseIterator::BaseIterator(const TilingData* tiling_data)
-    : tiling_data_(tiling_data),
-      index_x_(-1),
-      index_y_(-1) {
+TilingData::BaseIterator::BaseIterator() : index_x_(-1), index_y_(-1) {
 }
 
-TilingData::Iterator::Iterator() : BaseIterator(nullptr) { done(); }
+TilingData::Iterator::Iterator() {
+  done();
+}
 
 TilingData::Iterator::Iterator(const TilingData* tiling_data,
                                const gfx::Rect& consider_rect,
                                bool include_borders)
-    : BaseIterator(tiling_data), left_(-1), right_(-1), bottom_(-1) {
-  if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
+    : left_(-1), right_(-1), bottom_(-1) {
+  if (tiling_data->num_tiles_x() <= 0 || tiling_data->num_tiles_y() <= 0) {
     done();
     return;
   }
 
-  gfx::Rect tiling_bounds_rect(tiling_data_->tiling_size());
+  gfx::Rect tiling_bounds_rect(tiling_data->tiling_size());
   gfx::Rect rect(consider_rect);
   rect.Intersect(tiling_bounds_rect);
 
   gfx::Rect top_left_tile;
   if (include_borders) {
-    index_x_ = tiling_data_->FirstBorderTileXIndexFromSrcCoord(rect.x());
-    index_y_ = tiling_data_->FirstBorderTileYIndexFromSrcCoord(rect.y());
-    right_ = tiling_data_->LastBorderTileXIndexFromSrcCoord(rect.right() - 1);
-    bottom_ = tiling_data_->LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1);
-    top_left_tile = tiling_data_->TileBoundsWithBorder(index_x_, index_y_);
+    index_x_ = tiling_data->FirstBorderTileXIndexFromSrcCoord(rect.x());
+    index_y_ = tiling_data->FirstBorderTileYIndexFromSrcCoord(rect.y());
+    right_ = tiling_data->LastBorderTileXIndexFromSrcCoord(rect.right() - 1);
+    bottom_ = tiling_data->LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1);
+    top_left_tile = tiling_data->TileBoundsWithBorder(index_x_, index_y_);
   } else {
-    index_x_ = tiling_data_->TileXIndexFromSrcCoord(rect.x());
-    index_y_ = tiling_data_->TileYIndexFromSrcCoord(rect.y());
-    right_ = tiling_data_->TileXIndexFromSrcCoord(rect.right() - 1);
-    bottom_ = tiling_data_->TileYIndexFromSrcCoord(rect.bottom() - 1);
-    top_left_tile = tiling_data_->TileBounds(index_x_, index_y_);
+    index_x_ = tiling_data->TileXIndexFromSrcCoord(rect.x());
+    index_y_ = tiling_data->TileYIndexFromSrcCoord(rect.y());
+    right_ = tiling_data->TileXIndexFromSrcCoord(rect.right() - 1);
+    bottom_ = tiling_data->TileYIndexFromSrcCoord(rect.bottom() - 1);
+    top_left_tile = tiling_data->TileBounds(index_x_, index_y_);
   }
   left_ = index_x_;
 
@@ -355,8 +354,7 @@
     const TilingData* tiling_data,
     const gfx::Rect& consider_rect,
     const gfx::Rect& ignore_rect)
-    : BaseIterator(tiling_data),
-      consider_left_(-1),
+    : consider_left_(-1),
       consider_top_(-1),
       consider_right_(-1),
       consider_bottom_(-1),
@@ -364,12 +362,12 @@
       ignore_top_(-1),
       ignore_right_(-1),
       ignore_bottom_(-1) {
-  if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
+  if (tiling_data->num_tiles_x() <= 0 || tiling_data->num_tiles_y() <= 0) {
     done();
     return;
   }
 
-  gfx::Rect tiling_bounds_rect(tiling_data_->tiling_size());
+  gfx::Rect tiling_bounds_rect(tiling_data->tiling_size());
   gfx::Rect consider(consider_rect);
   gfx::Rect ignore(ignore_rect);
   consider.Intersect(tiling_bounds_rect);
@@ -379,17 +377,16 @@
     return;
   }
 
-  consider_left_ = tiling_data_->TileXIndexFromSrcCoord(consider.x());
-  consider_top_ = tiling_data_->TileYIndexFromSrcCoord(consider.y());
-  consider_right_ = tiling_data_->TileXIndexFromSrcCoord(consider.right() - 1);
-  consider_bottom_ =
-      tiling_data_->TileYIndexFromSrcCoord(consider.bottom() - 1);
+  consider_left_ = tiling_data->TileXIndexFromSrcCoord(consider.x());
+  consider_top_ = tiling_data->TileYIndexFromSrcCoord(consider.y());
+  consider_right_ = tiling_data->TileXIndexFromSrcCoord(consider.right() - 1);
+  consider_bottom_ = tiling_data->TileYIndexFromSrcCoord(consider.bottom() - 1);
 
   if (!ignore.IsEmpty()) {
-    ignore_left_ = tiling_data_->TileXIndexFromSrcCoord(ignore.x());
-    ignore_top_ = tiling_data_->TileYIndexFromSrcCoord(ignore.y());
-    ignore_right_ = tiling_data_->TileXIndexFromSrcCoord(ignore.right() - 1);
-    ignore_bottom_ = tiling_data_->TileYIndexFromSrcCoord(ignore.bottom() - 1);
+    ignore_left_ = tiling_data->TileXIndexFromSrcCoord(ignore.x());
+    ignore_top_ = tiling_data->TileYIndexFromSrcCoord(ignore.y());
+    ignore_right_ = tiling_data->TileXIndexFromSrcCoord(ignore.right() - 1);
+    ignore_bottom_ = tiling_data->TileYIndexFromSrcCoord(ignore.bottom() - 1);
 
     // Clamp ignore indices to consider indices.
     ignore_left_ = std::max(ignore_left_, consider_left_);
@@ -440,8 +437,7 @@
   return *this;
 }
 
-TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator()
-    : BaseIterator(nullptr) {
+TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator() {
   done();
 }
 
@@ -450,8 +446,7 @@
     const gfx::Rect& consider_rect,
     const gfx::Rect& ignore_rect,
     const gfx::Rect& center_rect)
-    : BaseIterator(tiling_data),
-      consider_left_(-1),
+    : consider_left_(-1),
       consider_top_(-1),
       consider_right_(-1),
       consider_bottom_(-1),
@@ -465,12 +460,12 @@
       current_step_(0),
       horizontal_step_count_(0),
       vertical_step_count_(0) {
-  if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
+  if (tiling_data->num_tiles_x() <= 0 || tiling_data->num_tiles_y() <= 0) {
     done();
     return;
   }
 
-  gfx::Rect tiling_bounds_rect(tiling_data_->tiling_size());
+  gfx::Rect tiling_bounds_rect(tiling_data->tiling_size());
   gfx::Rect consider(consider_rect);
   gfx::Rect ignore(ignore_rect);
   gfx::Rect center(center_rect);
@@ -481,17 +476,16 @@
     return;
   }
 
-  consider_left_ = tiling_data_->TileXIndexFromSrcCoord(consider.x());
-  consider_top_ = tiling_data_->TileYIndexFromSrcCoord(consider.y());
-  consider_right_ = tiling_data_->TileXIndexFromSrcCoord(consider.right() - 1);
-  consider_bottom_ =
-      tiling_data_->TileYIndexFromSrcCoord(consider.bottom() - 1);
+  consider_left_ = tiling_data->TileXIndexFromSrcCoord(consider.x());
+  consider_top_ = tiling_data->TileYIndexFromSrcCoord(consider.y());
+  consider_right_ = tiling_data->TileXIndexFromSrcCoord(consider.right() - 1);
+  consider_bottom_ = tiling_data->TileYIndexFromSrcCoord(consider.bottom() - 1);
 
   if (!ignore.IsEmpty()) {
-    ignore_left_ = tiling_data_->TileXIndexFromSrcCoord(ignore.x());
-    ignore_top_ = tiling_data_->TileYIndexFromSrcCoord(ignore.y());
-    ignore_right_ = tiling_data_->TileXIndexFromSrcCoord(ignore.right() - 1);
-    ignore_bottom_ = tiling_data_->TileYIndexFromSrcCoord(ignore.bottom() - 1);
+    ignore_left_ = tiling_data->TileXIndexFromSrcCoord(ignore.x());
+    ignore_top_ = tiling_data->TileYIndexFromSrcCoord(ignore.y());
+    ignore_right_ = tiling_data->TileXIndexFromSrcCoord(ignore.right() - 1);
+    ignore_bottom_ = tiling_data->TileYIndexFromSrcCoord(ignore.bottom() - 1);
 
     // Clamp ignore indices to consider indices.
     ignore_left_ = std::max(ignore_left_, consider_left_);
@@ -666,8 +660,7 @@
   }
 }
 
-TilingData::ReverseSpiralDifferenceIterator::ReverseSpiralDifferenceIterator()
-    : BaseIterator(nullptr) {
+TilingData::ReverseSpiralDifferenceIterator::ReverseSpiralDifferenceIterator() {
   done();
 }
 
@@ -676,8 +669,7 @@
     const gfx::Rect& consider_rect,
     const gfx::Rect& ignore_rect,
     const gfx::Rect& center_rect)
-    : BaseIterator(tiling_data),
-      consider_left_(-1),
+    : consider_left_(-1),
       consider_top_(-1),
       consider_right_(-1),
       consider_bottom_(-1),
@@ -695,12 +687,12 @@
       current_step_(0),
       horizontal_step_count_(0),
       vertical_step_count_(0) {
-  if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
+  if (tiling_data->num_tiles_x() <= 0 || tiling_data->num_tiles_y() <= 0) {
     done();
     return;
   }
 
-  gfx::Rect tiling_bounds_rect(tiling_data_->tiling_size());
+  gfx::Rect tiling_bounds_rect(tiling_data->tiling_size());
   gfx::Rect consider(consider_rect);
   gfx::Rect ignore(ignore_rect);
   gfx::Rect center(center_rect);
@@ -711,17 +703,16 @@
     return;
   }
 
-  consider_left_ = tiling_data_->TileXIndexFromSrcCoord(consider.x());
-  consider_top_ = tiling_data_->TileYIndexFromSrcCoord(consider.y());
-  consider_right_ = tiling_data_->TileXIndexFromSrcCoord(consider.right() - 1);
-  consider_bottom_ =
-      tiling_data_->TileYIndexFromSrcCoord(consider.bottom() - 1);
+  consider_left_ = tiling_data->TileXIndexFromSrcCoord(consider.x());
+  consider_top_ = tiling_data->TileYIndexFromSrcCoord(consider.y());
+  consider_right_ = tiling_data->TileXIndexFromSrcCoord(consider.right() - 1);
+  consider_bottom_ = tiling_data->TileYIndexFromSrcCoord(consider.bottom() - 1);
 
   if (!ignore.IsEmpty()) {
-    ignore_left_ = tiling_data_->TileXIndexFromSrcCoord(ignore.x());
-    ignore_top_ = tiling_data_->TileYIndexFromSrcCoord(ignore.y());
-    ignore_right_ = tiling_data_->TileXIndexFromSrcCoord(ignore.right() - 1);
-    ignore_bottom_ = tiling_data_->TileYIndexFromSrcCoord(ignore.bottom() - 1);
+    ignore_left_ = tiling_data->TileXIndexFromSrcCoord(ignore.x());
+    ignore_top_ = tiling_data->TileYIndexFromSrcCoord(ignore.y());
+    ignore_right_ = tiling_data->TileXIndexFromSrcCoord(ignore.right() - 1);
+    ignore_bottom_ = tiling_data->TileYIndexFromSrcCoord(ignore.bottom() - 1);
 
     // Clamp ignore indices to consider indices.
     ignore_left_ = std::max(ignore_left_, consider_left_);
diff --git a/cc/base/tiling_data.h b/cc/base/tiling_data.h
index 5e8a4d6..45b763e 100644
--- a/cc/base/tiling_data.h
+++ b/cc/base/tiling_data.h
@@ -76,13 +76,12 @@
     }
 
    protected:
-    explicit BaseIterator(const TilingData* tiling_data);
+    BaseIterator();
     void done() {
       index_x_ = -1;
       index_y_ = -1;
     }
 
-    const TilingData* tiling_data_;
     int index_x_;
     int index_y_;
   };
diff --git a/cc/blink/web_external_bitmap_impl.cc b/cc/blink/web_external_bitmap_impl.cc
index a101079..e2c67e4 100644
--- a/cc/blink/web_external_bitmap_impl.cc
+++ b/cc/blink/web_external_bitmap_impl.cc
@@ -4,18 +4,18 @@
 
 #include "cc/blink/web_external_bitmap_impl.h"
 
-#include "base/memory/shared_memory.h"
+#include "cc/resources/shared_bitmap.h"
 
 namespace cc_blink {
 
 namespace {
 
-SharedMemoryAllocationFunction g_memory_allocator;
+SharedBitmapAllocationFunction g_memory_allocator;
 
 }  // namespace
 
-void SetSharedMemoryAllocationFunction(
-    SharedMemoryAllocationFunction allocator) {
+void SetSharedBitmapAllocationFunction(
+    SharedBitmapAllocationFunction allocator) {
   g_memory_allocator = allocator;
 }
 
@@ -27,10 +27,7 @@
 
 void WebExternalBitmapImpl::setSize(blink::WebSize size) {
   if (size != size_) {
-    size_t byte_size = size.width * size.height * 4;
-    shared_memory_ = g_memory_allocator(byte_size);
-    if (shared_memory_)
-      shared_memory_->Map(byte_size);
+    shared_bitmap_ = g_memory_allocator(gfx::Size(size));
     size_ = size;
   }
 }
@@ -40,7 +37,7 @@
 }
 
 uint8* WebExternalBitmapImpl::pixels() {
-  return static_cast<uint8*>(shared_memory_->memory());
+  return shared_bitmap_->pixels();
 }
 
 }  // namespace cc_blink
diff --git a/cc/blink/web_external_bitmap_impl.h b/cc/blink/web_external_bitmap_impl.h
index 2d2d8ce..6cada7d 100644
--- a/cc/blink/web_external_bitmap_impl.h
+++ b/cc/blink/web_external_bitmap_impl.h
@@ -10,17 +10,18 @@
 #include "cc/blink/cc_blink_export.h"
 #include "third_party/WebKit/public/platform/WebExternalBitmap.h"
 
-namespace base {
-class SharedMemory;
+namespace cc {
+class SharedBitmap;
 }
 
 namespace cc_blink {
 
-typedef scoped_ptr<base::SharedMemory>(*SharedMemoryAllocationFunction)(size_t);
+typedef scoped_ptr<cc::SharedBitmap>(*SharedBitmapAllocationFunction)(
+    const gfx::Size& size);
 
 // Sets the function that this will use to allocate shared memory.
-CC_BLINK_EXPORT void SetSharedMemoryAllocationFunction(
-    SharedMemoryAllocationFunction);
+CC_BLINK_EXPORT void SetSharedBitmapAllocationFunction(
+    SharedBitmapAllocationFunction);
 
 class WebExternalBitmapImpl : public blink::WebExternalBitmap {
  public:
@@ -32,10 +33,10 @@
   void setSize(blink::WebSize size) override;
   uint8* pixels() override;
 
-  base::SharedMemory* shared_memory() { return shared_memory_.get(); }
+  cc::SharedBitmap* shared_bitmap() { return shared_bitmap_.get(); }
 
  private:
-  scoped_ptr<base::SharedMemory> shared_memory_;
+  scoped_ptr<cc::SharedBitmap> shared_bitmap_;
   blink::WebSize size_;
 
   DISALLOW_COPY_AND_ASSIGN(WebExternalBitmapImpl);
diff --git a/cc/blink/web_external_texture_layer_impl.cc b/cc/blink/web_external_texture_layer_impl.cc
index 30e0ce6..8d29aa1 100644
--- a/cc/blink/web_external_texture_layer_impl.cc
+++ b/cc/blink/web_external_texture_layer_impl.cc
@@ -84,7 +84,7 @@
   gpu::Mailbox name;
   name.SetName(client_mailbox.name);
   if (bitmap) {
-    *mailbox = cc::TextureMailbox(bitmap->shared_memory(), bitmap->size());
+    *mailbox = cc::TextureMailbox(bitmap->shared_bitmap(), bitmap->size());
   } else {
     *mailbox =
         cc::TextureMailbox(name, GL_TEXTURE_2D, client_mailbox.syncPoint);
diff --git a/cc/blink/web_image_layer_impl.cc b/cc/blink/web_image_layer_impl.cc
index ee80ca6..afd551a 100644
--- a/cc/blink/web_image_layer_impl.cc
+++ b/cc/blink/web_image_layer_impl.cc
@@ -35,4 +35,11 @@
   }
 }
 
+void WebImageLayerImpl::setNearestNeighbor(bool nearest_neighbor) {
+  if (WebLayerImpl::UsingPictureLayer()) {
+    static_cast<cc::PictureImageLayer*>(layer_->layer())
+        ->SetNearestNeighbor(nearest_neighbor);
+  }
+}
+
 }  // namespace cc_blink
diff --git a/cc/blink/web_image_layer_impl.h b/cc/blink/web_image_layer_impl.h
index e0591aa..48c31ea 100644
--- a/cc/blink/web_image_layer_impl.h
+++ b/cc/blink/web_image_layer_impl.h
@@ -22,6 +22,7 @@
   // blink::WebImageLayer implementation.
   virtual blink::WebLayer* layer();
   virtual void setImageBitmap(const SkBitmap& bitmap);
+  virtual void setNearestNeighbor(bool nearest_neighbor);
 
  private:
   scoped_ptr<WebLayerImpl> layer_;
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index c32fcba..cbea932 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -192,6 +192,8 @@
       'test/fake_ui_resource_layer_tree_host_impl.h',
       'test/fake_video_frame_provider.cc',
       'test/fake_video_frame_provider.h',
+      'test/failure_output_surface.cc',
+      'test/failure_output_surface.h',
       'test/geometry_test_utils.cc',
       'test/geometry_test_utils.h',
       'test/test_in_process_context_provider.cc',
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc
index c00d0b9..03267a8 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -15,6 +15,7 @@
 #include "cc/resources/tile_task_worker_pool.h"
 #include "cc/trees/layer_tree_host_common.h"
 #include "cc/trees/layer_tree_host_impl.h"
+#include "cc/trees/layer_tree_impl.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace cc {
@@ -121,18 +122,6 @@
     return base_client_->GetMaxTilePriorityBin();
   }
 
-  size_t GetMaxTilesForInterestArea() const override {
-    return base_client_->GetMaxTilesForInterestArea();
-  }
-
-  float GetSkewportTargetTimeInSeconds() const override {
-    return base_client_->GetSkewportTargetTimeInSeconds();
-  }
-
-  int GetSkewportExtrapolationLimitInContentPixels() const override {
-    return base_client_->GetSkewportExtrapolationLimitInContentPixels();
-  }
-
   WhichTree GetTree() const override { return base_client_->GetTree(); }
 
   bool RequiresHighResToDraw() const override {
@@ -215,7 +204,15 @@
 
   FixedInvalidationPictureLayerTilingClient client(
       layer, gfx::Rect(layer->content_bounds()));
-  auto tiling_set = PictureLayerTilingSet::Create(&client);
+
+  // In this benchmark, we will create a local tiling set and measure how long
+  // it takes to rasterize content. As such, the actual settings used here don't
+  // really matter.
+  const LayerTreeSettings& settings = layer->layer_tree_impl()->settings();
+  auto tiling_set = PictureLayerTilingSet::Create(
+      &client, settings.max_tiles_for_interest_area,
+      settings.skewport_target_time_in_seconds,
+      settings.skewport_extrapolation_limit_in_content_pixels);
 
   PictureLayerTiling* tiling =
       tiling_set->AddTiling(layer->contents_scale_x(), layer->bounds());
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 066d26c..6793d12 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -1268,8 +1268,6 @@
 
   DCHECK(this != page_scale_layer);
   DCHECK(scrollbar_clip_layer);
-  DCHECK(this != layer_tree_impl()->InnerViewportScrollLayer() ||
-         IsContainerForFixedPositionLayers());
   gfx::RectF clip_rect(gfx::PointF(),
                        scrollbar_clip_layer->BoundsForScrolling());
 
diff --git a/cc/layers/picture_image_layer.cc b/cc/layers/picture_image_layer.cc
index 5d76618..cebc8b7 100644
--- a/cc/layers/picture_image_layer.cc
+++ b/cc/layers/picture_image_layer.cc
@@ -21,7 +21,7 @@
 
 scoped_ptr<LayerImpl> PictureImageLayer::CreateLayerImpl(
     LayerTreeImpl* tree_impl) {
-  return PictureImageLayerImpl::Create(tree_impl, id());
+  return PictureImageLayerImpl::Create(tree_impl, id(), is_mask());
 }
 
 bool PictureImageLayer::HasDrawableContent() const {
diff --git a/cc/layers/picture_image_layer_impl.cc b/cc/layers/picture_image_layer_impl.cc
index a72ab01..cf09654 100644
--- a/cc/layers/picture_image_layer_impl.cc
+++ b/cc/layers/picture_image_layer_impl.cc
@@ -11,8 +11,10 @@
 
 namespace cc {
 
-PictureImageLayerImpl::PictureImageLayerImpl(LayerTreeImpl* tree_impl, int id)
-    : PictureLayerImpl(tree_impl, id) {
+PictureImageLayerImpl::PictureImageLayerImpl(LayerTreeImpl* tree_impl,
+                                             int id,
+                                             bool is_mask)
+    : PictureLayerImpl(tree_impl, id, is_mask) {
 }
 
 PictureImageLayerImpl::~PictureImageLayerImpl() {
@@ -24,7 +26,7 @@
 
 scoped_ptr<LayerImpl> PictureImageLayerImpl::CreateLayerImpl(
     LayerTreeImpl* tree_impl) {
-  return PictureImageLayerImpl::Create(tree_impl, id());
+  return PictureImageLayerImpl::Create(tree_impl, id(), is_mask_);
 }
 
 void PictureImageLayerImpl::GetDebugBorderProperties(
diff --git a/cc/layers/picture_image_layer_impl.h b/cc/layers/picture_image_layer_impl.h
index 7a363a1..f478951 100644
--- a/cc/layers/picture_image_layer_impl.h
+++ b/cc/layers/picture_image_layer_impl.h
@@ -12,8 +12,9 @@
 class CC_EXPORT PictureImageLayerImpl : public PictureLayerImpl {
  public:
   static scoped_ptr<PictureImageLayerImpl> Create(LayerTreeImpl* tree_impl,
-                                                  int id) {
-    return make_scoped_ptr(new PictureImageLayerImpl(tree_impl, id));
+                                                  int id,
+                                                  bool is_mask) {
+    return make_scoped_ptr(new PictureImageLayerImpl(tree_impl, id, is_mask));
   }
   ~PictureImageLayerImpl() override;
 
@@ -22,7 +23,7 @@
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
 
  protected:
-  PictureImageLayerImpl(LayerTreeImpl* tree_impl, int id);
+  PictureImageLayerImpl(LayerTreeImpl* tree_impl, int id, bool is_mask);
 
   bool ShouldAdjustRasterScale() const override;
   void RecalculateRasterScales() override;
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc
index 1c766ba..dbdcf6a 100644
--- a/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -22,8 +22,7 @@
 class TestablePictureImageLayerImpl : public PictureImageLayerImpl {
  public:
   TestablePictureImageLayerImpl(LayerTreeImpl* tree_impl, int id)
-      : PictureImageLayerImpl(tree_impl, id) {
-  }
+      : PictureImageLayerImpl(tree_impl, id, false) {}
   using PictureLayerImpl::UpdateIdealScales;
   using PictureLayerImpl::MaximumTilingContentsScale;
   using PictureLayerImpl::DoPostCommitInitializationIfNeeded;
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index 55241d0..48f3f73 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -24,7 +24,8 @@
       instrumentation_object_tracker_(id()),
       update_source_frame_number_(-1),
       can_use_lcd_text_for_update_(true),
-      is_mask_(false) {
+      is_mask_(false),
+      nearest_neighbor_(false) {
 }
 
 PictureLayer::PictureLayer(ContentLayerClient* client,
@@ -37,12 +38,14 @@
 }
 
 scoped_ptr<LayerImpl> PictureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
-  return PictureLayerImpl::Create(tree_impl, id());
+  return PictureLayerImpl::Create(tree_impl, id(), is_mask_);
 }
 
 void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
   Layer::PushPropertiesTo(base_layer);
   PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
+  // TODO(danakj): Make is_mask_ a constructor parameter for PictureLayer.
+  DCHECK_EQ(layer_impl->is_mask_, is_mask_);
 
   int source_frame_number = layer_tree_host()->source_frame_number();
   gfx::Size impl_bounds = layer_impl->bounds();
@@ -63,17 +66,16 @@
     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(&recording_invalidation_);
-  layer_impl->set_is_mask(is_mask_);
+  layer_impl->SetNearestNeighbor(nearest_neighbor_);
+
   scoped_refptr<RasterSource> raster_source =
       recording_source_->CreateRasterSource();
   raster_source->SetBackgoundColor(SafeOpaqueBackgroundColor());
   raster_source->SetRequiresClear(!contents_opaque() &&
                                   !client_->FillsBoundsCompletely());
-  layer_impl->UpdateRasterSource(raster_source);
+  layer_impl->UpdateRasterSource(raster_source, &recording_invalidation_,
+                                 nullptr);
+  DCHECK(recording_invalidation_.IsEmpty());
 }
 
 void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
@@ -206,6 +208,14 @@
   UpdateDrawsContent(HasDrawableContent());
 }
 
+void PictureLayer::SetNearestNeighbor(bool nearest_neighbor) {
+  if (nearest_neighbor_ == nearest_neighbor)
+    return;
+
+  nearest_neighbor_ = nearest_neighbor;
+  SetNeedsCommit();
+}
+
 bool PictureLayer::HasDrawableContent() const {
   return client_ && Layer::HasDrawableContent();
 }
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index 01a37a3..648d1c9 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -23,6 +23,8 @@
 
   void ClearClient();
 
+  void SetNearestNeighbor(bool nearest_neighbor);
+
   // Layer interface.
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
   void SetLayerTreeHost(LayerTreeHost* host) override;
@@ -50,9 +52,12 @@
   ~PictureLayer() override;
 
   bool HasDrawableContent() const override;
-  bool UpdateCanUseLCDText();
+
+  bool is_mask() const { return is_mask_; }
 
  private:
+  bool UpdateCanUseLCDText();
+
   ContentLayerClient* client_;
   scoped_ptr<RecordingSource> recording_source_;
   devtools_instrumentation::
@@ -66,6 +71,7 @@
   int update_source_frame_number_;
   bool can_use_lcd_text_for_update_;
   bool is_mask_;
+  bool nearest_neighbor_;
 
   DISALLOW_COPY_AND_ASSIGN(PictureLayer);
 };
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 54cfac8..392450a 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -63,9 +63,13 @@
 PictureLayerImpl::Pair::~Pair() {
 }
 
-PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
+PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl,
+                                   int id,
+                                   bool is_mask)
     : LayerImpl(tree_impl, id),
       twin_layer_(nullptr),
+      tilings_(CreatePictureLayerTilingSet()),
+      // TODO(danakj): Can this be null to start?
       raster_source_(PicturePileImpl::Create()),
       ideal_page_scale_(0.f),
       ideal_device_scale_(0.f),
@@ -81,7 +85,8 @@
       needs_post_commit_initialization_(true),
       should_update_tile_priorities_(false),
       only_used_low_res_last_append_quads_(false),
-      is_mask_(false) {
+      is_mask_(is_mask),
+      nearest_neighbor_(false) {
   layer_tree_impl()->RegisterPictureLayerImpl(this);
 }
 
@@ -95,8 +100,10 @@
     TreePriority tree_priority) {
   if (!tilings_)
     return make_scoped_ptr(new TilingSetEvictionQueue());
-  return make_scoped_ptr(
-      new TilingSetEvictionQueue(tilings_.get(), tree_priority));
+  bool skip_shared_out_of_order_tiles =
+      GetPendingOrActiveTwinLayer() != nullptr;
+  return make_scoped_ptr(new TilingSetEvictionQueue(
+      tilings_.get(), tree_priority, skip_shared_out_of_order_tiles));
 }
 
 scoped_ptr<TilingSetRasterQueue> PictureLayerImpl::CreateRasterQueue(
@@ -113,7 +120,7 @@
 
 scoped_ptr<LayerImpl> PictureLayerImpl::CreateLayerImpl(
     LayerTreeImpl* tree_impl) {
-  return PictureLayerImpl::Create(tree_impl, id());
+  return PictureLayerImpl::Create(tree_impl, id(), is_mask_);
 }
 
 void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
@@ -121,6 +128,7 @@
   // a descendant of an opacity 0 layer).
   DoPostCommitInitializationIfNeeded();
   PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
+  DCHECK_EQ(layer_impl->is_mask_, is_mask_);
 
   LayerImpl::PushPropertiesTo(base_layer);
 
@@ -134,54 +142,39 @@
   twin_layer_ = layer_impl;
   layer_impl->twin_layer_ = this;
 
-  layer_impl->set_is_mask(is_mask_);
-  layer_impl->UpdateRasterSource(raster_source_);
+  layer_impl->SetNearestNeighbor(nearest_neighbor_);
 
+  // Solid color layers have no tilings.
   DCHECK_IMPLIES(raster_source_->IsSolidColor(), tilings_->num_tilings() == 0);
-  // Tilings would be expensive to push, so we swap.
-  layer_impl->tilings_.swap(tilings_);
-  layer_impl->tilings_->SetClient(layer_impl);
-  if (tilings_)
-    tilings_->SetClient(this);
+  // The pending tree should only have a high res (and possibly low res) tiling.
+  DCHECK_LE(tilings_->num_tilings(),
+            layer_tree_impl()->create_low_res_tiling() ? 2u : 1u);
 
-  // Ensure that the recycle tree doesn't have any unshared tiles.
-  if (tilings_ && raster_source_->IsSolidColor())
-    tilings_->RemoveAllTilings();
+  layer_impl->UpdateRasterSource(raster_source_, &invalidation_,
+                                 tilings_.get());
+  DCHECK(invalidation_.IsEmpty());
 
-  // Remove invalidated tiles from what will become a recycle tree.
-  if (tilings_)
-    tilings_->RemoveTilesInRegion(invalidation_);
+  // After syncing a solid color layer, the active layer has no tilings.
+  DCHECK_IMPLIES(raster_source_->IsSolidColor(),
+                 layer_impl->tilings_->num_tilings() == 0);
 
   layer_impl->raster_page_scale_ = raster_page_scale_;
   layer_impl->raster_device_scale_ = raster_device_scale_;
   layer_impl->raster_source_scale_ = raster_source_scale_;
   layer_impl->raster_contents_scale_ = raster_contents_scale_;
   layer_impl->low_res_raster_contents_scale_ = low_res_raster_contents_scale_;
-  layer_impl->needs_post_commit_initialization_ = false;
 
-  // The invalidation on this soon-to-be-recycled layer must be cleared to
-  // mirror clearing the invalidation in PictureLayer's version of this function
-  // in case push properties is skipped.
-  layer_impl->invalidation_.Swap(&invalidation_);
-  invalidation_.Clear();
+  layer_impl->SanityCheckTilingState();
+
+  layer_impl->needs_post_commit_initialization_ = false;
   needs_post_commit_initialization_ = true;
 
   // We always need to push properties.
   // See http://crbug.com/303943
+  // TODO(danakj): Stop always pushing properties since we don't swap tilings.
   needs_push_properties_ = true;
 }
 
-void PictureLayerImpl::UpdateRasterSource(
-    scoped_refptr<RasterSource> raster_source) {
-  bool could_have_tilings = CanHaveTilings();
-  raster_source_.swap(raster_source);
-
-  // Need to call UpdateTiles again if CanHaveTilings changed.
-  if (could_have_tilings != CanHaveTilings()) {
-    layer_tree_impl()->set_needs_update_draw_properties();
-  }
-}
-
 void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
                                    const Occlusion& occlusion_in_content_space,
                                    AppendQuadsData* append_quads_data) {
@@ -251,8 +244,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, raster_source_);
+                 visible_geometry_rect, texture_rect, texture_size,
+                 nearest_neighbor_, RGBA_8888, quad_content_rect,
+                 max_contents_scale, raster_source_);
     return;
   }
 
@@ -364,7 +358,8 @@
                        draw_info.get_resource_id(),
                        texture_rect,
                        iter.texture_size(),
-                       draw_info.contents_swizzled());
+                       draw_info.contents_swizzled(),
+                       nearest_neighbor_);
           has_draw_quad = true;
           break;
         }
@@ -386,8 +381,8 @@
               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(),
-                       raster_source_);
+                       nearest_neighbor_, format, iter->content_rect(),
+                       iter->contents_scale(), raster_source_);
           has_draw_quad = true;
           break;
         }
@@ -485,8 +480,6 @@
 
   UpdateIdealScales();
 
-  DCHECK_IMPLIES(tilings_->num_tilings() == 0, raster_contents_scale_ == 0.f)
-      << "A layer with no tilings shouldn't have valid raster scales";
   if (!raster_contents_scale_ || ShouldAdjustRasterScale()) {
     RecalculateRasterScales();
     AddTilingsForRasterScale();
@@ -581,6 +574,44 @@
   return twin_layer_;
 }
 
+void PictureLayerImpl::UpdateRasterSource(
+    scoped_refptr<RasterSource> raster_source,
+    Region* new_invalidation,
+    const PictureLayerTilingSet* pending_set) {
+  // 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(!raster_source->GetSize().IsEmpty(),
+                 bounds() == raster_source->GetSize())
+      << " bounds " << bounds().ToString() << " pile "
+      << raster_source->GetSize().ToString();
+
+  bool could_have_tilings = CanHaveTilings();
+  raster_source_.swap(raster_source);
+
+  // The |new_invalidation| must be cleared before updating tilings since they
+  // access the invalidation through the PictureLayerTilingClient interface.
+  invalidation_.Clear();
+  invalidation_.Swap(new_invalidation);
+
+  bool can_have_tilings = CanHaveTilings();
+
+  // Need to call UpdateTiles again if CanHaveTilings changed.
+  if (could_have_tilings != can_have_tilings)
+    layer_tree_impl()->set_needs_update_draw_properties();
+
+  if (!can_have_tilings) {
+    RemoveAllTilings();
+    return;
+  }
+
+  // We could do this after doing UpdateTiles, which would avoid doing this for
+  // tilings that are going to disappear on the pending tree (if scale changed).
+  // But that would also be more complicated, so we just do it here for now.
+  tilings_->UpdateTilingsToCurrentRasterSource(
+      raster_source_.get(), pending_set, raster_source_->GetSize(),
+      invalidation_, MinimumContentsScale());
+}
+
 void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) {
   if (layer_tree_impl()->IsActiveTree()) {
     gfx::RectF layer_damage_rect =
@@ -600,9 +631,10 @@
 }
 
 void PictureLayerImpl::ReleaseResources() {
+  // Recreate tilings with new settings, since some of those might change when
+  // we release resources. If tilings_ is null, then leave it as null.
   if (tilings_)
-    RemoveAllTilings();
-
+    tilings_ = CreatePictureLayerTilingSet();
   ResetRasterScale();
 
   // To avoid an edge case after lost context where the tree is up to date but
@@ -637,6 +669,8 @@
 const Region* PictureLayerImpl::GetPendingInvalidation() {
   if (layer_tree_impl()->IsPendingTree())
     return &invalidation_;
+  if (layer_tree_impl()->IsRecycleTree())
+    return nullptr;
   DCHECK(layer_tree_impl()->IsActiveTree());
   if (PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer())
     return &twin_layer->invalidation_;
@@ -648,9 +682,6 @@
   PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer();
   if (!twin_layer)
     return nullptr;
-  // TODO(danakj): Remove this when no longer swapping tilings.
-  if (!twin_layer->tilings_)
-    return nullptr;
   return twin_layer->tilings_->FindTilingWithScale(tiling->contents_scale());
 }
 
@@ -668,22 +699,6 @@
   return TilePriority::NOW;
 }
 
-size_t PictureLayerImpl::GetMaxTilesForInterestArea() const {
-  return layer_tree_impl()->settings().max_tiles_for_interest_area;
-}
-
-float PictureLayerImpl::GetSkewportTargetTimeInSeconds() const {
-  return layer_tree_impl()->use_gpu_rasterization()
-             ? 0.f
-             : layer_tree_impl()->settings().skewport_target_time_in_seconds;
-}
-
-int PictureLayerImpl::GetSkewportExtrapolationLimitInContentPixels() const {
-  return layer_tree_impl()
-      ->settings()
-      .skewport_extrapolation_limit_in_content_pixels;
-}
-
 bool PictureLayerImpl::RequiresHighResToDraw() const {
   return layer_tree_impl()->RequiresHighResToDraw();
 }
@@ -765,69 +780,15 @@
   return gfx::Size(tile_width, tile_height);
 }
 
-void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) {
-  DCHECK(!other->needs_post_commit_initialization_);
-  DCHECK(other->tilings_);
-
-  if (!DrawsContent()) {
-    RemoveAllTilings();
-    return;
-  }
-
-  raster_page_scale_ = other->raster_page_scale_;
-  raster_device_scale_ = other->raster_device_scale_;
-  raster_source_scale_ = other->raster_source_scale_;
-  raster_contents_scale_ = other->raster_contents_scale_;
-  low_res_raster_contents_scale_ = other->low_res_raster_contents_scale_;
-
-  bool synced_high_res_tiling = false;
-  if (CanHaveTilings()) {
-    synced_high_res_tiling = tilings_->SyncTilings(
-        *other->tilings_, raster_source_->GetSize(), invalidation_,
-        MinimumContentsScale(), raster_source_.get());
-  } else {
-    RemoveAllTilings();
-  }
-
-  // If our MinimumContentsScale has changed to prevent the twin's high res
-  // tiling from being synced, we should reset the raster scale and let it be
-  // recalculated (1) again. This can happen if our bounds shrink to the point
-  // where min contents scale grows.
-  // (1) - TODO(vmpstr) Instead of hoping that this will be recalculated, we
-  // should refactor this code a little bit and actually recalculate this.
-  // However, this is a larger undertaking, so this will work for now.
-  if (!synced_high_res_tiling)
-    ResetRasterScale();
-  else
-    SanityCheckTilingState();
-}
-
-void PictureLayerImpl::SyncTiling(
-    const PictureLayerTiling* tiling) {
-  if (!tilings_)
-    return;
-  if (!CanHaveTilingWithScale(tiling->contents_scale()))
-    return;
-  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
-  // need update draw properties, then its transforms are up to date and
-  // we can create tiles for this tiling immediately.
-  if (!layer_tree_impl()->needs_update_draw_properties() &&
-      should_update_tile_priorities_) {
-    // TODO(danakj): Add a DCHECK() that we are not using occlusion tracking
-    // when we stop using the pending tree in the browser compositor. If we want
-    // to support occlusion tracking here, we need to dirty the draw properties
-    // or save occlusion as a draw property.
-    UpdateTilePriorities(Occlusion());
-  }
-}
-
 void PictureLayerImpl::GetContentsResourceId(
     ResourceProvider::ResourceId* resource_id,
     gfx::Size* resource_size) const {
-  DCHECK_EQ(bounds().ToString(), raster_source_->GetSize().ToString());
+  // 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(!raster_source_->GetSize().IsEmpty(),
+                 bounds() == raster_source_->GetSize())
+      << " bounds " << bounds().ToString() << " pile "
+      << raster_source_->GetSize().ToString();
   gfx::Rect content_rect(bounds());
   PictureLayerTilingSet::CoverageIterator iter(
       tilings_.get(), 1.f, content_rect, ideal_contents_scale_);
@@ -854,21 +815,18 @@
   *resource_size = iter.texture_size();
 }
 
+void PictureLayerImpl::SetNearestNeighbor(bool nearest_neighbor) {
+  if (nearest_neighbor_ == nearest_neighbor)
+    return;
+
+  nearest_neighbor_ = nearest_neighbor;
+  NoteLayerPropertyChanged();
+}
+
 void PictureLayerImpl::DoPostCommitInitialization() {
+  // TODO(danakj): Remove this.
   DCHECK(needs_post_commit_initialization_);
   DCHECK(layer_tree_impl()->IsPendingTree());
-
-  if (!tilings_)
-    tilings_ = PictureLayerTilingSet::Create(this);
-
-  PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer();
-  if (twin_layer) {
-    // If the twin has never been pushed to, do not sync from it.
-    // This can happen if this function is called during activation.
-    if (!twin_layer->needs_post_commit_initialization_)
-      SyncFromActiveLayer(twin_layer);
-  }
-
   needs_post_commit_initialization_ = false;
 }
 
@@ -881,9 +839,6 @@
 
   DCHECK(raster_source_->HasRecordings());
 
-  if (PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer())
-    twin_layer->SyncTiling(tiling);
-
   return tiling;
 }
 
@@ -929,6 +884,12 @@
   // Make sure we always have one high-res (even if high == low).
   high_res->set_resolution(HIGH_RESOLUTION);
 
+  if (layer_tree_impl()->IsPendingTree()) {
+    // On the pending tree, drop any tilings that are non-ideal since we don't
+    // need them to activate anyway.
+    tilings_->RemoveNonIdealTilings();
+  }
+
   SanityCheckTilingState();
 }
 
@@ -1113,9 +1074,6 @@
                            layer_tree_impl()->create_low_res_tiling(), twin_set,
                            recycled_twin_set);
 
-  if (twin_set && twin_set->num_tilings() == 0)
-    twin->ResetRasterScale();
-
   if (recycled_twin_set && recycled_twin_set->num_tilings() == 0)
     recycled_twin->ResetRasterScale();
 
@@ -1158,6 +1116,8 @@
     return false;
   if (!raster_source_->HasRecordings())
     return false;
+  // If the |raster_source_| has a recording it should have non-empty bounds.
+  DCHECK(!raster_source_->GetSize().IsEmpty());
   return true;
 }
 
@@ -1196,6 +1156,17 @@
   return std::max(max_contents_scale, MinimumContentsScale());
 }
 
+scoped_ptr<PictureLayerTilingSet>
+PictureLayerImpl::CreatePictureLayerTilingSet() {
+  const LayerTreeSettings& settings = layer_tree_impl()->settings();
+  return PictureLayerTilingSet::Create(
+      this, settings.max_tiles_for_interest_area,
+      layer_tree_impl()->use_gpu_rasterization()
+          ? 0.f
+          : settings.skewport_target_time_in_seconds,
+      settings.skewport_extrapolation_limit_in_content_pixels);
+}
+
 void PictureLayerImpl::UpdateIdealScales() {
   DCHECK(CanHaveTilings());
 
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index ddf928b..f17743d 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -39,8 +39,10 @@
     PictureLayerImpl* pending;
   };
 
-  static scoped_ptr<PictureLayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
-    return make_scoped_ptr(new PictureLayerImpl(tree_impl, id));
+  static scoped_ptr<PictureLayerImpl> Create(LayerTreeImpl* tree_impl,
+                                             int id,
+                                             bool is_mask) {
+    return make_scoped_ptr(new PictureLayerImpl(tree_impl, id, is_mask));
   }
   ~PictureLayerImpl() override;
 
@@ -73,9 +75,6 @@
   PictureLayerTiling* GetRecycledTwinTiling(
       const PictureLayerTiling* tiling) override;
   TilePriority::PriorityBin GetMaxTilePriorityBin() const override;
-  size_t GetMaxTilesForInterestArea() const override;
-  float GetSkewportTargetTimeInSeconds() const override;
-  int GetSkewportExtrapolationLimitInContentPixels() const override;
   WhichTree GetTree() const override;
   bool RequiresHighResToDraw() const override;
 
@@ -85,7 +84,8 @@
   // Mask-related functions.
   void GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
                              gfx::Size* resource_size) const override;
-  void set_is_mask(bool is_mask) { is_mask_ = is_mask; }
+
+  void SetNearestNeighbor(bool nearest_neighbor);
 
   size_t GPUMemoryUsageInBytes() const override;
 
@@ -108,10 +108,9 @@
   friend class LayerRasterTileIterator;
   using TileRequirementCheck = bool (PictureLayerTiling::*)(const Tile*) const;
 
-  PictureLayerImpl(LayerTreeImpl* tree_impl, int id);
+  PictureLayerImpl(LayerTreeImpl* tree_impl, int id, bool is_mask);
   PictureLayerTiling* AddTiling(float contents_scale);
   void RemoveAllTilings();
-  void SyncFromActiveLayer(const PictureLayerImpl* other);
   void AddTilingsForRasterScale();
   void UpdateTilePriorities(const Occlusion& occlusion_in_content_space);
   virtual bool ShouldAdjustRasterScale() const;
@@ -122,7 +121,9 @@
   void ResetRasterScale();
   gfx::Rect GetViewportForTilePriorityInContentSpace() const;
   PictureLayerImpl* GetRecycledTwinLayer() const;
-  void UpdateRasterSource(scoped_refptr<RasterSource> raster_source);
+  void UpdateRasterSource(scoped_refptr<RasterSource> raster_source,
+                          Region* new_invalidation,
+                          const PictureLayerTilingSet* pending_set);
 
   void DoPostCommitInitializationIfNeeded() {
     if (needs_post_commit_initialization_)
@@ -146,6 +147,7 @@
 
   virtual void UpdateIdealScales();
   float MaximumTilingContentsScale() const;
+  scoped_ptr<PictureLayerTilingSet> CreatePictureLayerTilingSet();
 
   PictureLayerImpl* twin_layer_;
 
@@ -171,7 +173,9 @@
   // after a CalculateContentsScale/ManageTilings.
   bool should_update_tile_priorities_;
   bool only_used_low_res_last_append_quads_;
-  bool is_mask_;
+  const bool is_mask_;
+
+  bool nearest_neighbor_;
 
   // Any draw properties derived from |transform|, |viewport|, and |clip|
   // parameters in LayerTreeHostImpl::SetExternalDrawConstraints are not valid
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 90a36f7..7c7c899 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -34,6 +34,18 @@
 namespace cc {
 namespace {
 
+#define EXPECT_BOTH_EQ(expression, x)         \
+  do {                                        \
+    EXPECT_EQ(x, pending_layer_->expression); \
+    EXPECT_EQ(x, active_layer_->expression);  \
+  } while (false)
+
+#define EXPECT_BOTH_NE(expression, x)         \
+  do {                                        \
+    EXPECT_NE(x, pending_layer_->expression); \
+    EXPECT_NE(x, active_layer_->expression);  \
+  } while (false)
+
 class MockCanvas : public SkCanvas {
  public:
   explicit MockCanvas(int w, int h) : SkCanvas(w, h) {}
@@ -58,15 +70,21 @@
   PictureLayerImplTest()
       : proxy_(base::MessageLoopProxy::current()),
         host_impl_(LowResTilingsSettings(), &proxy_, &shared_bitmap_manager_),
+        root_id_(6),
         id_(7),
         pending_layer_(nullptr),
         old_pending_layer_(nullptr),
-        active_layer_(nullptr) {}
+        active_layer_(nullptr) {
+    host_impl_.SetViewportSize(gfx::Size(10000, 10000));
+  }
 
   explicit PictureLayerImplTest(const LayerTreeSettings& settings)
       : proxy_(base::MessageLoopProxy::current()),
         host_impl_(settings, &proxy_, &shared_bitmap_manager_),
-        id_(7) {}
+        root_id_(6),
+        id_(7) {
+    host_impl_.SetViewportSize(gfx::Size(10000, 10000));
+  }
 
   virtual ~PictureLayerImplTest() {
   }
@@ -88,6 +106,18 @@
     SetupTrees(pending_pile, active_pile);
   }
 
+  void SetupDefaultTreesWithInvalidation(const gfx::Size& layer_bounds,
+                                         const Region& invalidation) {
+    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);
+
+    SetupTreesWithInvalidation(pending_pile, active_pile, invalidation);
+  }
+
   void ActivateTree() {
     host_impl_.ActivateSyncTree();
     CHECK(!host_impl_.pending_tree());
@@ -96,13 +126,22 @@
     pending_layer_ = nullptr;
     active_layer_ = static_cast<FakePictureLayerImpl*>(
         host_impl_.active_tree()->LayerById(id_));
+
+    host_impl_.active_tree()->UpdateDrawProperties();
   }
 
   void SetupDefaultTreesWithFixedTileSize(const gfx::Size& layer_bounds,
-                                          const gfx::Size& tile_size) {
-    SetupDefaultTrees(layer_bounds);
-    pending_layer_->set_fixed_tile_size(tile_size);
-    active_layer_->set_fixed_tile_size(tile_size);
+                                          const gfx::Size& tile_size,
+                                          const Region& invalidation) {
+    gfx::Size pile_tile_size(100, 100);
+
+    scoped_refptr<FakePicturePileImpl> pending_pile =
+        FakePicturePileImpl::CreateFilledPile(pile_tile_size, layer_bounds);
+    scoped_refptr<FakePicturePileImpl> active_pile =
+        FakePicturePileImpl::CreateFilledPile(pile_tile_size, layer_bounds);
+
+    SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size,
+                                invalidation);
   }
 
   void SetupTrees(
@@ -110,54 +149,80 @@
       scoped_refptr<PicturePileImpl> active_pile) {
     SetupPendingTree(active_pile);
     ActivateTree();
-    SetupPendingTree(pending_pile);
+    SetupPendingTreeInternal(pending_pile, gfx::Size(), Region());
   }
 
-  void CreateHighLowResAndSetAllTilesVisible() {
-    // Active layer must get updated first so pending layer can share from it.
-    active_layer_->CreateDefaultTilingsAndTiles();
-    active_layer_->SetAllTilesVisible();
-    pending_layer_->CreateDefaultTilingsAndTiles();
-    pending_layer_->SetAllTilesVisible();
+  void SetupTreesWithInvalidation(scoped_refptr<PicturePileImpl> pending_pile,
+                                  scoped_refptr<PicturePileImpl> active_pile,
+                                  const Region& pending_invalidation) {
+    SetupPendingTreeInternal(active_pile, gfx::Size(), Region());
+    ActivateTree();
+    SetupPendingTreeInternal(pending_pile, gfx::Size(), pending_invalidation);
   }
 
-  void AddDefaultTilingsWithInvalidation(const Region& invalidation) {
-    active_layer_->AddTiling(2.3f);
-    active_layer_->AddTiling(1.0f);
-    active_layer_->AddTiling(0.5f);
-    for (size_t i = 0; i < active_layer_->tilings()->num_tilings(); ++i)
-      active_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
-    pending_layer_->set_invalidation(invalidation);
-    for (size_t i = 0; i < pending_layer_->tilings()->num_tilings(); ++i)
-      pending_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
+  void SetupTreesWithFixedTileSize(scoped_refptr<PicturePileImpl> pending_pile,
+                                   scoped_refptr<PicturePileImpl> active_pile,
+                                   const gfx::Size& tile_size,
+                                   const Region& pending_invalidation) {
+    SetupPendingTreeInternal(active_pile, tile_size, Region());
+    ActivateTree();
+    SetupPendingTreeInternal(pending_pile, tile_size, pending_invalidation);
   }
 
   void SetupPendingTree(scoped_refptr<RasterSource> raster_source) {
+    SetupPendingTreeInternal(raster_source, gfx::Size(), Region());
+  }
+
+  void SetupPendingTreeWithInvalidation(
+      scoped_refptr<RasterSource> raster_source,
+      const Region& invalidation) {
+    SetupPendingTreeInternal(raster_source, gfx::Size(), invalidation);
+  }
+
+  void SetupPendingTreeWithFixedTileSize(
+      scoped_refptr<RasterSource> raster_source,
+      const gfx::Size& tile_size,
+      const Region& invalidation) {
+    SetupPendingTreeInternal(raster_source, tile_size, invalidation);
+  }
+
+  void SetupPendingTreeInternal(scoped_refptr<RasterSource> raster_source,
+                                const gfx::Size& tile_size,
+                                const Region& invalidation) {
     host_impl_.CreatePendingTree();
     host_impl_.pending_tree()->PushPageScaleFromMainThread(1.f, 0.25f, 100.f);
     LayerTreeImpl* pending_tree = host_impl_.pending_tree();
 
-    // Steal from the recycled tree.
-    scoped_ptr<LayerImpl> old_pending_root = pending_tree->DetachLayerTree();
-    DCHECK_IMPLIES(old_pending_root, old_pending_root->id() == id_);
-
+    // Steal from the recycled tree if possible.
+    scoped_ptr<LayerImpl> pending_root = pending_tree->DetachLayerTree();
     scoped_ptr<FakePictureLayerImpl> pending_layer;
-    if (old_pending_root) {
-      pending_layer.reset(
-          static_cast<FakePictureLayerImpl*>(old_pending_root.release()));
-      pending_layer->SetRasterSource(raster_source);
-    } else {
-      pending_layer = FakePictureLayerImpl::CreateWithRasterSource(
-          pending_tree, id_, raster_source);
+    DCHECK_IMPLIES(pending_root, pending_root->id() == root_id_);
+    if (!pending_root) {
+      pending_root = LayerImpl::Create(pending_tree, root_id_);
+      pending_layer = FakePictureLayerImpl::Create(pending_tree, id_);
+      if (!tile_size.IsEmpty())
+        pending_layer->set_fixed_tile_size(tile_size);
       pending_layer->SetDrawsContent(true);
+    } else {
+      pending_layer.reset(static_cast<FakePictureLayerImpl*>(
+          pending_root->RemoveChild(pending_root->children()[0]).release()));
+      if (!tile_size.IsEmpty())
+        pending_layer->set_fixed_tile_size(tile_size);
     }
     // The bounds() just mirror the pile size.
-    pending_layer->SetBounds(pending_layer->raster_source()->GetSize());
-    pending_tree->SetRootLayer(pending_layer.Pass());
+    pending_layer->SetBounds(raster_source->GetSize());
+    pending_layer->SetContentBounds(raster_source->GetSize());
+    pending_layer->SetRasterSourceOnPending(raster_source, invalidation);
+
+    pending_root->AddChild(pending_layer.Pass());
+    pending_tree->SetRootLayer(pending_root.Pass());
 
     pending_layer_ = static_cast<FakePictureLayerImpl*>(
         host_impl_.pending_tree()->LayerById(id_));
     pending_layer_->DoPostCommitInitializationIfNeeded();
+
+    // Add tilings/tiles for the layer.
+    host_impl_.pending_tree()->UpdateDrawProperties();
   }
 
   void SetupDrawPropertiesAndUpdateTiles(FakePictureLayerImpl* layer,
@@ -213,6 +278,10 @@
   void ResetTilingsAndRasterScales() {
     pending_layer_->ReleaseResources();
     active_layer_->ReleaseResources();
+    if (pending_layer_)
+      EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+    if (active_layer_)
+      EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
   }
 
   void AssertAllTilesRequired(PictureLayerTiling* tiling) {
@@ -230,60 +299,12 @@
   }
 
  protected:
-  void TestTileGridAlignmentCommon() {
-    // Layer to span 4 raster tiles in x and in y
-    ImplSidePaintingSettings settings;
-    gfx::Size layer_size(
-        settings.default_tile_size.width() * 7 / 2,
-        settings.default_tile_size.height() * 7 / 2);
-
-    scoped_refptr<FakePicturePileImpl> pending_pile =
-        FakePicturePileImpl::CreateFilledPile(layer_size, layer_size);
-    scoped_refptr<FakePicturePileImpl> active_pile =
-        FakePicturePileImpl::CreateFilledPile(layer_size, layer_size);
-
-    SetupTrees(pending_pile, active_pile);
-
-    SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
-
-    // Add 1x1 rects at the centers of each tile, then re-record pile contents
-    active_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
-    std::vector<Tile*> tiles =
-        active_layer_->tilings()->tiling_at(0)->AllTilesForTesting();
-    EXPECT_EQ(16u, tiles.size());
-    std::vector<SkRect> rects;
-    std::vector<Tile*>::const_iterator tile_iter;
-    for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
-      gfx::Point tile_center = (*tile_iter)->content_rect().CenterPoint();
-      gfx::Rect rect(tile_center.x(), tile_center.y(), 1, 1);
-      active_pile->add_draw_rect(rect);
-      rects.push_back(SkRect::MakeXYWH(rect.x(), rect.y(), 1, 1));
-    }
-    // Force re-record with newly injected content
-    active_pile->RemoveRecordingAt(0, 0);
-    active_pile->AddRecordingAt(0, 0);
-
-    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->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
-      // neighboring tiles which indicates that the tile grid embedded in
-      // SkPicture is perfectly aligned with the compositor's tiles.
-      EXPECT_EQ(1u, mock_canvas.rects_.size());
-      EXPECT_EQ(*rect_iter, mock_canvas.rects_[0]);
-      rect_iter++;
-    }
-  }
-
   void TestQuadsForSolidColor(bool test_for_solid);
 
   FakeImplProxy proxy_;
   TestSharedBitmapManager shared_bitmap_manager_;
   FakeLayerTreeHostImpl host_impl_;
+  int root_id_;
   int id_;
   FakePictureLayerImpl* pending_layer_;
   FakePictureLayerImpl* old_pending_layer_;
@@ -293,14 +314,56 @@
   DISALLOW_COPY_AND_ASSIGN(PictureLayerImplTest);
 };
 
-TEST_F(PictureLayerImplTest, TileGridAlignment) {
-  host_impl_.SetDeviceScaleFactor(1.f);
-  TestTileGridAlignmentCommon();
-}
+class NoLowResPictureLayerImplTest : public PictureLayerImplTest {
+ public:
+  NoLowResPictureLayerImplTest()
+      : PictureLayerImplTest(NoLowResTilingsSettings()) {}
+};
 
-TEST_F(PictureLayerImplTest, TileGridAlignmentHiDPI) {
-  host_impl_.SetDeviceScaleFactor(2.f);
-  TestTileGridAlignmentCommon();
+TEST_F(PictureLayerImplTest, TileGridAlignment) {
+  // Layer to span 4 raster tiles in x and in y
+  ImplSidePaintingSettings settings;
+  gfx::Size layer_size(settings.default_tile_size.width() * 7 / 2,
+                       settings.default_tile_size.height() * 7 / 2);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(layer_size, layer_size);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(layer_size, layer_size);
+
+  SetupTrees(pending_pile, active_pile);
+
+  // Add 1x1 rects at the centers of each tile, then re-record pile contents
+  active_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
+  std::vector<Tile*> tiles =
+      active_layer_->tilings()->tiling_at(0)->AllTilesForTesting();
+  EXPECT_EQ(16u, tiles.size());
+  std::vector<SkRect> rects;
+  std::vector<Tile*>::const_iterator tile_iter;
+  for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
+    gfx::Point tile_center = (*tile_iter)->content_rect().CenterPoint();
+    gfx::Rect rect(tile_center.x(), tile_center.y(), 1, 1);
+    active_pile->add_draw_rect(rect);
+    rects.push_back(SkRect::MakeXYWH(rect.x(), rect.y(), 1, 1));
+  }
+  // Force re-raster with newly injected content
+  active_pile->RemoveRecordingAt(0, 0);
+  active_pile->AddRecordingAt(0, 0);
+
+  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->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
+    // neighboring tiles which indicates that the tile grid embedded in
+    // SkPicture is perfectly aligned with the compositor's tiles.
+    EXPECT_EQ(1u, mock_canvas.rects_.size());
+    EXPECT_EQ(*rect_iter, mock_canvas.rects_[0]);
+    rect_iter++;
+  }
 }
 
 TEST_F(PictureLayerImplTest, CloneNoInvalidation) {
@@ -312,10 +375,7 @@
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  SetupTrees(pending_pile, active_pile);
-
-  Region invalidation;
-  AddDefaultTilingsWithInvalidation(invalidation);
+  SetupTreesWithInvalidation(pending_pile, active_pile, Region());
 
   EXPECT_EQ(pending_layer_->tilings()->num_tilings(),
             active_layer_->tilings()->num_tilings());
@@ -323,7 +383,7 @@
   const PictureLayerTilingSet* tilings = pending_layer_->tilings();
   EXPECT_GT(tilings->num_tilings(), 0u);
   for (size_t i = 0; i < tilings->num_tilings(); ++i)
-    VerifyAllTilesExistAndHavePile(tilings->tiling_at(i), active_pile.get());
+    VerifyAllTilesExistAndHavePile(tilings->tiling_at(i), pending_pile.get());
 }
 
 TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) {
@@ -339,10 +399,8 @@
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  SetupTrees(pending_pile, active_pile);
+  SetupTreesWithInvalidation(pending_pile, active_pile, Region());
 
-  Region invalidation;
-  AddDefaultTilingsWithInvalidation(invalidation);
   SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
 
   time_ticks += base::TimeDelta::FromMilliseconds(200);
@@ -436,10 +494,8 @@
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  SetupTrees(pending_pile, active_pile);
+  SetupTreesWithInvalidation(pending_pile, active_pile, Region());
 
-  Region invalidation;
-  AddDefaultTilingsWithInvalidation(invalidation);
   SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
 
   // UpdateTiles with valid viewport. Should update tile viewport.
@@ -516,11 +572,20 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> lost_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  SetupTrees(pending_pile, active_pile);
+  SetupPendingTreeWithFixedTileSize(lost_pile, gfx::Size(50, 50), Region());
+  ActivateTree();
+  // Add a non-shared tiling on the active tree.
+  PictureLayerTiling* tiling = active_layer_->AddTiling(3.f);
+  tiling->CreateAllTilesForTesting();
+  // Then setup a new pending tree and activate it.
+  SetupTreesWithFixedTileSize(pending_pile, active_pile, gfx::Size(50, 50),
+                              layer_invalidation);
 
-  Region invalidation(layer_invalidation);
-  AddDefaultTilingsWithInvalidation(invalidation);
+  EXPECT_EQ(2u, pending_layer_->num_tilings());
+  EXPECT_EQ(3u, active_layer_->num_tilings());
 
   const PictureLayerTilingSet* tilings = pending_layer_->tilings();
   EXPECT_GT(tilings->num_tilings(), 0u);
@@ -537,10 +602,30 @@
          ++iter) {
       EXPECT_TRUE(*iter);
       EXPECT_FALSE(iter.geometry_rect().IsEmpty());
+      EXPECT_EQ(pending_pile.get(), iter->raster_source());
+    }
+  }
+
+  tilings = active_layer_->tilings();
+  EXPECT_GT(tilings->num_tilings(), 0u);
+  for (size_t i = 0; i < tilings->num_tilings(); ++i) {
+    const PictureLayerTiling* tiling = tilings->tiling_at(i);
+    gfx::Rect content_invalidation =
+        gfx::ScaleToEnclosingRect(layer_invalidation, tiling->contents_scale());
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             tiling->contents_scale(),
+             gfx::Rect(tiling->tiling_size()));
+         iter;
+         ++iter) {
+      EXPECT_TRUE(*iter);
+      EXPECT_FALSE(iter.geometry_rect().IsEmpty());
       if (iter.geometry_rect().Intersects(content_invalidation))
-        EXPECT_EQ(pending_pile.get(), iter->raster_source());
-      else
         EXPECT_EQ(active_pile.get(), iter->raster_source());
+      else if (!active_layer_->GetPendingOrActiveTwinTiling(tiling))
+        EXPECT_EQ(active_pile.get(), iter->raster_source());
+      else
+        EXPECT_EQ(pending_pile.get(), iter->raster_source());
     }
   }
 }
@@ -554,10 +639,8 @@
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  SetupTrees(pending_pile, active_pile);
-
-  Region invalidation((gfx::Rect(layer_bounds)));
-  AddDefaultTilingsWithInvalidation(invalidation);
+  SetupTreesWithInvalidation(pending_pile, active_pile,
+                             gfx::Rect(layer_bounds));
 
   EXPECT_EQ(pending_layer_->tilings()->num_tilings(),
             active_layer_->tilings()->num_tilings());
@@ -568,125 +651,6 @@
     VerifyAllTilesExistAndHavePile(tilings->tiling_at(i), pending_pile.get());
 }
 
-TEST_F(PictureLayerImplTest, NoInvalidationBoundsChange) {
-  gfx::Size tile_size(90, 80);
-  gfx::Size active_layer_bounds(300, 500);
-  gfx::Size pending_layer_bounds(400, 800);
-
-  scoped_refptr<FakePicturePileImpl> pending_pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size,
-                                                pending_layer_bounds);
-  scoped_refptr<FakePicturePileImpl> active_pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, active_layer_bounds);
-
-  SetupTrees(pending_pile, active_pile);
-  pending_layer_->set_fixed_tile_size(gfx::Size(100, 100));
-
-  Region invalidation;
-  AddDefaultTilingsWithInvalidation(invalidation);
-
-  const PictureLayerTilingSet* tilings = pending_layer_->tilings();
-  EXPECT_GT(tilings->num_tilings(), 0u);
-  for (size_t i = 0; i < tilings->num_tilings(); ++i) {
-    const PictureLayerTiling* tiling = tilings->tiling_at(i);
-    gfx::Rect active_content_bounds = gfx::ScaleToEnclosingRect(
-        gfx::Rect(active_layer_bounds),
-        tiling->contents_scale());
-    for (PictureLayerTiling::CoverageIterator iter(
-             tiling,
-             tiling->contents_scale(),
-             gfx::Rect(tiling->tiling_size()));
-         iter;
-         ++iter) {
-      EXPECT_TRUE(*iter);
-      EXPECT_FALSE(iter.geometry_rect().IsEmpty());
-      std::vector<Tile*> active_tiles =
-          active_layer_->tilings()->tiling_at(i)->AllTilesForTesting();
-      std::vector<Tile*> pending_tiles = tiling->AllTilesForTesting();
-      if (iter.geometry_rect().right() >= active_content_bounds.width() ||
-          iter.geometry_rect().bottom() >= active_content_bounds.height() ||
-          active_tiles[0]->content_rect().size() !=
-              pending_tiles[0]->content_rect().size()) {
-        EXPECT_EQ(pending_pile.get(), iter->raster_source());
-      } else {
-        EXPECT_EQ(active_pile.get(), iter->raster_source());
-      }
-    }
-  }
-}
-
-TEST_F(PictureLayerImplTest, AddTilesFromNewRecording) {
-  gfx::Size tile_size(400, 400);
-  gfx::Size layer_bounds(1300, 1900);
-
-  scoped_refptr<FakePicturePileImpl> pending_pile =
-      FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
-  scoped_refptr<FakePicturePileImpl> active_pile =
-      FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
-
-  // Fill in some of active pile, but more of pending pile.
-  int hole_count = 0;
-  for (int x = 0; x < active_pile->tiling().num_tiles_x(); ++x) {
-    for (int y = 0; y < active_pile->tiling().num_tiles_y(); ++y) {
-      if ((x + y) % 2) {
-        pending_pile->AddRecordingAt(x, y);
-        active_pile->AddRecordingAt(x, y);
-      } else {
-        hole_count++;
-        if (hole_count % 2)
-          pending_pile->AddRecordingAt(x, y);
-      }
-    }
-  }
-
-  SetupTrees(pending_pile, active_pile);
-  Region invalidation;
-  AddDefaultTilingsWithInvalidation(invalidation);
-
-  const PictureLayerTilingSet* tilings = pending_layer_->tilings();
-  EXPECT_GT(tilings->num_tilings(), 0u);
-  for (size_t i = 0; i < tilings->num_tilings(); ++i) {
-    const PictureLayerTiling* tiling = tilings->tiling_at(i);
-
-    for (PictureLayerTiling::CoverageIterator iter(
-             tiling,
-             tiling->contents_scale(),
-             gfx::Rect(tiling->tiling_size()));
-         iter;
-         ++iter) {
-      EXPECT_FALSE(iter.full_tile_geometry_rect().IsEmpty());
-      // Ensure there is a recording for this tile.
-      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());
-      else if (in_active)
-        EXPECT_EQ(active_pile.get(), iter->raster_source());
-      else
-        EXPECT_FALSE(*iter);
-    }
-  }
-}
-
-TEST_F(PictureLayerImplTest, ManageTilingsWithNoRecording) {
-  gfx::Size tile_size(400, 400);
-  gfx::Size layer_bounds(1300, 1900);
-
-  scoped_refptr<FakePicturePileImpl> pending_pile =
-      FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
-  scoped_refptr<FakePicturePileImpl> active_pile =
-      FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
-
-  SetupTrees(pending_pile, active_pile);
-
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
-
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-}
-
 TEST_F(PictureLayerImplTest, ManageTilingsCreatesTilings) {
   gfx::Size tile_size(400, 400);
   gfx::Size layer_bounds(1300, 1900);
@@ -697,11 +661,83 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
   SetupTrees(pending_pile, active_pile);
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
 
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
   EXPECT_LT(low_res_factor, 1.f);
 
+  active_layer_->ReleaseResources();
+  EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+
+  SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                    6.f,  // ideal contents scale
+                                    3.f,  // device scale
+                                    2.f,  // page scale
+                                    1.f,  // maximum animation scale
+                                    false);
+  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(6.f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(6.f * low_res_factor,
+                  active_layer_->tilings()->tiling_at(1)->contents_scale());
+
+  // If we change the page scale factor, then we should get new tilings.
+  SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                    6.6f,  // ideal contents scale
+                                    3.f,   // device scale
+                                    2.2f,  // page scale
+                                    1.f,   // maximum animation scale
+                                    false);
+  ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(6.6f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(6.6f * low_res_factor,
+                  active_layer_->tilings()->tiling_at(2)->contents_scale());
+
+  // If we change the device scale factor, then we should get new tilings.
+  SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                    7.26f,  // ideal contents scale
+                                    3.3f,   // device scale
+                                    2.2f,   // page scale
+                                    1.f,    // maximum animation scale
+                                    false);
+  ASSERT_EQ(6u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(7.26f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(7.26f * low_res_factor,
+                  active_layer_->tilings()->tiling_at(3)->contents_scale());
+
+  // If we change the device scale factor, but end up at the same total scale
+  // factor somehow, then we don't get new tilings.
+  SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                    7.26f,  // ideal contents scale
+                                    2.2f,   // device scale
+                                    3.3f,   // page scale
+                                    1.f,    // maximum animation scale
+                                    false);
+  ASSERT_EQ(6u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(7.26f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(7.26f * low_res_factor,
+                  active_layer_->tilings()->tiling_at(3)->contents_scale());
+}
+
+TEST_F(PictureLayerImplTest, PendingLayerOnlyHasHighAndLowResTiling) {
+  gfx::Size tile_size(400, 400);
+  gfx::Size layer_bounds(1300, 1900);
+
+  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;
+  EXPECT_LT(low_res_factor, 1.f);
+
+  pending_layer_->ReleaseResources();
+  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
   SetupDrawPropertiesAndUpdateTiles(pending_layer_,
                                     6.f,  // ideal contents scale
                                     3.f,  // device scale
@@ -721,11 +757,11 @@
                                     2.2f,  // page scale
                                     1.f,   // maximum animation scale
                                     false);
-  ASSERT_EQ(4u, pending_layer_->tilings()->num_tilings());
+  ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(6.6f,
                   pending_layer_->tilings()->tiling_at(0)->contents_scale());
   EXPECT_FLOAT_EQ(6.6f * low_res_factor,
-                  pending_layer_->tilings()->tiling_at(2)->contents_scale());
+                  pending_layer_->tilings()->tiling_at(1)->contents_scale());
 
   // If we change the device scale factor, then we should get new tilings.
   SetupDrawPropertiesAndUpdateTiles(pending_layer_,
@@ -734,11 +770,11 @@
                                     2.2f,   // page scale
                                     1.f,    // maximum animation scale
                                     false);
-  ASSERT_EQ(6u, pending_layer_->tilings()->num_tilings());
+  ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(7.26f,
                   pending_layer_->tilings()->tiling_at(0)->contents_scale());
   EXPECT_FLOAT_EQ(7.26f * low_res_factor,
-                  pending_layer_->tilings()->tiling_at(3)->contents_scale());
+                  pending_layer_->tilings()->tiling_at(1)->contents_scale());
 
   // If we change the device scale factor, but end up at the same total scale
   // factor somehow, then we don't get new tilings.
@@ -748,11 +784,11 @@
                                     3.3f,   // page scale
                                     1.f,    // maximum animation scale
                                     false);
-  ASSERT_EQ(6u, pending_layer_->tilings()->num_tilings());
+  ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(7.26f,
                   pending_layer_->tilings()->tiling_at(0)->contents_scale());
   EXPECT_FLOAT_EQ(7.26f * low_res_factor,
-                  pending_layer_->tilings()->tiling_at(3)->contents_scale());
+                  pending_layer_->tilings()->tiling_at(1)->contents_scale());
 }
 
 TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) {
@@ -767,63 +803,22 @@
   scoped_refptr<FakePicturePileImpl> valid_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
-  EXPECT_LT(low_res_factor, 1.f);
-
-  float high_res_scale = 1.3f;
-  float low_res_scale = high_res_scale * low_res_factor;
-  float device_scale = 1.7f;
-  float page_scale = 3.2f;
-  float maximum_animation_scale = 1.f;
-
   SetupPendingTree(valid_pile);
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
-                                    high_res_scale,
-                                    device_scale,
-                                    page_scale,
-                                    maximum_animation_scale,
-                                    false);
   ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(high_res_scale,
-                  pending_layer_->HighResTiling()->contents_scale());
-  EXPECT_FLOAT_EQ(low_res_scale,
-                  pending_layer_->LowResTiling()->contents_scale());
 
   ActivateTree();
   SetupPendingTree(empty_pile);
   EXPECT_FALSE(pending_layer_->CanHaveTilings());
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
-                                    high_res_scale,
-                                    device_scale,
-                                    page_scale,
-                                    maximum_animation_scale,
-                                    false);
   ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
   ASSERT_EQ(0u, pending_layer_->tilings()->num_tilings());
 
   ActivateTree();
   EXPECT_FALSE(active_layer_->CanHaveTilings());
-  SetupDrawPropertiesAndUpdateTiles(active_layer_,
-                                    high_res_scale,
-                                    device_scale,
-                                    page_scale,
-                                    maximum_animation_scale,
-                                    false);
   ASSERT_EQ(0u, active_layer_->tilings()->num_tilings());
 
   SetupPendingTree(valid_pile);
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
-                                    high_res_scale,
-                                    device_scale,
-                                    page_scale,
-                                    maximum_animation_scale,
-                                    false);
   ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
   ASSERT_EQ(0u, active_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(high_res_scale,
-                  pending_layer_->HighResTiling()->contents_scale());
-  EXPECT_FLOAT_EQ(low_res_scale,
-                  pending_layer_->LowResTiling()->contents_scale());
 }
 
 TEST_F(PictureLayerImplTest, ZoomOutCrash) {
@@ -837,8 +832,10 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
   SetupTrees(pending_pile, active_pile);
+  ResetTilingsAndRasterScales();
   EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
   SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f, 1.0f, false);
+  EXPECT_EQ(32.f, active_layer_->HighResTiling()->contents_scale());
   host_impl_.PinchGestureBegin();
   SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, false);
   SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, false);
@@ -849,6 +846,8 @@
   gfx::Size tile_size(400, 400);
   gfx::Size layer_bounds(1300, 1900);
 
+  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   scoped_refptr<FakePicturePileImpl> active_pile =
@@ -856,21 +855,20 @@
 
   // Set up the high and low res tilings before pinch zoom.
   SetupTrees(pending_pile, active_pile);
-  EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
-  SetContentsScaleOnBothLayers(2.0f, 1.0f, 1.0f, 1.0f, false);
-  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
-  EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(2.0f,
-                  active_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_FLOAT_EQ(2.0f * low_res_factor,
-                  active_layer_->tilings()->tiling_at(1)->contents_scale());
+  ResetTilingsAndRasterScales();
+
+  SetContentsScaleOnBothLayers(2.f, 1.0f, 2.f, 1.0f, false);
+  EXPECT_BOTH_EQ(num_tilings(), 2u);
+  EXPECT_BOTH_EQ(tilings()->tiling_at(0)->contents_scale(), 2.f);
+  EXPECT_BOTH_EQ(tilings()->tiling_at(1)->contents_scale(),
+                 2.f * low_res_factor);
 
   // Start a pinch gesture.
   host_impl_.PinchGestureBegin();
 
   // Zoom out by a small amount. We should create a tiling at half
   // the scale (2/kMaxScaleRatioDuringPinch).
-  SetContentsScaleOnBothLayers(1.8f, 1.0f, 0.9f, 1.0f, false);
+  SetContentsScaleOnBothLayers(1.8f, 1.0f, 1.8f, 1.0f, false);
   EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(2.0f,
                   active_layer_->tilings()->tiling_at(0)->contents_scale());
@@ -887,7 +885,7 @@
 
   // Zoom in a lot now. Since we increase by increments of
   // kMaxScaleRatioDuringPinch, this will create a new tiling at 4.0.
-  SetContentsScaleOnBothLayers(3.8f, 1.0f, 2.1f, 1.f, false);
+  SetContentsScaleOnBothLayers(3.8f, 1.0f, 3.8f, 1.f, false);
   EXPECT_EQ(4u, active_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(4.0f,
                   active_layer_->tilings()->tiling_at(0)->contents_scale());
@@ -902,9 +900,12 @@
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  // Set up the high and low res tilings before pinch zoom.
   SetupTrees(pending_pile, active_pile);
+
+  ResetTilingsAndRasterScales();
   EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+
+  // Set up the high and low res tilings before pinch zoom.
   SetContentsScaleOnBothLayers(0.24f, 1.0f, 0.24f, 1.0f, false);
   EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(0.24f,
@@ -955,31 +956,28 @@
 
   std::vector<PictureLayerTiling*> used_tilings;
 
-  SetupTrees(pending_pile, active_pile);
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
   EXPECT_LT(low_res_factor, 1.f);
 
-  float device_scale = 1.7f;
-  float page_scale = 3.2f;
   float scale = 1.f;
+  float page_scale = 1.f;
 
-  SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
-  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+  SetupTrees(pending_pile, active_pile);
+  EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
+  EXPECT_EQ(1.f, active_layer_->HighResTiling()->contents_scale());
 
   // We only have ideal tilings, so they aren't removed.
   used_tilings.clear();
   active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
-  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+  EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
 
   host_impl_.PinchGestureBegin();
 
   // Changing the ideal but not creating new tilings.
-  scale *= 1.5f;
-  page_scale *= 1.5f;
-  SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
-  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+  scale = 1.5f;
+  page_scale = 1.5f;
+  SetContentsScaleOnBothLayers(scale, 1.f, page_scale, 1.f, false);
+  EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
 
   // The tilings are still our target scale, so they aren't removed.
   used_tilings.clear();
@@ -989,9 +987,9 @@
   host_impl_.PinchGestureEnd();
 
   // Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
-  scale /= 4.f;
-  page_scale /= 4.f;
-  SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, 1.f, false);
+  scale = 1.2f;
+  page_scale = 1.2f;
+  SetContentsScaleOnBothLayers(1.2f, 1.f, page_scale, 1.f, false);
   ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(
       1.f,
@@ -1008,7 +1006,7 @@
   ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
 
   // Now move the ideal scale to 0.5. Our target stays 1.2.
-  SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, 1.f, false);
+  SetContentsScaleOnBothLayers(0.5f, 1.f, page_scale, 1.f, false);
 
   // The high resolution tiling is between target and ideal, so is not
   // removed.  The low res tiling for the old ideal=1.0 scale is removed.
@@ -1017,7 +1015,7 @@
   ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
 
   // Now move the ideal scale to 1.0. Our target stays 1.2.
-  SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, 1.f, false);
+  SetContentsScaleOnBothLayers(1.f, 1.f, page_scale, 1.f, false);
 
   // All the tilings are between are target and the ideal, so they are not
   // removed.
@@ -1026,8 +1024,8 @@
   ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
 
   // Now move the ideal scale to 1.1 on the active layer. Our target stays 1.2.
-  SetupDrawPropertiesAndUpdateTiles(
-      active_layer_, 1.1f, device_scale, page_scale, 1.f, false);
+  SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.1f, 1.f, page_scale, 1.f,
+                                    false);
 
   // Because the pending layer's ideal scale is still 1.0, our tilings fall
   // in the range [1.0,1.2] and are kept.
@@ -1037,8 +1035,8 @@
 
   // Move the ideal scale on the pending layer to 1.1 as well. Our target stays
   // 1.2 still.
-  SetupDrawPropertiesAndUpdateTiles(
-      pending_layer_, 1.1f, device_scale, page_scale, 1.f, false);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.1f, 1.f, page_scale, 1.f,
+                                    false);
 
   // Our 1.0 tiling now falls outside the range between our ideal scale and our
   // target raster scale. But it is in our used tilings set, so nothing is
@@ -1055,26 +1053,13 @@
   ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
 }
 
-#define EXPECT_BOTH_EQ(expression, x)         \
-  do {                                        \
-    EXPECT_EQ(x, pending_layer_->expression); \
-    EXPECT_EQ(x, active_layer_->expression);  \
-  } while (false)
-
-#define EXPECT_BOTH_NE(expression, x)         \
-  do {                                        \
-    EXPECT_NE(x, pending_layer_->expression); \
-    EXPECT_NE(x, active_layer_->expression);  \
-  } while (false)
-
 TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) {
   // Make sure this layer covers multiple tiles, since otherwise low
   // res won't get created because it is too small.
   gfx::Size tile_size(host_impl_.settings().default_tile_size);
-  SetupDefaultTrees(gfx::Size(tile_size.width() + 1, tile_size.height() + 1));
   // Avoid max untiled layer size heuristics via fixed tile size.
-  pending_layer_->set_fixed_tile_size(tile_size);
-  active_layer_->set_fixed_tile_size(tile_size);
+  gfx::Size layer_bounds(tile_size.width() + 1, tile_size.height() + 1);
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
 
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
   float contents_scale = 1.f;
@@ -1083,6 +1068,8 @@
   float maximum_animation_scale = 1.f;
   bool animating_transform = true;
 
+  ResetTilingsAndRasterScales();
+
   // Animating, so don't create low res even if there isn't one already.
   SetContentsScaleOnBothLayers(contents_scale,
                                device_scale,
@@ -1104,7 +1091,8 @@
   EXPECT_BOTH_EQ(num_tilings(), 2u);
 
   // Page scale animation, new high res, but no low res. We still have
-  // a tiling at the previous scale, it's just not marked as low res.
+  // a tiling at the previous scale, it's just not marked as low res on the
+  // active layer. The pending layer drops non-ideal tilings.
   contents_scale = 2.f;
   page_scale = 2.f;
   maximum_animation_scale = 2.f;
@@ -1117,7 +1105,8 @@
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
   EXPECT_FALSE(active_layer_->LowResTiling());
   EXPECT_FALSE(pending_layer_->LowResTiling());
-  EXPECT_BOTH_EQ(num_tilings(), 3u);
+  EXPECT_EQ(3u, active_layer_->num_tilings());
+  EXPECT_EQ(1u, pending_layer_->num_tilings());
 
   // Stop animating, new low res gets created for final page scale.
   animating_transform = false;
@@ -1128,7 +1117,8 @@
                                animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
   EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), 2.f * low_res_factor);
-  EXPECT_BOTH_EQ(num_tilings(), 4u);
+  EXPECT_EQ(4u, active_layer_->num_tilings());
+  EXPECT_EQ(2u, pending_layer_->num_tilings());
 }
 
 TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
@@ -1185,120 +1175,187 @@
                  contents_scale * low_res_factor);
   EXPECT_BOTH_EQ(num_tilings(), 2u);
 
-  ResetTilingsAndRasterScales();
-
   // Mask layers dont create low res since they always fit on one tile.
-  pending_layer_->set_is_mask(true);
-  active_layer_->set_is_mask(true);
-  SetContentsScaleOnBothLayers(contents_scale,
-                               device_scale,
-                               page_scale,
-                               maximum_animation_scale,
-                               animating_transform);
-  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
-  EXPECT_BOTH_EQ(num_tilings(), 1u);
+  scoped_ptr<FakePictureLayerImpl> mask =
+      FakePictureLayerImpl::CreateMaskWithRasterSource(
+          host_impl_.pending_tree(), 3, pending_pile);
+  mask->SetBounds(layer_bounds);
+  mask->SetContentBounds(layer_bounds);
+  mask->SetDrawsContent(true);
+
+  SetupDrawPropertiesAndUpdateTiles(mask.get(), contents_scale, device_scale,
+                                    page_scale, maximum_animation_scale,
+                                    animating_transform);
+  EXPECT_EQ(mask->HighResTiling()->contents_scale(), contents_scale);
+  EXPECT_EQ(mask->num_tilings(), 1u);
 }
 
 TEST_F(PictureLayerImplTest, HugeMasksDontGetTiles) {
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
   gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(1000, 1000);
 
   scoped_refptr<FakePicturePileImpl> valid_pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   SetupPendingTree(valid_pile);
-  pending_layer_->set_is_mask(true);
 
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
-  EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
-  EXPECT_EQ(1u, pending_layer_->num_tilings());
+  scoped_ptr<FakePictureLayerImpl> mask_ptr =
+      FakePictureLayerImpl::CreateMaskWithRasterSource(
+          host_impl_.pending_tree(), 3, valid_pile);
+  mask_ptr->SetBounds(layer_bounds);
+  mask_ptr->SetContentBounds(layer_bounds);
+  mask_ptr->SetDrawsContent(true);
+  pending_layer_->SetMaskLayer(mask_ptr.Pass());
 
-  pending_layer_->HighResTiling()->CreateAllTilesForTesting();
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  FakePictureLayerImpl* pending_mask =
+      static_cast<FakePictureLayerImpl*>(pending_layer_->mask_layer());
+
+  EXPECT_EQ(1.f, pending_mask->HighResTiling()->contents_scale());
+  EXPECT_EQ(1u, pending_mask->num_tilings());
+
   host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
-      pending_layer_->HighResTiling()->AllTilesForTesting());
+      pending_mask->HighResTiling()->AllTilesForTesting());
 
   ActivateTree();
 
+  FakePictureLayerImpl* active_mask =
+      static_cast<FakePictureLayerImpl*>(active_layer_->mask_layer());
+
   // Mask layers have a tiling with a single tile in it.
-  EXPECT_EQ(1u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+  EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
   // The mask resource exists.
   ResourceProvider::ResourceId mask_resource_id;
   gfx::Size mask_texture_size;
-  active_layer_->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+  active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+  EXPECT_NE(0u, mask_resource_id);
+  EXPECT_EQ(mask_texture_size, active_mask->bounds());
+
+  // Drop resources and recreate them, still the same.
+  pending_mask->ReleaseResources();
+  active_mask->ReleaseResources();
+  SetupDrawPropertiesAndUpdateTiles(active_mask, 1.f, 1.f, 1.f, 1.f, false);
+  active_mask->HighResTiling()->CreateAllTilesForTesting();
+  EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
   EXPECT_NE(0u, mask_resource_id);
   EXPECT_EQ(mask_texture_size, active_layer_->bounds());
 
   // Drop resources and recreate them, still the same.
-  old_pending_layer_->ReleaseResources();
-  active_layer_->ReleaseResources();
-  SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
-  active_layer_->HighResTiling()->CreateAllTilesForTesting();
-  EXPECT_EQ(1u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+  pending_mask->ReleaseResources();
+  active_mask->ReleaseResources();
+  SetupDrawPropertiesAndUpdateTiles(active_mask, 1.f, 1.f, 1.f, 1.f, false);
+  active_mask->HighResTiling()->CreateAllTilesForTesting();
+  EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
   EXPECT_NE(0u, mask_resource_id);
-  EXPECT_EQ(mask_texture_size, active_layer_->bounds());
+  EXPECT_EQ(mask_texture_size, active_mask->bounds());
 
   // Resize larger than the max texture size.
   int max_texture_size = host_impl_.GetRendererCapabilities().max_texture_size;
+  gfx::Size huge_bounds(max_texture_size + 1, 10);
   scoped_refptr<FakePicturePileImpl> huge_pile =
-      FakePicturePileImpl::CreateFilledPile(
-          tile_size, gfx::Size(max_texture_size + 1, 10));
+      FakePicturePileImpl::CreateFilledPile(tile_size, huge_bounds);
+
   SetupPendingTree(huge_pile);
-  pending_layer_->set_is_mask(true);
+  pending_mask->SetBounds(huge_bounds);
+  pending_mask->SetContentBounds(huge_bounds);
+  pending_mask->SetRasterSourceOnPending(huge_pile, Region());
 
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
-  EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
-  EXPECT_EQ(1u, pending_layer_->num_tilings());
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+  host_impl_.pending_tree()->UpdateDrawProperties();
 
-  pending_layer_->HighResTiling()->CreateAllTilesForTesting();
+  EXPECT_EQ(1.f, pending_mask->HighResTiling()->contents_scale());
+  EXPECT_EQ(1u, pending_mask->num_tilings());
+
   host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
-      pending_layer_->HighResTiling()->AllTilesForTesting());
+      pending_mask->HighResTiling()->AllTilesForTesting());
 
   ActivateTree();
 
   // Mask layers have a tiling, but there should be no tiles in it.
-  EXPECT_EQ(0u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+  EXPECT_EQ(0u, active_mask->HighResTiling()->AllTilesForTesting().size());
   // The mask resource is empty.
   active_layer_->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
   EXPECT_EQ(0u, mask_resource_id);
 
   // Drop resources and recreate them, still the same.
-  old_pending_layer_->ReleaseResources();
-  active_layer_->ReleaseResources();
-  SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
-  active_layer_->HighResTiling()->CreateAllTilesForTesting();
-  EXPECT_EQ(0u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+  pending_mask->ReleaseResources();
+  active_mask->ReleaseResources();
+  SetupDrawPropertiesAndUpdateTiles(active_mask, 1.f, 1.f, 1.f, 1.f, false);
+  active_mask->HighResTiling()->CreateAllTilesForTesting();
+  EXPECT_EQ(0u, active_mask->HighResTiling()->AllTilesForTesting().size());
+  active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+  EXPECT_EQ(0u, mask_resource_id);
+
+  // Do another activate, the same holds.
+  SetupPendingTree(huge_pile);
+  ActivateTree();
+  EXPECT_EQ(0u, active_mask->HighResTiling()->AllTilesForTesting().size());
   active_layer_->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
   EXPECT_EQ(0u, mask_resource_id);
 }
 
 TEST_F(PictureLayerImplTest, ScaledMaskLayer) {
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
   gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(1000, 1000);
+
+  host_impl_.SetDeviceScaleFactor(1.3f);
 
   scoped_refptr<FakePicturePileImpl> valid_pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   SetupPendingTree(valid_pile);
-  pending_layer_->set_is_mask(true);
 
-  float ideal_contents_scale = 1.3f;
-  SetupDrawPropertiesAndUpdateTiles(
-      pending_layer_, ideal_contents_scale, 1.f, 1.f, 1.f, false);
-  EXPECT_EQ(ideal_contents_scale,
-            pending_layer_->HighResTiling()->contents_scale());
-  EXPECT_EQ(1u, pending_layer_->num_tilings());
+  scoped_ptr<FakePictureLayerImpl> mask_ptr =
+      FakePictureLayerImpl::CreateMaskWithRasterSource(
+          host_impl_.pending_tree(), 3, valid_pile);
+  mask_ptr->SetBounds(layer_bounds);
+  mask_ptr->SetContentBounds(layer_bounds);
+  mask_ptr->SetDrawsContent(true);
+  pending_layer_->SetMaskLayer(mask_ptr.Pass());
 
-  pending_layer_->HighResTiling()->CreateAllTilesForTesting();
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  FakePictureLayerImpl* pending_mask =
+      static_cast<FakePictureLayerImpl*>(pending_layer_->mask_layer());
+
+  // Masks are scaled, and do not have a low res tiling.
+  EXPECT_EQ(1.3f, pending_mask->HighResTiling()->contents_scale());
+  EXPECT_EQ(1u, pending_mask->num_tilings());
+
   host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
-      pending_layer_->HighResTiling()->AllTilesForTesting());
+      pending_mask->HighResTiling()->AllTilesForTesting());
 
   ActivateTree();
 
+  FakePictureLayerImpl* active_mask =
+      static_cast<FakePictureLayerImpl*>(active_layer_->mask_layer());
+
   // Mask layers have a tiling with a single tile in it.
-  EXPECT_EQ(1u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+  EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
   // The mask resource exists.
   ResourceProvider::ResourceId mask_resource_id;
   gfx::Size mask_texture_size;
-  active_layer_->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+  active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
   EXPECT_NE(0u, mask_resource_id);
-  gfx::Size expected_mask_texture_size = gfx::ToCeiledSize(
-      gfx::ScaleSize(active_layer_->bounds(), ideal_contents_scale));
+  gfx::Size expected_mask_texture_size =
+      gfx::ToCeiledSize(gfx::ScaleSize(active_mask->bounds(), 1.3f));
   EXPECT_EQ(mask_texture_size, expected_mask_texture_size);
 }
 
@@ -1312,14 +1369,6 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
   SetupTrees(pending_pile, active_pile);
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
-                                    1.3f,  // ideal contents scale
-                                    2.7f,  // device scale
-                                    3.2f,  // page scale
-                                    1.f,   // maximum animation scale
-                                    false);
   EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
 
   // All tilings should be removed when losing output surface.
@@ -1330,10 +1379,10 @@
 
   // This should create new tilings.
   SetupDrawPropertiesAndUpdateTiles(pending_layer_,
-                                    1.3f,  // ideal contents scale
-                                    2.7f,  // device scale
-                                    3.2f,  // page scale
-                                    1.f,   // maximum animation scale
+                                    1.f,  // ideal contents scale
+                                    1.f,  // device scale
+                                    1.f,  // page scale
+                                    1.f,  // maximum animation scale
                                     false);
   EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
 }
@@ -1349,10 +1398,7 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
   SetupTrees(pending_pile, active_pile);
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
-  ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
+  EXPECT_GE(pending_layer_->tilings()->num_tilings(), 1u);
 
   pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
 
@@ -1364,7 +1410,7 @@
   EXPECT_EQ(gfx::Size(256, 256).ToString(),
             tile->content_rect().size().ToString());
 
-  pending_layer_->ReleaseResources();
+  ResetTilingsAndRasterScales();
 
   // Change the max texture size on the output surface context.
   scoped_ptr<TestWebGraphicsContext3D> context =
@@ -1396,10 +1442,7 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
   SetupTrees(pending_pile, active_pile);
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
-  ASSERT_LE(1u, pending_layer_->tilings()->num_tilings());
+  EXPECT_GE(pending_layer_->tilings()->num_tilings(), 1u);
 
   pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
 
@@ -1411,7 +1454,7 @@
   PictureLayerTiling* high_res_tiling = pending_layer_->tilings()->tiling_at(0);
   EXPECT_EQ(1u, high_res_tiling->AllTilesForTesting().size());
 
-  pending_layer_->ReleaseResources();
+  ResetTilingsAndRasterScales();
 
   // Change the max texture size on the output surface context.
   scoped_ptr<TestWebGraphicsContext3D> context =
@@ -1448,15 +1491,12 @@
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  SetupTrees(pending_pile, active_pile);
+  gfx::Rect layer_invalidation(150, 200, 30, 180);
+  SetupTreesWithInvalidation(pending_pile, active_pile, layer_invalidation);
 
   active_layer_->draw_properties().visible_content_rect =
       gfx::Rect(layer_bounds);
 
-  gfx::Rect layer_invalidation(150, 200, 30, 180);
-  Region invalidation(layer_invalidation);
-  AddDefaultTilingsWithInvalidation(invalidation);
-
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_RESOURCELESS_SOFTWARE, nullptr);
   active_layer_->AppendQuads(render_pass.get(), Occlusion(), &data);
@@ -1514,33 +1554,20 @@
   pending_pile->set_is_solid_color(false);
   active_pile->set_is_solid_color(true);
   SetupTrees(pending_pile, active_pile);
-  // Solid color layer should not have tilings.
-  ASSERT_FALSE(active_layer_->CanHaveTilings());
-
-  // Update properties with solid color pile should not allow tilings at any
-  // scale.
-  host_impl_.active_tree()->UpdateDrawProperties();
+  // Solid color pile should not allow tilings at any scale.
   EXPECT_FALSE(active_layer_->CanHaveTilings());
   EXPECT_EQ(0.f, active_layer_->ideal_contents_scale());
 
-  // Push non-solid-color pending pile makes active layer can have tilings.
-  active_layer_->UpdateRasterSource(pending_pile);
-  ASSERT_TRUE(active_layer_->CanHaveTilings());
-
-  // Update properties with non-solid color pile should allow tilings.
-  host_impl_.active_tree()->UpdateDrawProperties();
+  // Activate non-solid-color pending pile makes active layer can have tilings.
+  ActivateTree();
   EXPECT_TRUE(active_layer_->CanHaveTilings());
   EXPECT_GT(active_layer_->ideal_contents_scale(), 0.f);
 }
 
-TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
+TEST_F(NoLowResPictureLayerImplTest, MarkRequiredOffscreenTiles) {
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
 
-  scoped_refptr<FakePicturePileImpl> pending_pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  SetupPendingTree(pending_pile);
-
   gfx::Transform transform;
   gfx::Transform transform_for_tile_priority;
   bool resourceless_software_draw = false;
@@ -1552,10 +1579,11 @@
                                         transform,
                                         resourceless_software_draw);
 
-  pending_layer_->set_fixed_tile_size(tile_size);
-  ASSERT_TRUE(pending_layer_->CanHaveTilings());
-  PictureLayerTiling* tiling = pending_layer_->AddTiling(1.f);
-  host_impl_.pending_tree()->UpdateDrawProperties();
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
+
+  EXPECT_EQ(1u, pending_layer_->num_tilings());
   EXPECT_EQ(viewport, pending_layer_->visible_rect_for_tile_priority());
 
   base::TimeTicks time_ticks;
@@ -1563,13 +1591,13 @@
   host_impl_.SetCurrentBeginFrameArgs(
       CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
-  EXPECT_EQ(HIGH_RESOLUTION, tiling->resolution());
 
   int num_visible = 0;
   int num_offscreen = 0;
 
-  for (PictureLayerTiling::TilingRasterTileIterator iter(tiling); iter;
-       ++iter) {
+  for (PictureLayerTiling::TilingRasterTileIterator iter(
+           pending_layer_->HighResTiling());
+       iter; ++iter) {
     const Tile* tile = *iter;
     DCHECK(tile);
     if (tile->priority(PENDING_TREE).distance_to_visible == 0.f) {
@@ -1585,7 +1613,8 @@
   EXPECT_GT(num_offscreen, 0);
 }
 
-TEST_F(PictureLayerImplTest, TileOutsideOfViewportForTilePriorityNotRequired) {
+TEST_F(NoLowResPictureLayerImplTest,
+       TileOutsideOfViewportForTilePriorityNotRequired) {
   base::TimeTicks time_ticks;
   time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentBeginFrameArgs(
@@ -1600,12 +1629,10 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  SetupTrees(pending_pile, active_pile);
+  SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
 
-  active_layer_->set_fixed_tile_size(tile_size);
-  pending_layer_->set_fixed_tile_size(tile_size);
-  ASSERT_TRUE(pending_layer_->CanHaveTilings());
-  PictureLayerTiling* tiling = pending_layer_->AddTiling(1.f);
+  ASSERT_EQ(1u, pending_layer_->num_tilings());
+  ASSERT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
 
   // Set external viewport for tile priority.
   gfx::Rect viewport = gfx::Rect(layer_bounds);
@@ -1618,6 +1645,9 @@
                                         external_viewport_for_tile_priority,
                                         transform_for_tile_priority,
                                         resourceless_software_draw);
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
   host_impl_.pending_tree()->UpdateDrawProperties();
 
   // Set visible content rect that is different from
@@ -1637,9 +1667,8 @@
   int num_inside = 0;
   int num_outside = 0;
   for (PictureLayerTiling::CoverageIterator iter(
-           tiling, pending_layer_->contents_scale_x(), gfx::Rect(layer_bounds));
-       iter;
-       ++iter) {
+           pending_layer_->HighResTiling(), 1.f, gfx::Rect(layer_bounds));
+       iter; ++iter) {
     if (!*iter)
       continue;
     Tile* tile = *iter;
@@ -1683,16 +1712,13 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  SetupPendingTree(pending_pile);
+
+  SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
   ActivateTree();
 
   // All high res tiles have resources.
-  active_layer_->set_fixed_tile_size(tile_size);
-  host_impl_.active_tree()->UpdateDrawProperties();
   std::vector<Tile*> tiles =
       active_layer_->tilings()->tiling_at(0)->AllTilesForTesting();
   host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
@@ -1719,16 +1745,11 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  SetupPendingTree(pending_pile);
+  SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
   ActivateTree();
 
-  active_layer_->set_fixed_tile_size(tile_size);
-  host_impl_.active_tree()->UpdateDrawProperties();
-
   scoped_ptr<RenderPass> render_pass = RenderPass::Create();
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_SOFTWARE, nullptr);
@@ -1750,15 +1771,11 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  SetupPendingTree(pending_pile);
+  SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
   ActivateTree();
 
-  active_layer_->set_fixed_tile_size(tile_size);
-  host_impl_.active_tree()->UpdateDrawProperties();
   std::vector<Tile*> low_tiles =
       active_layer_->tilings()->tiling_at(1)->AllTilesForTesting();
   host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(low_tiles);
@@ -1784,16 +1801,12 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  SetupPendingTree(pending_pile);
+  SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
   ActivateTree();
 
   // All high res tiles have resources except one.
-  active_layer_->set_fixed_tile_size(tile_size);
-  host_impl_.active_tree()->UpdateDrawProperties();
   std::vector<Tile*> high_tiles =
       active_layer_->tilings()->tiling_at(0)->AllTilesForTesting();
   high_tiles.erase(high_tiles.begin());
@@ -1826,20 +1839,16 @@
 
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(200, 200);
+  gfx::Size viewport_size(400, 400);
 
-  host_impl_.SetViewportSize(layer_bounds);
+  host_impl_.SetViewportSize(viewport_size);
+  host_impl_.SetDeviceScaleFactor(2.f);
 
   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);
-
-  active_layer_->set_fixed_tile_size(tile_size);
-
-  active_layer_->draw_properties().visible_content_rect =
-      gfx::Rect(layer_bounds);
-  SetupDrawPropertiesAndUpdateTiles(active_layer_, 2.f, 1.f, 1.f, 1.f, false);
+  SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
 
   // One ideal tile exists, this will get used when drawing.
   std::vector<Tile*> ideal_tiles;
@@ -1891,14 +1900,9 @@
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
-  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
   // No tiles shared.
-  pending_layer_->set_invalidation(gfx::Rect(layer_bounds));
-
-  CreateHighLowResAndSetAllTilesVisible();
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size,
+                                     gfx::Rect(layer_bounds));
 
   active_layer_->SetAllTilesReady();
 
@@ -1915,12 +1919,8 @@
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
-  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
   // All tiles shared (no invalidation).
-  CreateHighLowResAndSetAllTilesVisible();
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
 
   // Verify active tree not ready.
   Tile* some_active_tile =
@@ -1942,11 +1942,7 @@
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
-  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
-  CreateHighLowResAndSetAllTilesVisible();
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
 
   Tile* some_active_tile =
       active_layer_->HighResTiling()->AllTilesForTesting()[0];
@@ -1964,9 +1960,8 @@
 TEST_F(PictureLayerImplTest, DisallowRequiredForActivation) {
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
-  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
 
-  CreateHighLowResAndSetAllTilesVisible();
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
 
   Tile* some_active_tile =
       active_layer_->HighResTiling()->AllTilesForTesting()[0];
@@ -1986,6 +1981,7 @@
 TEST_F(PictureLayerImplTest, NothingRequiredIfActiveMissingTiles) {
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
+
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   // This pile will create tilings, but has no recordings so will not create any
@@ -1995,11 +1991,8 @@
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
           tile_size, layer_bounds);
-  SetupTrees(pending_pile, active_pile);
-  pending_layer_->set_fixed_tile_size(tile_size);
-  active_layer_->set_fixed_tile_size(tile_size);
 
-  CreateHighLowResAndSetAllTilesVisible();
+  SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
 
   // Active layer has tilings, but no tiles due to missing recordings.
   EXPECT_TRUE(active_layer_->CanHaveTilings());
@@ -2019,17 +2012,11 @@
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
-  SetupTrees(pending_pile, active_pile);
-  pending_layer_->set_fixed_tile_size(tile_size);
-  active_layer_->set_fixed_tile_size(tile_size);
-
-  CreateHighLowResAndSetAllTilesVisible();
+  SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
 
   // Active layer can't have tiles.
   EXPECT_FALSE(active_layer_->CanHaveTilings());
@@ -2046,21 +2033,16 @@
 }
 
 TEST_F(PictureLayerImplTest, HighResRequiredWhenActiveHasDifferentBounds) {
-  gfx::Size layer_bounds(200, 200);
-  gfx::Size tile_size(100, 100);
-  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
   gfx::Size pending_layer_bounds(400, 400);
-  pending_layer_->SetBounds(pending_layer_bounds);
+  gfx::Size active_layer_bounds(200, 200);
+  gfx::Size tile_size(100, 100);
 
-  CreateHighLowResAndSetAllTilesVisible();
-  // TODO(vmpstr): This is confusing. Rework the test to create different bounds
-  // on different trees instead of fudging tilings.
-  pending_layer_->HighResTiling()->ComputeTilePriorityRects(
-      gfx::Rect(pending_layer_bounds), 1.f, 1.f, Occlusion());
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, pending_layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, active_layer_bounds);
 
-  pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
-  active_layer_->SetAllTilesReady();
+  SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
 
   // Since the active layer has different bounds, the pending layer needs all
   // high res tiles in order to activate.
@@ -2108,9 +2090,15 @@
 }
 
 TEST_F(PictureLayerImplTest, ShareTilesOnNextFrame) {
-  SetupDefaultTrees(gfx::Size(1500, 1500));
+  gfx::Size layer_bounds(1500, 1500);
+  gfx::Size tile_size(100, 100);
 
-  PictureLayerTiling* tiling = pending_layer_->AddTiling(1.f);
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  SetupPendingTree(pending_pile);
+
+  PictureLayerTiling* tiling = pending_layer_->HighResTiling();
   gfx::Rect first_invalidate = tiling->TilingDataForTesting().TileBounds(0, 0);
   first_invalidate.Inset(tiling->TilingDataForTesting().border_texels(),
                          tiling->TilingDataForTesting().border_texels());
@@ -2118,22 +2106,20 @@
   second_invalidate.Inset(tiling->TilingDataForTesting().border_texels(),
                           tiling->TilingDataForTesting().border_texels());
 
+  ActivateTree();
+
   // Make a pending tree with an invalidated raster tile 0,0.
-  tiling->CreateAllTilesForTesting();
-  pending_layer_->set_invalidation(first_invalidate);
+  SetupPendingTreeWithInvalidation(pending_pile, first_invalidate);
 
   // Activate and make a pending tree with an invalidated raster tile 1,1.
   ActivateTree();
 
-  host_impl_.CreatePendingTree();
-  pending_layer_ = static_cast<FakePictureLayerImpl*>(
-      host_impl_.pending_tree()->root_layer());
-  pending_layer_->set_invalidation(second_invalidate);
+  SetupPendingTreeWithInvalidation(pending_pile, second_invalidate);
 
   PictureLayerTiling* pending_tiling = pending_layer_->tilings()->tiling_at(0);
   PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(0);
 
-  pending_tiling->CreateAllTilesForTesting();
+  // pending_tiling->CreateAllTilesForTesting();
 
   // Tile 0,0 should be shared, but tile 1,1 should not be.
   EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
@@ -2162,180 +2148,138 @@
   EXPECT_FALSE(pending_tiling->TileAt(1, 1)->is_shared());
 }
 
-TEST_F(PictureLayerImplTest, ShareTilesOnSync) {
+TEST_F(PictureLayerImplTest, ShareTilesWithNoInvalidation) {
   SetupDefaultTrees(gfx::Size(1500, 1500));
-  AddDefaultTilingsWithInvalidation(gfx::Rect());
 
-  host_impl_.ActivateSyncTree();
-  host_impl_.CreatePendingTree();
-  active_layer_ = static_cast<FakePictureLayerImpl*>(
-      host_impl_.active_tree()->LayerById(id_));
+  EXPECT_GE(active_layer_->num_tilings(), 1u);
+  EXPECT_GE(pending_layer_->num_tilings(), 1u);
 
-  // Force the active tree to sync to the pending tree "post-commit".
-  pending_layer_->DoPostCommitInitializationIfNeeded();
+  // No invalidation, so all tiles are shared.
+  PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(0);
+  PictureLayerTiling* pending_tiling = pending_layer_->tilings()->tiling_at(0);
+  ASSERT_TRUE(active_tiling);
+  ASSERT_TRUE(pending_tiling);
 
-  // Both invalidations should drop tiles from the pending tree.
-  EXPECT_EQ(3u, active_layer_->num_tilings());
-  EXPECT_EQ(3u, pending_layer_->num_tilings());
-  for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
-    PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(i);
-    PictureLayerTiling* pending_tiling =
-        pending_layer_->tilings()->tiling_at(i);
+  EXPECT_TRUE(active_tiling->TileAt(0, 0));
+  EXPECT_TRUE(active_tiling->TileAt(1, 0));
+  EXPECT_TRUE(active_tiling->TileAt(0, 1));
+  EXPECT_TRUE(active_tiling->TileAt(1, 1));
 
-    ASSERT_TRUE(active_tiling);
-    ASSERT_TRUE(pending_tiling);
+  EXPECT_TRUE(pending_tiling->TileAt(0, 0));
+  EXPECT_TRUE(pending_tiling->TileAt(1, 0));
+  EXPECT_TRUE(pending_tiling->TileAt(0, 1));
+  EXPECT_TRUE(pending_tiling->TileAt(1, 1));
 
-    EXPECT_TRUE(active_tiling->TileAt(0, 0));
-    EXPECT_TRUE(active_tiling->TileAt(1, 0));
-    EXPECT_TRUE(active_tiling->TileAt(0, 1));
-    EXPECT_TRUE(active_tiling->TileAt(1, 1));
-
-    EXPECT_TRUE(pending_tiling->TileAt(0, 0));
-    EXPECT_TRUE(pending_tiling->TileAt(1, 0));
-    EXPECT_TRUE(pending_tiling->TileAt(0, 1));
-    EXPECT_TRUE(pending_tiling->TileAt(1, 1));
-
-    EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
-    EXPECT_TRUE(active_tiling->TileAt(0, 0)->is_shared());
-    EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
-    EXPECT_TRUE(active_tiling->TileAt(1, 0)->is_shared());
-    EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
-    EXPECT_TRUE(active_tiling->TileAt(0, 1)->is_shared());
-    EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
-    EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
-  }
+  EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
+  EXPECT_TRUE(active_tiling->TileAt(0, 0)->is_shared());
+  EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
+  EXPECT_TRUE(active_tiling->TileAt(1, 0)->is_shared());
+  EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
+  EXPECT_TRUE(active_tiling->TileAt(0, 1)->is_shared());
+  EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
+  EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
 }
 
-TEST_F(PictureLayerImplTest, ShareInvalidActiveTreeTilesOnSync) {
-  SetupDefaultTrees(gfx::Size(1500, 1500));
-  AddDefaultTilingsWithInvalidation(gfx::Rect(0, 0, 1, 1));
+TEST_F(PictureLayerImplTest, ShareInvalidActiveTreeTiles) {
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(1500, 1500);
 
-  // This activates the 0,0,1,1 invalidation.
-  host_impl_.ActivateSyncTree();
-  host_impl_.CreatePendingTree();
-  active_layer_ = static_cast<FakePictureLayerImpl*>(
-      host_impl_.active_tree()->LayerById(id_));
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupTreesWithInvalidation(pending_pile, active_pile, gfx::Rect(1, 1));
+  // Activate the invalidation.
+  ActivateTree();
+  // Make another pending tree without any invalidation in it.
+  scoped_refptr<FakePicturePileImpl> pending_pile2 =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupPendingTree(pending_pile2);
 
-  // Force the active tree to sync to the pending tree "post-commit".
-  pending_layer_->DoPostCommitInitializationIfNeeded();
+  EXPECT_GE(active_layer_->num_tilings(), 1u);
+  EXPECT_GE(pending_layer_->num_tilings(), 1u);
 
   // The active tree invalidation was handled by the active tiles, so they
   // can be shared with the pending tree.
-  EXPECT_EQ(3u, active_layer_->num_tilings());
-  EXPECT_EQ(3u, pending_layer_->num_tilings());
-  for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
-    PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(i);
-    PictureLayerTiling* pending_tiling =
-        pending_layer_->tilings()->tiling_at(i);
+  PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(0);
+  PictureLayerTiling* pending_tiling = pending_layer_->tilings()->tiling_at(0);
+  ASSERT_TRUE(active_tiling);
+  ASSERT_TRUE(pending_tiling);
 
-    ASSERT_TRUE(active_tiling);
-    ASSERT_TRUE(pending_tiling);
+  EXPECT_TRUE(active_tiling->TileAt(0, 0));
+  EXPECT_TRUE(active_tiling->TileAt(1, 0));
+  EXPECT_TRUE(active_tiling->TileAt(0, 1));
+  EXPECT_TRUE(active_tiling->TileAt(1, 1));
 
-    EXPECT_TRUE(active_tiling->TileAt(0, 0));
-    EXPECT_TRUE(active_tiling->TileAt(1, 0));
-    EXPECT_TRUE(active_tiling->TileAt(0, 1));
-    EXPECT_TRUE(active_tiling->TileAt(1, 1));
+  EXPECT_TRUE(pending_tiling->TileAt(0, 0));
+  EXPECT_TRUE(pending_tiling->TileAt(1, 0));
+  EXPECT_TRUE(pending_tiling->TileAt(0, 1));
+  EXPECT_TRUE(pending_tiling->TileAt(1, 1));
 
-    EXPECT_TRUE(pending_tiling->TileAt(0, 0));
-    EXPECT_TRUE(pending_tiling->TileAt(1, 0));
-    EXPECT_TRUE(pending_tiling->TileAt(0, 1));
-    EXPECT_TRUE(pending_tiling->TileAt(1, 1));
-
-    EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
-    EXPECT_TRUE(active_tiling->TileAt(0, 0)->is_shared());
-    EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
-    EXPECT_TRUE(active_tiling->TileAt(1, 0)->is_shared());
-    EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
-    EXPECT_TRUE(active_tiling->TileAt(0, 1)->is_shared());
-    EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
-    EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
-  }
+  EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
+  EXPECT_TRUE(active_tiling->TileAt(0, 0)->is_shared());
+  EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
+  EXPECT_TRUE(active_tiling->TileAt(1, 0)->is_shared());
+  EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
+  EXPECT_TRUE(active_tiling->TileAt(0, 1)->is_shared());
+  EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
+  EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
 }
 
-TEST_F(PictureLayerImplTest, RemoveInvalidPendingTreeTilesOnSync) {
-  SetupDefaultTrees(gfx::Size(1500, 1500));
-  AddDefaultTilingsWithInvalidation(gfx::Rect());
+TEST_F(PictureLayerImplTest, RecreateInvalidPendingTreeTiles) {
+  // Set some invalidation on the pending tree. We should replace raster tiles
+  // that touch this.
+  SetupDefaultTreesWithInvalidation(gfx::Size(1500, 1500), gfx::Rect(1, 1));
 
-  host_impl_.ActivateSyncTree();
-  host_impl_.CreatePendingTree();
-  active_layer_ = static_cast<FakePictureLayerImpl*>(
-      host_impl_.active_tree()->LayerById(id_));
-
-  // Set some invalidation on the pending tree "during commit". We should
-  // replace raster tiles that touch this.
-  pending_layer_->set_invalidation(gfx::Rect(1, 1));
-
-  // Force the active tree to sync to the pending tree "post-commit".
-  pending_layer_->DoPostCommitInitializationIfNeeded();
+  EXPECT_GE(active_layer_->num_tilings(), 1u);
+  EXPECT_GE(pending_layer_->num_tilings(), 1u);
 
   // The pending tree invalidation means tiles can not be shared with the
   // active tree.
-  EXPECT_EQ(3u, active_layer_->num_tilings());
-  EXPECT_EQ(3u, pending_layer_->num_tilings());
-  for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
-    PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(i);
-    PictureLayerTiling* pending_tiling =
-        pending_layer_->tilings()->tiling_at(i);
+  PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(0);
+  PictureLayerTiling* pending_tiling = pending_layer_->tilings()->tiling_at(0);
+  ASSERT_TRUE(active_tiling);
+  ASSERT_TRUE(pending_tiling);
 
-    ASSERT_TRUE(active_tiling);
-    ASSERT_TRUE(pending_tiling);
+  EXPECT_TRUE(active_tiling->TileAt(0, 0));
+  EXPECT_TRUE(active_tiling->TileAt(1, 0));
+  EXPECT_TRUE(active_tiling->TileAt(0, 1));
+  EXPECT_TRUE(active_tiling->TileAt(1, 1));
 
-    EXPECT_TRUE(active_tiling->TileAt(0, 0));
-    EXPECT_TRUE(active_tiling->TileAt(1, 0));
-    EXPECT_TRUE(active_tiling->TileAt(0, 1));
-    EXPECT_TRUE(active_tiling->TileAt(1, 1));
+  EXPECT_TRUE(pending_tiling->TileAt(0, 0));
+  EXPECT_TRUE(pending_tiling->TileAt(1, 0));
+  EXPECT_TRUE(pending_tiling->TileAt(0, 1));
+  EXPECT_TRUE(pending_tiling->TileAt(1, 1));
 
-    EXPECT_TRUE(pending_tiling->TileAt(0, 0));
-    EXPECT_TRUE(pending_tiling->TileAt(1, 0));
-    EXPECT_TRUE(pending_tiling->TileAt(0, 1));
-    EXPECT_TRUE(pending_tiling->TileAt(1, 1));
-
-    EXPECT_NE(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
-    EXPECT_FALSE(active_tiling->TileAt(0, 0)->is_shared());
-    EXPECT_FALSE(pending_tiling->TileAt(0, 0)->is_shared());
-    EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
-    EXPECT_TRUE(active_tiling->TileAt(1, 0)->is_shared());
-    EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
-    EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
-    EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
-    EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
-  }
-}
-
-TEST_F(PictureLayerImplTest, SyncTilingAfterReleaseResource) {
-  SetupDefaultTrees(gfx::Size(10, 10));
-  host_impl_.active_tree()->UpdateDrawProperties();
-  EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties());
-
-  // Contrived unit test of a real crash. A layer is transparent during a
-  // context loss, and later becomes opaque, causing active layer SyncTiling to
-  // be called.
-  float new_scale = 1.f;
-  active_layer_->ReleaseResources();
-  pending_layer_->ReleaseResources();
-  EXPECT_FALSE(active_layer_->tilings()->FindTilingWithScale(new_scale));
-  pending_layer_->AddTiling(new_scale);
-  EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(new_scale));
-
-  // UpdateDrawProperties early-outs if the tree doesn't need it.  It is also
-  // responsible for calling ManageTilings.  These checks verify that
-  // ReleaseResources has set needs update draw properties so that the
-  // new tiling gets the appropriate resolution set in ManageTilings.
-  EXPECT_TRUE(host_impl_.active_tree()->needs_update_draw_properties());
-  host_impl_.active_tree()->UpdateDrawProperties();
-  PictureLayerTiling* high_res =
-      active_layer_->tilings()->FindTilingWithScale(new_scale);
-  ASSERT_TRUE(!!high_res);
-  EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
+  EXPECT_NE(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
+  EXPECT_FALSE(active_tiling->TileAt(0, 0)->is_shared());
+  EXPECT_FALSE(pending_tiling->TileAt(0, 0)->is_shared());
+  EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
+  EXPECT_TRUE(active_tiling->TileAt(1, 0)->is_shared());
+  EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
+  EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
+  EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
+  EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
 }
 
 TEST_F(PictureLayerImplTest, SyncTilingAfterGpuRasterizationToggles) {
-  SetupDefaultTrees(gfx::Size(10, 10));
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
-  const float kScale = 1.f;
-  pending_layer_->AddTiling(kScale);
-  EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(kScale));
-  EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(kScale));
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(10, 10);
+
+  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);
+
+  EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.f));
+  EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(1.f));
 
   // Gpu rasterization is disabled by default.
   EXPECT_FALSE(host_impl_.use_gpu_rasterization());
@@ -2346,9 +2290,17 @@
 
   // Make sure that we can still add tiling to the pending layer,
   // that gets synced to the active layer.
-  pending_layer_->AddTiling(kScale);
-  EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(kScale));
-  EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(kScale));
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+  host_impl_.pending_tree()->UpdateDrawProperties();
+  EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.f));
+
+  ActivateTree();
+  EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(1.f));
+
+  SetupPendingTree(pending_pile);
+  EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.f));
 
   // Toggling the gpu rasterization clears all tilings on both trees.
   EXPECT_TRUE(host_impl_.use_gpu_rasterization());
@@ -2360,50 +2312,49 @@
 TEST_F(PictureLayerImplTest, HighResCreatedWhenBoundsShrink) {
   gfx::Size tile_size(100, 100);
 
-  scoped_refptr<FakePicturePileImpl> active_pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(10, 10));
-  SetupPendingTree(active_pile);
-  ActivateTree();
-  host_impl_.active_tree()->UpdateDrawProperties();
-  EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties());
+  // Put 0.5 as high res.
+  host_impl_.SetDeviceScaleFactor(0.5f);
 
-  SetupDrawPropertiesAndUpdateTiles(
-      active_layer_, 0.5f, 0.5f, 0.5f, 0.5f, false);
-  active_layer_->tilings()->RemoveAllTilings();
-  PictureLayerTiling* tiling = active_layer_->AddTiling(0.5f);
-  active_layer_->AddTiling(1.5f);
-  active_layer_->AddTiling(0.25f);
-  tiling->set_resolution(HIGH_RESOLUTION);
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(10, 10));
+  SetupPendingTree(pending_pile);
 
   // Sanity checks.
-  ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
-  ASSERT_EQ(tiling, active_layer_->tilings()->FindTilingWithScale(0.5f));
+  EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+  EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(0.5f));
 
-  // Now, set the bounds to be 1x1 (so that minimum contents scale becomes
-  // 1.0f). Note that we should also ensure that the pending layer needs post
-  // commit initialization, since this is what would happen during commit. In
-  // other words we want the pending layer to sync from the active layer.
-  scoped_refptr<FakePicturePileImpl> pending_pile =
+  ActivateTree();
+
+  // Now, set the bounds to be 1x1, so that minimum contents scale becomes 1.
+  pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1, 1));
   SetupPendingTree(pending_pile);
 
-  // Update the draw properties: sync from active tree should happen here.
-  host_impl_.pending_tree()->UpdateDrawProperties();
-  EXPECT_FALSE(pending_layer_->needs_post_commit_initialization());
-
   // Another sanity check.
-  ASSERT_EQ(1.f, pending_layer_->MinimumContentsScale());
+  EXPECT_EQ(1.f, pending_layer_->MinimumContentsScale());
 
-  // Now we should've synced 1.5f tiling, since that's the only one that doesn't
-  // violate minimum contents scale. At the same time, we should've created a
-  // new high res tiling at scale 1.0f.
+  // Since the MinContentsScale is 1, the 0.5 tiling should be replaced by a 1.0
+  // tiling.
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 0.5f, 1.f, 1.f, 1.f, false);
+
+  EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+  PictureLayerTiling* tiling =
+      pending_layer_->tilings()->FindTilingWithScale(1.0f);
+  ASSERT_TRUE(tiling);
+  EXPECT_EQ(HIGH_RESOLUTION, tiling->resolution());
+}
+
+TEST_F(PictureLayerImplTest, LowResTilingWithoutGpuRasterization) {
+  gfx::Size default_tile_size(host_impl_.settings().default_tile_size);
+  gfx::Size layer_bounds(default_tile_size.width() * 4,
+                         default_tile_size.height() * 4);
+
+  host_impl_.SetUseGpuRasterization(false);
+
+  SetupDefaultTrees(layer_bounds);
+  EXPECT_FALSE(host_impl_.use_gpu_rasterization());
+  // Should have a low-res and a high-res tiling.
   EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
-  ASSERT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.0f));
-  EXPECT_EQ(HIGH_RESOLUTION,
-            pending_layer_->tilings()->FindTilingWithScale(1.0f)->resolution());
-  ASSERT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.5f));
-  EXPECT_EQ(NON_IDEAL_RESOLUTION,
-            pending_layer_->tilings()->FindTilingWithScale(1.5f)->resolution());
 }
 
 TEST_F(PictureLayerImplTest, NoLowResTilingWithGpuRasterization) {
@@ -2411,21 +2362,12 @@
   gfx::Size layer_bounds(default_tile_size.width() * 4,
                          default_tile_size.height() * 4);
 
-  SetupDefaultTrees(layer_bounds);
-  EXPECT_FALSE(host_impl_.use_gpu_rasterization());
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
-  // Should have a low-res and a high-res tiling.
-  ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
-
-  ResetTilingsAndRasterScales();
-
   host_impl_.SetUseGpuRasterization(true);
-  EXPECT_TRUE(host_impl_.use_gpu_rasterization());
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
 
+  SetupDefaultTrees(layer_bounds);
+  EXPECT_TRUE(host_impl_.use_gpu_rasterization());
   // Should only have the high-res tiling.
-  ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
+  EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
 }
 
 TEST_F(PictureLayerImplTest, NoTilingIfDoesNotDrawContent) {
@@ -2450,31 +2392,38 @@
 
 TEST_F(PictureLayerImplTest, FirstTilingDuringPinch) {
   SetupDefaultTrees(gfx::Size(10, 10));
+
+  // We start with a tiling at scale 1.
+  EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
+
+  // When we scale up by 2.3, we get a new tiling that is a power of 2, in this
+  // case 4.
   host_impl_.PinchGestureBegin();
   float high_res_scale = 2.3f;
   SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, 1.f, false);
-
-  ASSERT_GE(pending_layer_->num_tilings(), 0u);
-  EXPECT_FLOAT_EQ(high_res_scale,
-                  pending_layer_->HighResTiling()->contents_scale());
-}
-
-TEST_F(PictureLayerImplTest, FirstTilingTooSmall) {
-  SetupDefaultTrees(gfx::Size(10, 10));
-  host_impl_.PinchGestureBegin();
-  float high_res_scale = 0.0001f;
-  EXPECT_GT(pending_layer_->MinimumContentsScale(), high_res_scale);
-
-  SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, 1.f, false);
-
-  ASSERT_GE(pending_layer_->num_tilings(), 0u);
-  EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
-                  pending_layer_->HighResTiling()->contents_scale());
+  EXPECT_EQ(4.f, pending_layer_->HighResTiling()->contents_scale());
 }
 
 TEST_F(PictureLayerImplTest, PinchingTooSmall) {
   SetupDefaultTrees(gfx::Size(10, 10));
 
+  // We start with a tiling at scale 1.
+  EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
+
+  host_impl_.PinchGestureBegin();
+  float high_res_scale = 0.0001f;
+  EXPECT_LT(high_res_scale, pending_layer_->MinimumContentsScale());
+
+  SetContentsScaleOnBothLayers(high_res_scale, 1.f, high_res_scale, 1.f, false);
+  EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
+                  pending_layer_->HighResTiling()->contents_scale());
+}
+
+TEST_F(PictureLayerImplTest, PinchingTooSmallWithContentsScale) {
+  SetupDefaultTrees(gfx::Size(10, 10));
+
+  ResetTilingsAndRasterScales();
+
   float contents_scale = 0.15f;
   SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f, 1.f, false);
 
@@ -2542,22 +2491,18 @@
 }
 
 TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
-  gfx::Size layer_bounds(100, 100);
   gfx::Size viewport_size(1000, 1000);
-  SetupDefaultTrees(layer_bounds);
   host_impl_.SetViewportSize(viewport_size);
 
+  gfx::Size layer_bounds(100, 100);
+  SetupDefaultTrees(layer_bounds);
+
   float contents_scale = 1.f;
-  float device_scale = 1.3f;
-  float page_scale = 1.4f;
+  float device_scale = 1.f;
+  float page_scale = 1.f;
   float maximum_animation_scale = 1.f;
   bool animating_transform = false;
 
-  SetContentsScaleOnBothLayers(contents_scale,
-                               device_scale,
-                               page_scale,
-                               maximum_animation_scale,
-                               animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
 
   // Since we're CPU-rasterizing, starting an animation should cause tiling
@@ -2781,6 +2726,8 @@
   host_impl_.SetCurrentBeginFrameArgs(
       CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
 
+  host_impl_.SetViewportSize(gfx::Size(500, 500));
+
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
 
@@ -2788,24 +2735,10 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
   SetupPendingTree(pending_pile);
+  EXPECT_EQ(2u, pending_layer_->num_tilings());
 
-  ASSERT_TRUE(pending_layer_->CanHaveTilings());
-
-  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
-
-  // No tilings.
   scoped_ptr<TilingSetRasterQueue> queue =
       pending_layer_->CreateRasterQueue(false);
-  EXPECT_TRUE(queue->IsEmpty());
-
-  pending_layer_->AddTiling(low_res_factor);
-  pending_layer_->AddTiling(0.3f);
-  pending_layer_->AddTiling(0.7f);
-  PictureLayerTiling* high_res_tiling = pending_layer_->AddTiling(1.0f);
-  pending_layer_->AddTiling(2.0f);
-
-  host_impl_.SetViewportSize(gfx::Size(500, 500));
-  host_impl_.pending_tree()->UpdateDrawProperties();
 
   std::set<Tile*> unique_tiles;
   bool reached_prepaint = false;
@@ -2883,7 +2816,8 @@
       gfx::Rect(0, 0, 500, 500);
   pending_layer_->UpdateTiles(Occlusion(), resourceless_software_draw);
 
-  std::vector<Tile*> high_res_tiles = high_res_tiling->AllTilesForTesting();
+  std::vector<Tile*> high_res_tiles =
+      pending_layer_->HighResTiling()->AllTilesForTesting();
   for (std::vector<Tile*>::iterator tile_it = high_res_tiles.begin();
        tile_it != high_res_tiles.end();
        ++tile_it) {
@@ -2916,33 +2850,23 @@
 TEST_F(PictureLayerImplTest, TilingSetEvictionQueue) {
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
+  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+
+  host_impl_.SetViewportSize(gfx::Size(500, 500));
 
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
+  // TODO(vmpstr): Add a test with tilings other than high/low res on the active
+  // tree.
   SetupPendingTree(pending_pile);
-
-  ASSERT_TRUE(pending_layer_->CanHaveTilings());
-
-  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
-
-  std::vector<PictureLayerTiling*> tilings;
-  tilings.push_back(pending_layer_->AddTiling(low_res_factor));
-  tilings.push_back(pending_layer_->AddTiling(0.3f));
-  tilings.push_back(pending_layer_->AddTiling(0.7f));
-  tilings.push_back(pending_layer_->AddTiling(1.0f));
-  tilings.push_back(pending_layer_->AddTiling(2.0f));
-
-  host_impl_.SetViewportSize(gfx::Size(500, 500));
-  host_impl_.pending_tree()->UpdateDrawProperties();
+  EXPECT_EQ(2u, pending_layer_->num_tilings());
 
   std::vector<Tile*> all_tiles;
-  for (std::vector<PictureLayerTiling*>::iterator tiling_iterator =
-           tilings.begin();
-       tiling_iterator != tilings.end();
-       ++tiling_iterator) {
-    std::vector<Tile*> tiles = (*tiling_iterator)->AllTilesForTesting();
-    std::copy(tiles.begin(), tiles.end(), std::back_inserter(all_tiles));
+  for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+    std::vector<Tile*> tiles = tiling->AllTilesForTesting();
+    all_tiles.insert(all_tiles.end(), tiles.begin(), tiles.end());
   }
 
   std::set<Tile*> all_tiles_set(all_tiles.begin(), all_tiles.end());
@@ -2950,8 +2874,8 @@
   bool mark_required = false;
   size_t number_of_marked_tiles = 0u;
   size_t number_of_unmarked_tiles = 0u;
-  for (size_t i = 0; i < tilings.size(); ++i) {
-    PictureLayerTiling* tiling = tilings.at(i);
+  for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
     for (PictureLayerTiling::CoverageIterator iter(
              tiling,
              pending_layer_->contents_scale_x(),
@@ -2969,8 +2893,8 @@
   }
 
   // Sanity checks.
-  EXPECT_EQ(91u, all_tiles.size());
-  EXPECT_EQ(91u, all_tiles_set.size());
+  EXPECT_EQ(17u, all_tiles.size());
+  EXPECT_EQ(17u, all_tiles_set.size());
   EXPECT_GT(number_of_marked_tiles, 1u);
   EXPECT_GT(number_of_unmarked_tiles, 1u);
 
@@ -2982,10 +2906,12 @@
   host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
 
   std::set<Tile*> unique_tiles;
-  float expected_scales[] = {2.0f, 0.3f, 0.7f, low_res_factor, 1.0f};
+  float expected_scales[] = {low_res_factor, 1.f};
   size_t scale_index = 0;
   bool reached_visible = false;
   Tile* last_tile = nullptr;
+  size_t distance_decreasing = 0;
+  size_t distance_increasing = 0;
   queue = pending_layer_->CreateEvictionQueue(SAME_PRIORITY_FOR_BOTH_TREES);
   while (!queue->IsEmpty()) {
     Tile* tile = queue->Top();
@@ -3013,24 +2939,28 @@
     EXPECT_FLOAT_EQ(tile->contents_scale(), expected_scales[scale_index]);
     unique_tiles.insert(tile);
 
-    // If the tile is the same rough bin as last tile (same activation, bin, and
-    // scale), then distance should be decreasing.
     if (tile->required_for_activation() ==
             last_tile->required_for_activation() &&
         priority.priority_bin ==
             last_tile->priority(PENDING_TREE).priority_bin &&
         std::abs(tile->contents_scale() - last_tile->contents_scale()) <
             std::numeric_limits<float>::epsilon()) {
-      EXPECT_LE(priority.distance_to_visible,
-                last_tile->priority(PENDING_TREE).distance_to_visible);
+      if (priority.distance_to_visible <=
+          last_tile->priority(PENDING_TREE).distance_to_visible)
+        ++distance_decreasing;
+      else
+        ++distance_increasing;
     }
 
     last_tile = tile;
     queue->Pop();
   }
 
+  // 4 high res tiles are inside the viewport, the rest are evicted.
   EXPECT_TRUE(reached_visible);
-  EXPECT_EQ(65u, unique_tiles.size());
+  EXPECT_EQ(12u, unique_tiles.size());
+  EXPECT_EQ(1u, distance_increasing);
+  EXPECT_EQ(11u, distance_decreasing);
 
   scale_index = 0;
   bool reached_required = false;
@@ -3069,16 +2999,12 @@
   gfx::Size viewport_size(1000, 1000);
 
   LayerTestCommon::LayerImplTest impl;
+  host_impl_.SetViewportSize(viewport_size);
 
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(layer_bounds, layer_bounds);
-  SetupPendingTree(pending_pile);
-  pending_layer_->SetBounds(layer_bounds);
+  SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
   ActivateTree();
-  active_layer_->set_fixed_tile_size(tile_size);
-
-  host_impl_.SetViewportSize(viewport_size);
-  host_impl_.active_tree()->UpdateDrawProperties();
 
   std::vector<Tile*> tiles =
       active_layer_->HighResTiling()->AllTilesForTesting();
@@ -3121,6 +3047,8 @@
   gfx::Size tile_size(host_impl_.settings().default_tile_size);
   SetupDefaultTrees(tile_size);
 
+  ResetTilingsAndRasterScales();
+
   float contents_scale = 2.f;
   float device_scale = 1.f;
   float page_scale = 1.f;
@@ -3161,15 +3089,9 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
-  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
   // Make sure some tiles are not shared.
-  pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
-
-  CreateHighLowResAndSetAllTilesVisible();
-  active_layer_->SetAllTilesReady();
+  gfx::Rect invalidation(gfx::Point(50, 50), tile_size);
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, invalidation);
 
   // All pending layer tiles required are not ready.
   EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
@@ -3190,15 +3112,9 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
-  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
   // Make sure some tiles are not shared.
-  pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
-
-  CreateHighLowResAndSetAllTilesVisible();
-  active_layer_->SetAllTilesReady();
+  gfx::Rect invalidation(gfx::Point(50, 50), tile_size);
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, invalidation);
 
   // All pending layer tiles required are not ready.
   EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
@@ -3215,14 +3131,9 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
-  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
   // Make sure some tiles are not shared.
-  pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
-
-  CreateHighLowResAndSetAllTilesVisible();
+  gfx::Rect invalidation(gfx::Point(50, 50), tile_size);
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, invalidation);
 
   // Initialize all high-res tiles in the active layer.
   active_layer_->SetAllTilesReadyInTiling(active_layer_->HighResTiling());
@@ -3241,14 +3152,9 @@
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(1000, 1000);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
-  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
   // Make sure some tiles are not shared.
-  pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
-
-  CreateHighLowResAndSetAllTilesVisible();
+  gfx::Rect invalidation(gfx::Point(50, 50), tile_size);
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, invalidation);
 
   // Initialize all high-res tiles in the active layer.
   active_layer_->SetAllTilesReadyInTiling(active_layer_->HighResTiling());
@@ -3261,12 +3167,6 @@
   EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
 }
 
-class NoLowResPictureLayerImplTest : public PictureLayerImplTest {
- public:
-  NoLowResPictureLayerImplTest()
-      : PictureLayerImplTest(NoLowResTilingsSettings()) {}
-};
-
 TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
   gfx::Size tile_size(400, 400);
   gfx::Size layer_bounds(1300, 1900);
@@ -3277,11 +3177,73 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
   SetupTrees(pending_pile, active_pile);
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
 
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
   EXPECT_LT(low_res_factor, 1.f);
 
+  ResetTilingsAndRasterScales();
+
+  SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                    6.f,  // ideal contents scale
+                                    3.f,  // device scale
+                                    2.f,  // page scale
+                                    1.f,  // maximum animation scale
+                                    false);
+  ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(6.f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+
+  // If we change the page scale factor, then we should get new tilings.
+  SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                    6.6f,  // ideal contents scale
+                                    3.f,   // device scale
+                                    2.2f,  // page scale
+                                    1.f,   // maximum animation scale
+                                    false);
+  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(6.6f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+
+  // If we change the device scale factor, then we should get new tilings.
+  SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                    7.26f,  // ideal contents scale
+                                    3.3f,   // device scale
+                                    2.2f,   // page scale
+                                    1.f,    // maximum animation scale
+                                    false);
+  ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(7.26f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+
+  // If we change the device scale factor, but end up at the same total scale
+  // factor somehow, then we don't get new tilings.
+  SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                    7.26f,  // ideal contents scale
+                                    2.2f,   // device scale
+                                    3.3f,   // page scale
+                                    1.f,    // maximum animation scale
+                                    false);
+  ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(7.26f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, PendingLayerOnlyHasHighResTiling) {
+  gfx::Size tile_size(400, 400);
+  gfx::Size layer_bounds(1300, 1900);
+
+  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;
+  EXPECT_LT(low_res_factor, 1.f);
+
+  ResetTilingsAndRasterScales();
+
   SetupDrawPropertiesAndUpdateTiles(pending_layer_,
                                     6.f,  // ideal contents scale
                                     3.f,  // device scale
@@ -3299,7 +3261,7 @@
                                     2.2f,  // page scale
                                     1.f,   // maximum animation scale
                                     false);
-  ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
+  ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(6.6f,
                   pending_layer_->tilings()->tiling_at(0)->contents_scale());
 
@@ -3310,7 +3272,7 @@
                                     2.2f,   // page scale
                                     1.f,    // maximum animation scale
                                     false);
-  ASSERT_EQ(3u, pending_layer_->tilings()->num_tilings());
+  ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(7.26f,
                   pending_layer_->tilings()->tiling_at(0)->contents_scale());
 
@@ -3322,7 +3284,7 @@
                                     3.3f,   // page scale
                                     1.f,    // maximum animation scale
                                     false);
-  ASSERT_EQ(3u, pending_layer_->tilings()->num_tilings());
+  ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(7.26f,
                   pending_layer_->tilings()->tiling_at(0)->contents_scale());
 }
@@ -3331,11 +3293,7 @@
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
 
-  host_impl_.SetViewportSize(layer_bounds);
-
-  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
-
-  CreateHighLowResAndSetAllTilesVisible();
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
 
   Tile* some_active_tile =
       active_layer_->HighResTiling()->AllTilesForTesting()[0];
@@ -3355,6 +3313,7 @@
 TEST_F(NoLowResPictureLayerImplTest, NothingRequiredIfActiveMissingTiles) {
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
+
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   // This pile will create tilings, but has no recordings so will not create any
@@ -3364,11 +3323,8 @@
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
           tile_size, layer_bounds);
-  SetupTrees(pending_pile, active_pile);
-  pending_layer_->set_fixed_tile_size(tile_size);
-  active_layer_->set_fixed_tile_size(tile_size);
 
-  CreateHighLowResAndSetAllTilesVisible();
+  SetupTreesWithFixedTileSize(pending_pile, active_pile, tile_size, Region());
 
   // Active layer has tilings, but no tiles due to missing recordings.
   EXPECT_TRUE(active_layer_->CanHaveTilings());
@@ -3401,10 +3357,8 @@
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  SetupTrees(pending_pile, active_pile);
+  SetupTreesWithInvalidation(pending_pile, active_pile, Region());
 
-  Region invalidation;
-  AddDefaultTilingsWithInvalidation(invalidation);
   SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
 
   // UpdateTiles with valid viewport. Should update tile viewport.
@@ -3484,7 +3438,6 @@
   std::vector<PictureLayerTiling*> used_tilings;
 
   SetupTrees(pending_pile, active_pile);
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
 
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
   EXPECT_LT(low_res_factor, 1.f);
@@ -3493,6 +3446,8 @@
   float page_scale = 3.2f;
   float scale = 1.f;
 
+  ResetTilingsAndRasterScales();
+
   SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
   ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
 
@@ -3578,80 +3533,6 @@
   ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
 }
 
-TEST_F(PictureLayerImplTest, ScaleCollision) {
-  gfx::Size tile_size(400, 400);
-  gfx::Size layer_bounds(1300, 1900);
-
-  scoped_refptr<FakePicturePileImpl> pending_pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  scoped_refptr<FakePicturePileImpl> active_pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
-  std::vector<PictureLayerTiling*> used_tilings;
-
-  SetupTrees(pending_pile, active_pile);
-
-  float pending_contents_scale = 1.f;
-  float active_contents_scale = 2.f;
-  float device_scale_factor = 1.f;
-  float page_scale_factor = 1.f;
-  float maximum_animation_contents_scale = 1.f;
-  bool animating_transform = false;
-
-  EXPECT_TRUE(host_impl_.settings().create_low_res_tiling);
-  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
-  EXPECT_LT(low_res_factor, 1.f);
-
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
-                                    pending_contents_scale,
-                                    device_scale_factor,
-                                    page_scale_factor,
-                                    maximum_animation_contents_scale,
-                                    animating_transform);
-  SetupDrawPropertiesAndUpdateTiles(active_layer_,
-                                    active_contents_scale,
-                                    device_scale_factor,
-                                    page_scale_factor,
-                                    maximum_animation_contents_scale,
-                                    animating_transform);
-
-  ASSERT_EQ(4u, pending_layer_->tilings()->num_tilings());
-  ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
-
-  EXPECT_EQ(active_contents_scale,
-            pending_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_EQ(pending_contents_scale,
-            pending_layer_->tilings()->tiling_at(1)->contents_scale());
-  EXPECT_EQ(active_contents_scale * low_res_factor,
-            pending_layer_->tilings()->tiling_at(2)->contents_scale());
-  EXPECT_EQ(pending_contents_scale * low_res_factor,
-            pending_layer_->tilings()->tiling_at(3)->contents_scale());
-
-  EXPECT_EQ(active_contents_scale,
-            active_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_EQ(pending_contents_scale,
-            active_layer_->tilings()->tiling_at(1)->contents_scale());
-  EXPECT_EQ(active_contents_scale * low_res_factor,
-            active_layer_->tilings()->tiling_at(2)->contents_scale());
-  EXPECT_EQ(pending_contents_scale * low_res_factor,
-            active_layer_->tilings()->tiling_at(3)->contents_scale());
-
-  // The unused low res tiling from the pending tree must be kept or we may add
-  // it again on the active tree and collide with the pending tree.
-  used_tilings.push_back(active_layer_->tilings()->tiling_at(1));
-  active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
-  ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
-
-  EXPECT_EQ(active_contents_scale,
-            active_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_EQ(pending_contents_scale,
-            active_layer_->tilings()->tiling_at(1)->contents_scale());
-  EXPECT_EQ(active_contents_scale * low_res_factor,
-            active_layer_->tilings()->tiling_at(2)->contents_scale());
-  EXPECT_EQ(pending_contents_scale * low_res_factor,
-            active_layer_->tilings()->tiling_at(3)->contents_scale());
-}
-
 TEST_F(NoLowResPictureLayerImplTest, ReleaseResources) {
   gfx::Size tile_size(400, 400);
   gfx::Size layer_bounds(1300, 1900);
@@ -3662,15 +3543,8 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
   SetupTrees(pending_pile, active_pile);
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
-                                    1.3f,  // ideal contents scale
-                                    2.7f,  // device scale
-                                    3.2f,  // page scale
-                                    1.f,   // maximum animation scale
-                                    false);
   EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+  EXPECT_EQ(1u, active_layer_->tilings()->num_tilings());
 
   // All tilings should be removed when losing output surface.
   active_layer_->ReleaseResources();
@@ -3694,7 +3568,7 @@
   gfx::Size tile_size(400, 400);
   gfx::Size layer_bounds(1000, 2000);
 
-  host_impl_.SetViewportSize(layer_bounds);
+  host_impl_.SetViewportSize(gfx::Size(10000, 20000));
 
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
@@ -3703,14 +3577,12 @@
 
   SetupTrees(pending_pile, active_pile);
 
-  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 2.5f, 1.f, 1.f, 1.f, false);
-  host_impl_.pending_tree()->UpdateDrawProperties();
-
-  active_layer_->draw_properties().visible_content_rect =
-      gfx::Rect(layer_bounds);
-  host_impl_.active_tree()->UpdateDrawProperties();
+  ResetTilingsAndRasterScales();
+  SetupDrawPropertiesAndUpdateTiles(active_layer_, 2.5f, 1.f, 1.f, 1.f, false);
 
   float max_contents_scale = active_layer_->MaximumTilingContentsScale();
+  EXPECT_EQ(2.5f, max_contents_scale);
+
   gfx::Transform scaled_draw_transform = active_layer_->draw_transform();
   scaled_draw_transform.Scale(SK_MScalar1 / max_contents_scale,
                               SK_MScalar1 / max_contents_scale);
@@ -3747,40 +3619,35 @@
 
   scoped_ptr<FakePictureLayerImpl> layer_with_mask =
       FakePictureLayerImpl::Create(host_impl_.pending_tree(), 2);
-
   layer_with_mask->SetBounds(bounds);
   layer_with_mask->SetContentBounds(bounds);
 
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, bounds);
   scoped_ptr<FakePictureLayerImpl> mask =
-      FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 3,
-                                                   pending_pile);
-  mask->set_is_mask(true);
-
+      FakePictureLayerImpl::CreateMaskWithRasterSource(
+          host_impl_.pending_tree(), 3, pending_pile);
   mask->SetBounds(bounds);
   mask->SetContentBounds(bounds);
   mask->SetDrawsContent(true);
-
-  FakePictureLayerImpl* pending_mask_content = mask.get();
   layer_with_mask->SetMaskLayer(mask.Pass());
 
+  FakePictureLayerImpl* pending_mask =
+      static_cast<FakePictureLayerImpl*>(layer_with_mask->mask_layer());
+
   scoped_ptr<FakePictureLayerImpl> child_of_layer_with_mask =
       FakePictureLayerImpl::Create(host_impl_.pending_tree(), 4);
-
   child_of_layer_with_mask->SetBounds(bounds);
   child_of_layer_with_mask->SetContentBounds(bounds);
   child_of_layer_with_mask->SetDrawsContent(true);
-
   layer_with_mask->AddChild(child_of_layer_with_mask.Pass());
-
   root->AddChild(layer_with_mask.Pass());
 
   host_impl_.pending_tree()->SetRootLayer(root.Pass());
 
-  EXPECT_FALSE(pending_mask_content->tilings());
+  EXPECT_EQ(0u, pending_mask->num_tilings());
   host_impl_.pending_tree()->UpdateDrawProperties();
-  EXPECT_NE(0u, pending_mask_content->num_tilings());
+  EXPECT_NE(0u, pending_mask->num_tilings());
 }
 
 class PictureLayerImplTestWithDelegatingRenderer : public PictureLayerImplTest {
@@ -3804,7 +3671,6 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   SetupPendingTree(pending_pile);
   pending_layer_->SetBounds(layer_bounds);
-  host_impl_.SetViewportSize(layer_bounds);
   ActivateTree();
   host_impl_.active_tree()->UpdateDrawProperties();
   std::vector<Tile*> tiles =
@@ -3851,14 +3717,17 @@
   OcclusionTrackingPictureLayerImplTest()
       : PictureLayerImplTest(OcclusionTrackingSettings()) {}
 
-  void VerifyEvictionConsidersOcclusion(
-      PictureLayerImpl* layer,
-      size_t expected_occluded_tile_count[NUM_TREE_PRIORITIES]) {
+  void VerifyEvictionConsidersOcclusion(FakePictureLayerImpl* layer,
+                                        FakePictureLayerImpl* twin_layer,
+                                        WhichTree tree,
+                                        size_t expected_occluded_tile_count) {
+    WhichTree twin_tree = tree == ACTIVE_TREE ? PENDING_TREE : ACTIVE_TREE;
     for (int priority_count = 0; priority_count < NUM_TREE_PRIORITIES;
          ++priority_count) {
       TreePriority tree_priority = static_cast<TreePriority>(priority_count);
       size_t occluded_tile_count = 0u;
       Tile* last_tile = nullptr;
+      std::set<Tile*> shared_tiles;
 
       scoped_ptr<TilingSetEvictionQueue> queue =
           layer->CreateEvictionQueue(tree_priority);
@@ -3866,23 +3735,22 @@
         Tile* tile = queue->Top();
         if (!last_tile)
           last_tile = tile;
+        if (tile->is_shared())
+          EXPECT_TRUE(shared_tiles.insert(tile).second);
 
         // The only way we will encounter an occluded tile after an unoccluded
         // tile is if the priorty bin decreased, the tile is required for
         // activation, or the scale changed.
-        bool tile_is_occluded =
-            tile->is_occluded_for_tree_priority(tree_priority);
+        bool tile_is_occluded = tile->is_occluded(tree);
         if (tile_is_occluded) {
           occluded_tile_count++;
 
-          bool last_tile_is_occluded =
-              last_tile->is_occluded_for_tree_priority(tree_priority);
+          bool last_tile_is_occluded = last_tile->is_occluded(tree);
           if (!last_tile_is_occluded) {
             TilePriority::PriorityBin tile_priority_bin =
-                tile->priority_for_tree_priority(tree_priority).priority_bin;
+                tile->priority(tree).priority_bin;
             TilePriority::PriorityBin last_tile_priority_bin =
-                last_tile->priority_for_tree_priority(tree_priority)
-                    .priority_bin;
+                last_tile->priority(tree).priority_bin;
 
             EXPECT_TRUE(
                 (tile_priority_bin < last_tile_priority_bin) ||
@@ -3893,8 +3761,74 @@
         last_tile = tile;
         queue->Pop();
       }
-      EXPECT_EQ(expected_occluded_tile_count[priority_count],
-                occluded_tile_count);
+      // Count also shared tiles which are occluded in the tree but which were
+      // not returned by the tiling set eviction queue. Those shared tiles
+      // shall be returned by the twin tiling set eviction queue.
+      queue = twin_layer->CreateEvictionQueue(tree_priority);
+      while (!queue->IsEmpty()) {
+        Tile* tile = queue->Top();
+        if (tile->is_shared()) {
+          EXPECT_TRUE(shared_tiles.insert(tile).second);
+          if (tile->is_occluded(tree))
+            ++occluded_tile_count;
+          // Check the reasons why the shared tile was not returned by
+          // the first tiling set eviction queue.
+          switch (tree_priority) {
+            case SAME_PRIORITY_FOR_BOTH_TREES: {
+              const TilePriority& priority = tile->priority(tree);
+              const TilePriority& priority_for_tree_priority =
+                  tile->priority_for_tree_priority(tree_priority);
+              const TilePriority& twin_priority = tile->priority(twin_tree);
+              // Check if the shared tile was not returned by the first tiling
+              // set eviction queue because it was out of order for the first
+              // tiling set eviction queue but not for the twin tiling set
+              // eviction queue.
+              if (priority.priority_bin != twin_priority.priority_bin) {
+                EXPECT_LT(priority_for_tree_priority.priority_bin,
+                          priority.priority_bin);
+                EXPECT_EQ(priority_for_tree_priority.priority_bin,
+                          twin_priority.priority_bin);
+                EXPECT_TRUE(priority_for_tree_priority.priority_bin <
+                            priority.priority_bin);
+              } else if (tile->is_occluded(tree) !=
+                         tile->is_occluded(twin_tree)) {
+                EXPECT_TRUE(tile->is_occluded(tree));
+                EXPECT_FALSE(tile->is_occluded(twin_tree));
+                EXPECT_FALSE(
+                    tile->is_occluded_for_tree_priority(tree_priority));
+              } else if (priority.distance_to_visible !=
+                         twin_priority.distance_to_visible) {
+                EXPECT_LT(priority_for_tree_priority.distance_to_visible,
+                          priority.distance_to_visible);
+                EXPECT_EQ(priority_for_tree_priority.distance_to_visible,
+                          twin_priority.distance_to_visible);
+                EXPECT_TRUE(priority_for_tree_priority.distance_to_visible <
+                            priority.distance_to_visible);
+              } else {
+                // Shared tiles having the same active and pending priorities
+                // should be returned only by a pending tree eviction queue.
+                EXPECT_EQ(ACTIVE_TREE, tree);
+              }
+              break;
+            }
+            case SMOOTHNESS_TAKES_PRIORITY:
+              // Shared tiles should be returned only by an active tree
+              // eviction queue.
+              EXPECT_EQ(PENDING_TREE, tree);
+              break;
+            case NEW_CONTENT_TAKES_PRIORITY:
+              // Shared tiles should be returned only by a pending tree
+              // eviction queue.
+              EXPECT_EQ(ACTIVE_TREE, tree);
+              break;
+            case NUM_TREE_PRIORITIES:
+              NOTREACHED();
+              break;
+          }
+        }
+        queue->Pop();
+      }
+      EXPECT_EQ(expected_occluded_tile_count, occluded_tile_count);
     }
   }
 };
@@ -3911,13 +3845,11 @@
   gfx::Size viewport_size(500, 500);
   gfx::Point occluding_layer_position(310, 0);
 
+  host_impl_.SetViewportSize(viewport_size);
+
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  SetupPendingTree(pending_pile);
-  pending_layer_->set_fixed_tile_size(tile_size);
-
-  host_impl_.SetViewportSize(viewport_size);
-  host_impl_.pending_tree()->UpdateDrawProperties();
+  SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
 
   // No occlusion.
   int unoccluded_tile_count = 0;
@@ -4004,13 +3936,11 @@
   gfx::Size viewport_size(500, 500);
   gfx::Point occluding_layer_position(310, 0);
 
+  host_impl_.SetViewportSize(viewport_size);
+
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  SetupPendingTree(pending_pile);
-  pending_layer_->set_fixed_tile_size(tile_size);
-
-  host_impl_.SetViewportSize(viewport_size);
-  host_impl_.pending_tree()->UpdateDrawProperties();
+  SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
 
   // No occlusion.
   int occluded_tile_count = 0;
@@ -4125,6 +4055,11 @@
 }
 
 TEST_F(OcclusionTrackingPictureLayerImplTest, OcclusionForDifferentScales) {
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
   gfx::Size tile_size(102, 102);
   gfx::Size layer_bounds(1000, 1000);
   gfx::Size viewport_size(500, 500);
@@ -4132,20 +4067,12 @@
 
   scoped_refptr<FakePicturePileImpl> pending_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  SetupPendingTree(pending_pile);
-  pending_layer_->set_fixed_tile_size(tile_size);
 
+  host_impl_.SetViewportSize(viewport_size);
+
+  SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, Region());
   ASSERT_TRUE(pending_layer_->CanHaveTilings());
 
-  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
-
-  std::vector<PictureLayerTiling*> tilings;
-  tilings.push_back(pending_layer_->AddTiling(low_res_factor));
-  tilings.push_back(pending_layer_->AddTiling(0.3f));
-  tilings.push_back(pending_layer_->AddTiling(0.7f));
-  tilings.push_back(pending_layer_->AddTiling(1.0f));
-  tilings.push_back(pending_layer_->AddTiling(2.0f));
-
   pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 1));
   LayerImpl* layer1 = pending_layer_->children()[0];
   layer1->SetBounds(layer_bounds);
@@ -4154,49 +4081,56 @@
   layer1->SetContentsOpaque(true);
   layer1->SetPosition(occluding_layer_position);
 
-  host_impl_.SetViewportSize(viewport_size);
+  pending_layer_->tilings()->RemoveAllTilings();
+  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+  pending_layer_->AddTiling(low_res_factor);
+  pending_layer_->AddTiling(0.3f);
+  pending_layer_->AddTiling(0.7f);
+  pending_layer_->AddTiling(1.0f);
+  pending_layer_->AddTiling(2.0f);
+
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+  // UpdateDrawProperties with the occluding layer.
   host_impl_.pending_tree()->UpdateDrawProperties();
 
-  int tiling_count = 0;
+  EXPECT_EQ(5u, pending_layer_->num_tilings());
+
   int occluded_tile_count = 0;
-  for (std::vector<PictureLayerTiling*>::iterator tiling_iterator =
-           tilings.begin();
-       tiling_iterator != tilings.end();
-       ++tiling_iterator) {
-    (*tiling_iterator)->UpdateAllTilePrioritiesForTesting();
-    std::vector<Tile*> tiles = (*tiling_iterator)->AllTilesForTesting();
+  for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+    tiling->UpdateAllTilePrioritiesForTesting();
+    std::vector<Tile*> tiles = tiling->AllTilesForTesting();
 
     occluded_tile_count = 0;
-    for (size_t i = 0; i < tiles.size(); ++i) {
-      if (tiles[i]->is_occluded(PENDING_TREE)) {
+    for (size_t j = 0; j < tiles.size(); ++j) {
+      if (tiles[j]->is_occluded(PENDING_TREE)) {
         gfx::Rect scaled_content_rect = ScaleToEnclosingRect(
-            tiles[i]->content_rect(), 1.0f / tiles[i]->contents_scale());
+            tiles[j]->content_rect(), 1.0f / tiles[j]->contents_scale());
         EXPECT_GE(scaled_content_rect.x(), occluding_layer_position.x());
         occluded_tile_count++;
       }
     }
-    switch (tiling_count) {
+
+    switch (i) {
       case 0:
+        EXPECT_EQ(occluded_tile_count, 30);
+        break;
       case 1:
-        EXPECT_EQ(occluded_tile_count, 2);
+        EXPECT_EQ(occluded_tile_count, 5);
         break;
       case 2:
         EXPECT_EQ(occluded_tile_count, 4);
         break;
-      case 3:
-        EXPECT_EQ(occluded_tile_count, 5);
-        break;
       case 4:
-        EXPECT_EQ(occluded_tile_count, 30);
+      case 3:
+        EXPECT_EQ(occluded_tile_count, 2);
         break;
       default:
         NOTREACHED();
     }
-
-    tiling_count++;
   }
-
-  EXPECT_EQ(tiling_count, 5);
 }
 
 TEST_F(OcclusionTrackingPictureLayerImplTest, DifferentOcclusionOnTrees) {
@@ -4210,24 +4144,23 @@
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-  SetupTrees(pending_pile, active_pile);
+
+  host_impl_.SetViewportSize(viewport_size);
+  SetupPendingTree(active_pile);
 
   // Partially occlude the active layer.
-  active_layer_->AddChild(LayerImpl::Create(host_impl_.active_tree(), 2));
-  LayerImpl* layer1 = active_layer_->children()[0];
+  pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 2));
+  LayerImpl* layer1 = pending_layer_->children()[0];
   layer1->SetBounds(layer_bounds);
   layer1->SetContentBounds(layer_bounds);
   layer1->SetDrawsContent(true);
   layer1->SetContentsOpaque(true);
   layer1->SetPosition(occluding_layer_position);
 
+  ActivateTree();
+
   // Partially invalidate the pending layer.
-  pending_layer_->set_invalidation(invalidation_rect);
-
-  host_impl_.SetViewportSize(viewport_size);
-
-  active_layer_->CreateDefaultTilingsAndTiles();
-  pending_layer_->CreateDefaultTilingsAndTiles();
+  SetupPendingTreeWithInvalidation(pending_pile, invalidation_rect);
 
   for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
     PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
@@ -4306,36 +4239,45 @@
 
 TEST_F(OcclusionTrackingPictureLayerImplTest,
        OccludedTilesConsideredDuringEviction) {
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+
   gfx::Size tile_size(102, 102);
   gfx::Size layer_bounds(1000, 1000);
-  gfx::Size viewport_size(500, 500);
+  gfx::Size viewport_size(1000, 1000);
   gfx::Point pending_occluding_layer_position(310, 0);
   gfx::Point active_occluding_layer_position(0, 310);
   gfx::Rect invalidation_rect(230, 230, 102, 102);
 
+  host_impl_.SetViewportSize(viewport_size);
+  host_impl_.SetDeviceScaleFactor(2.f);
+
   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);
 
-  pending_layer_->set_fixed_tile_size(tile_size);
-  active_layer_->set_fixed_tile_size(tile_size);
+  SetupPendingTreeWithFixedTileSize(active_pile, tile_size, Region());
 
-  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+  // Partially occlude the active layer.
+  pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 2));
+  LayerImpl* active_occluding_layer = pending_layer_->children()[0];
+  active_occluding_layer->SetBounds(layer_bounds);
+  active_occluding_layer->SetContentBounds(layer_bounds);
+  active_occluding_layer->SetDrawsContent(true);
+  active_occluding_layer->SetContentsOpaque(true);
+  active_occluding_layer->SetPosition(active_occluding_layer_position);
 
-  std::vector<PictureLayerTiling*> tilings;
-  tilings.push_back(pending_layer_->AddTiling(low_res_factor));
-  tilings.push_back(pending_layer_->AddTiling(0.3f));
-  tilings.push_back(pending_layer_->AddTiling(0.7f));
-  tilings.push_back(pending_layer_->AddTiling(1.0f));
-  tilings.push_back(pending_layer_->AddTiling(2.0f));
+  ActivateTree();
 
-  EXPECT_EQ(5u, pending_layer_->num_tilings());
-  EXPECT_EQ(5u, active_layer_->num_tilings());
+  // Partially invalidate the pending layer. Tiles inside the invalidation rect
+  // are not shared between trees.
+  SetupPendingTreeWithFixedTileSize(pending_pile, tile_size, invalidation_rect);
 
-  // Partially occlude the pending layer.
-  pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 1));
+  // Partially occlude the pending layer in a different way.
+  pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 3));
   LayerImpl* pending_occluding_layer = pending_layer_->children()[0];
   pending_occluding_layer->SetBounds(layer_bounds);
   pending_occluding_layer->SetContentBounds(layer_bounds);
@@ -4343,52 +4285,38 @@
   pending_occluding_layer->SetContentsOpaque(true);
   pending_occluding_layer->SetPosition(pending_occluding_layer_position);
 
-  // Partially occlude the active layer.
-  active_layer_->AddChild(LayerImpl::Create(host_impl_.active_tree(), 2));
-  LayerImpl* active_occluding_layer = active_layer_->children()[0];
-  active_occluding_layer->SetBounds(layer_bounds);
-  active_occluding_layer->SetContentBounds(layer_bounds);
-  active_occluding_layer->SetDrawsContent(true);
-  active_occluding_layer->SetContentsOpaque(true);
-  active_occluding_layer->SetPosition(active_occluding_layer_position);
+  EXPECT_EQ(2u, pending_layer_->num_tilings());
+  EXPECT_EQ(2u, active_layer_->num_tilings());
 
-  // Partially invalidate the pending layer. Tiles inside the invalidation rect
-  // are not shared between trees.
-  pending_layer_->set_invalidation(invalidation_rect);
-
-  host_impl_.SetViewportSize(viewport_size);
-  host_impl_.active_tree()->UpdateDrawProperties();
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentBeginFrameArgs(
+      CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
+  // UpdateDrawProperties with the occluding layer.
   host_impl_.pending_tree()->UpdateDrawProperties();
 
-  // The expected number of occluded tiles on each of the 5 tilings for each of
+  // The expected number of occluded tiles on each of the 2 tilings for each of
   // the 3 tree priorities.
-  size_t expected_occluded_tile_count_on_both[] = {9u, 1u, 1u, 1u, 1u};
-  size_t expected_occluded_tile_count_on_active[] = {30u, 5u, 4u, 2u, 2u};
-  size_t expected_occluded_tile_count_on_pending[] = {30u, 5u, 4u, 2u, 2u};
+  size_t expected_occluded_tile_count_on_both[] = {9u, 1u};
+  size_t expected_occluded_tile_count_on_active[] = {30u, 3u};
+  size_t expected_occluded_tile_count_on_pending[] = {30u, 3u};
 
-  // The total expected number of occluded tiles on all tilings for each of the
-  // 3 tree priorities.
-  size_t total_expected_occluded_tile_count[] = {13u, 43u, 43u};
-
-  ASSERT_EQ(arraysize(total_expected_occluded_tile_count), NUM_TREE_PRIORITIES);
+  size_t total_expected_occluded_tile_count_on_trees[] = {33u, 33u};
 
   // Verify number of occluded tiles on the pending layer for each tiling.
   for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
     PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
-    tiling->CreateAllTilesForTesting();
     tiling->UpdateAllTilePrioritiesForTesting();
 
     size_t occluded_tile_count_on_pending = 0u;
     size_t occluded_tile_count_on_active = 0u;
     size_t occluded_tile_count_on_both = 0u;
-    for (PictureLayerTiling::CoverageIterator iter(
-             tiling,
-             pending_layer_->contents_scale_x(),
-             gfx::Rect(layer_bounds));
-         iter;
-         ++iter) {
+    for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f,
+                                                   gfx::Rect(layer_bounds));
+         iter; ++iter) {
       Tile* tile = *iter;
 
+      if (!tile)
+        continue;
       if (tile->is_occluded(PENDING_TREE))
         occluded_tile_count_on_pending++;
       if (tile->is_occluded(ACTIVE_TREE))
@@ -4398,19 +4326,18 @@
     }
     EXPECT_EQ(expected_occluded_tile_count_on_pending[i],
               occluded_tile_count_on_pending)
-        << i;
+        << tiling->contents_scale();
     EXPECT_EQ(expected_occluded_tile_count_on_active[i],
               occluded_tile_count_on_active)
-        << i;
+        << tiling->contents_scale();
     EXPECT_EQ(expected_occluded_tile_count_on_both[i],
               occluded_tile_count_on_both)
-        << i;
+        << tiling->contents_scale();
   }
 
   // Verify number of occluded tiles on the active layer for each tiling.
   for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
     PictureLayerTiling* tiling = active_layer_->tilings()->tiling_at(i);
-    tiling->CreateAllTilesForTesting();
     tiling->UpdateAllTilePrioritiesForTesting();
 
     size_t occluded_tile_count_on_pending = 0u;
@@ -4424,6 +4351,8 @@
          ++iter) {
       Tile* tile = *iter;
 
+      if (!tile)
+        continue;
       if (tile->is_occluded(PENDING_TREE))
         occluded_tile_count_on_pending++;
       if (tile->is_occluded(ACTIVE_TREE))
@@ -4443,20 +4372,38 @@
   }
 
   std::vector<Tile*> all_tiles;
-  for (std::vector<PictureLayerTiling*>::iterator tiling_iterator =
-           tilings.begin();
-       tiling_iterator != tilings.end();
-       ++tiling_iterator) {
-    std::vector<Tile*> tiles = (*tiling_iterator)->AllTilesForTesting();
-    std::copy(tiles.begin(), tiles.end(), std::back_inserter(all_tiles));
+  for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+    std::vector<Tile*> tiles = tiling->AllTilesForTesting();
+    all_tiles.insert(all_tiles.end(), tiles.begin(), tiles.end());
   }
 
   host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
 
-  VerifyEvictionConsidersOcclusion(pending_layer_,
-                                   total_expected_occluded_tile_count);
-  VerifyEvictionConsidersOcclusion(active_layer_,
-                                   total_expected_occluded_tile_count);
+  VerifyEvictionConsidersOcclusion(
+      pending_layer_, active_layer_, PENDING_TREE,
+      total_expected_occluded_tile_count_on_trees[PENDING_TREE]);
+  VerifyEvictionConsidersOcclusion(
+      active_layer_, pending_layer_, ACTIVE_TREE,
+      total_expected_occluded_tile_count_on_trees[ACTIVE_TREE]);
+
+  // Repeat the tests without valid active tree priorities.
+  active_layer_->set_has_valid_tile_priorities(false);
+  VerifyEvictionConsidersOcclusion(
+      pending_layer_, active_layer_, PENDING_TREE,
+      total_expected_occluded_tile_count_on_trees[PENDING_TREE]);
+  VerifyEvictionConsidersOcclusion(
+      active_layer_, pending_layer_, ACTIVE_TREE, 0u);
+  active_layer_->set_has_valid_tile_priorities(true);
+
+  // Repeat the tests without valid pending tree priorities.
+  pending_layer_->set_has_valid_tile_priorities(false);
+  VerifyEvictionConsidersOcclusion(
+      active_layer_, pending_layer_, ACTIVE_TREE,
+      total_expected_occluded_tile_count_on_trees[ACTIVE_TREE]);
+  VerifyEvictionConsidersOcclusion(
+      pending_layer_, active_layer_, PENDING_TREE, 0u);
+  pending_layer_->set_has_valid_tile_priorities(true);
 }
 
 TEST_F(PictureLayerImplTest, PendingOrActiveTwinLayer) {
@@ -4530,8 +4477,6 @@
   host->SetRootLayer(layer);
   RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
 
-  host_impl_.SetViewportSize(layer_bounds);
-
   int frame_number = 0;
 
   client.set_fill_with_nonsolid_color(!test_for_solid);
@@ -4544,11 +4489,9 @@
   scoped_refptr<RasterSource> pending_raster_source =
       recording_source->CreateRasterSource();
 
-  SetupPendingTree(pending_raster_source);
+  SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region());
   ActivateTree();
 
-  active_layer_->set_fixed_tile_size(tile_size);
-  host_impl_.active_tree()->UpdateDrawProperties();
   if (test_for_solid) {
     EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
   } else {
@@ -4597,8 +4540,6 @@
   host->SetRootLayer(layer);
   RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
 
-  host_impl_.SetViewportSize(layer_bounds);
-
   int frame_number = 0;
 
   client.set_fill_with_nonsolid_color(true);
@@ -4696,6 +4637,66 @@
   EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
 }
 
+TEST_F(PictureLayerImplTest, CloneMissingRecordings) {
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(400, 400);
+
+  scoped_refptr<FakePicturePileImpl> filled_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> partial_pile =
+      FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
+  for (int i = 1; i < partial_pile->tiling().num_tiles_x(); ++i) {
+    for (int j = 1; j < partial_pile->tiling().num_tiles_y(); ++j)
+      partial_pile->AddRecordingAt(i, j);
+  }
+
+  SetupPendingTreeWithFixedTileSize(filled_pile, tile_size, Region());
+  ActivateTree();
+
+  PictureLayerTiling* pending_tiling = old_pending_layer_->HighResTiling();
+  PictureLayerTiling* active_tiling = active_layer_->HighResTiling();
+
+  // We should have all tiles in both tile sets.
+  EXPECT_EQ(5u * 5u, pending_tiling->AllTilesForTesting().size());
+  EXPECT_EQ(5u * 5u, active_tiling->AllTilesForTesting().size());
+
+  // Now put a partially-recorded pile on the pending tree (and invalidate
+  // everything, since the main thread PicturePile will invalidate dropped
+  // recordings). This will cause us to be missing some tiles.
+  SetupPendingTreeWithFixedTileSize(partial_pile, tile_size,
+                                    Region(gfx::Rect(layer_bounds)));
+  EXPECT_EQ(3u * 3u, pending_tiling->AllTilesForTesting().size());
+  EXPECT_FALSE(pending_tiling->TileAt(0, 0));
+  EXPECT_FALSE(pending_tiling->TileAt(1, 1));
+  EXPECT_TRUE(pending_tiling->TileAt(2, 2));
+
+  // Active is not affected yet.
+  EXPECT_EQ(5u * 5u, active_tiling->AllTilesForTesting().size());
+
+  // Activate the tree. The same tiles go missing on the active tree.
+  ActivateTree();
+  EXPECT_EQ(3u * 3u, active_tiling->AllTilesForTesting().size());
+  EXPECT_FALSE(active_tiling->TileAt(0, 0));
+  EXPECT_FALSE(active_tiling->TileAt(1, 1));
+  EXPECT_TRUE(active_tiling->TileAt(2, 2));
+
+  // Now put a full recording on the pending tree again. We'll get all our tiles
+  // back.
+  SetupPendingTreeWithFixedTileSize(filled_pile, tile_size,
+                                    Region(gfx::Rect(layer_bounds)));
+  EXPECT_EQ(5u * 5u, pending_tiling->AllTilesForTesting().size());
+
+  // Active is not affected yet.
+  EXPECT_EQ(3u * 3u, active_tiling->AllTilesForTesting().size());
+
+  // Activate the tree. The tiles are created and shared on the active tree.
+  ActivateTree();
+  EXPECT_EQ(5u * 5u, active_tiling->AllTilesForTesting().size());
+  EXPECT_TRUE(active_tiling->TileAt(0, 0)->is_shared());
+  EXPECT_TRUE(active_tiling->TileAt(1, 1)->is_shared());
+  EXPECT_TRUE(active_tiling->TileAt(2, 2)->is_shared());
+}
+
 class TileSizeSettings : public ImplSidePaintingSettings {
  public:
   TileSizeSettings() {
diff --git a/cc/layers/texture_layer_impl.cc b/cc/layers/texture_layer_impl.cc
index b174348..6e9cea1 100644
--- a/cc/layers/texture_layer_impl.cc
+++ b/cc/layers/texture_layer_impl.cc
@@ -111,8 +111,7 @@
 
     if (texture_copy_->id()) {
       std::vector<uint8> swizzled;
-      uint8* pixels =
-          static_cast<uint8*>(texture_mailbox_.shared_memory()->memory());
+      uint8* pixels = texture_mailbox_.shared_bitmap()->pixels();
 
       if (!PlatformColor::SameComponentOrder(texture_copy_->format())) {
         // Swizzle colors. This is slow, but should be really uncommon.
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 4e2f675..f2dbb33 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -101,7 +101,7 @@
                     uint32 sync_point,
                     bool lost_resource));
   MOCK_METHOD3(Release2,
-               void(base::SharedMemory* shared_memory,
+               void(SharedBitmap* shared_bitmap,
                     uint32 sync_point,
                     bool lost_resource));
   MOCK_METHOD4(ReleaseImpl,
@@ -110,19 +110,18 @@
                     bool lost_resource,
                     BlockingTaskRunner* main_thread_task_runner));
   MOCK_METHOD4(ReleaseImpl2,
-               void(base::SharedMemory* shared_memory,
+               void(SharedBitmap* shared_bitmap,
                     uint32 sync_point,
                     bool lost_resource,
                     BlockingTaskRunner* main_thread_task_runner));
 };
 
 struct CommonMailboxObjects {
-  CommonMailboxObjects()
+  explicit CommonMailboxObjects(SharedBitmapManager* manager)
       : mailbox_name1_(MailboxFromChar('1')),
         mailbox_name2_(MailboxFromChar('2')),
         sync_point1_(1),
-        sync_point2_(2),
-        shared_memory_(new base::SharedMemory) {
+        sync_point2_(2) {
     release_mailbox1_ = base::Bind(&MockMailboxCallback::Release,
                                    base::Unretained(&mock_callback_),
                                    mailbox_name1_);
@@ -140,14 +139,15 @@
     mailbox1_ = TextureMailbox(mailbox_name1_, arbitrary_target1, sync_point1_);
     mailbox2_ = TextureMailbox(mailbox_name2_, arbitrary_target2, sync_point2_);
     gfx::Size size(128, 128);
-    EXPECT_TRUE(shared_memory_->CreateAndMapAnonymous(4 * size.GetArea()));
-    release_mailbox3_ = base::Bind(&MockMailboxCallback::Release2,
-                                   base::Unretained(&mock_callback_),
-                                   shared_memory_.get());
-    release_mailbox3_impl_ = base::Bind(&MockMailboxCallback::ReleaseImpl2,
-                                        base::Unretained(&mock_callback_),
-                                        shared_memory_.get());
-    mailbox3_ = TextureMailbox(shared_memory_.get(), size);
+    shared_bitmap_ = manager->AllocateSharedBitmap(size);
+    DCHECK(shared_bitmap_);
+    release_mailbox3_ =
+        base::Bind(&MockMailboxCallback::Release2,
+                   base::Unretained(&mock_callback_), shared_bitmap_.get());
+    release_mailbox3_impl_ =
+        base::Bind(&MockMailboxCallback::ReleaseImpl2,
+                   base::Unretained(&mock_callback_), shared_bitmap_.get());
+    mailbox3_ = TextureMailbox(shared_bitmap_.get(), size);
   }
 
   gpu::Mailbox mailbox_name1_;
@@ -164,7 +164,7 @@
   TextureMailbox mailbox3_;
   uint32 sync_point1_;
   uint32 sync_point2_;
-  scoped_ptr<base::SharedMemory> shared_memory_;
+  scoped_ptr<SharedBitmap> shared_bitmap_;
 };
 
 class TextureLayerTest : public testing::Test {
@@ -172,7 +172,8 @@
   TextureLayerTest()
       : fake_client_(
             FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)),
-        host_impl_(&proxy_, &shared_bitmap_manager_) {}
+        host_impl_(&proxy_, &shared_bitmap_manager_),
+        test_data_(&shared_bitmap_manager_) {}
 
  protected:
   virtual void SetUp() {
@@ -195,6 +196,7 @@
   FakeLayerTreeHostClient fake_client_;
   TestSharedBitmapManager shared_bitmap_manager_;
   FakeLayerTreeHostImpl host_impl_;
+  CommonMailboxObjects test_data_;
 };
 
 TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
@@ -309,8 +311,6 @@
                         false)).Times(1);
     TextureLayerTest::TearDown();
   }
-
-  CommonMailboxObjects test_data_;
 };
 
 TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
@@ -359,9 +359,7 @@
 
   EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
   EXPECT_CALL(test_data_.mock_callback_,
-              Release2(test_data_.shared_memory_.get(),
-                       0, false))
-      .Times(1);
+              Release2(test_data_.shared_bitmap_.get(), 0, false)).Times(1);
   test_layer->SetTextureMailbox(TextureMailbox(), nullptr);
   Mock::VerifyAndClearExpectations(layer_tree_host_.get());
   Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
@@ -452,7 +450,6 @@
       main_ref_;
   base::Thread main_thread_;
   scoped_ptr<BlockingTaskRunner> main_thread_task_runner_;
-  CommonMailboxObjects test_data_;
 };
 
 TEST_F(TextureLayerMailboxHolderTest, TwoCompositors_BothReleaseThenMain) {
@@ -946,7 +943,6 @@
     return will_draw;
   }
 
-  CommonMailboxObjects test_data_;
   FakeLayerTreeHostClient fake_client_;
 };
 
@@ -958,7 +954,7 @@
       ReleaseImpl(test_data_.mailbox_name1_, test_data_.sync_point1_, false, _))
       .Times(AnyNumber());
   EXPECT_CALL(test_data_.mock_callback_,
-              ReleaseImpl2(test_data_.shared_memory_.get(), 0, false, _))
+              ReleaseImpl2(test_data_.shared_bitmap_.get(), 0, false, _))
       .Times(AnyNumber());
   // Hardware mode.
   {
diff --git a/cc/layers/tiled_layer_impl.cc b/cc/layers/tiled_layer_impl.cc
index c66e124..a36c030 100644
--- a/cc/layers/tiled_layer_impl.cc
+++ b/cc/layers/tiled_layer_impl.cc
@@ -262,7 +262,8 @@
                    tile->resource_id(),
                    tex_coord_rect,
                    texture_size,
-                   tile->contents_swizzled());
+                   tile->contents_swizzled(),
+                   false);
     }
   }
 }
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index a9a1e78..b4ee30f 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -45,18 +45,10 @@
   }
 };
 
-class SynchronousOutputSurfaceLayerTreeHost : public LayerTreeHost {
+class SynchronousOutputSurfaceClient : public FakeLayerTreeHostClient {
  public:
-  static scoped_ptr<SynchronousOutputSurfaceLayerTreeHost> Create(
-      LayerTreeHostClient* client,
-      SharedBitmapManager* manager,
-      const LayerTreeSettings& settings,
-      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
-    return make_scoped_ptr(new SynchronousOutputSurfaceLayerTreeHost(
-        client, manager, settings, impl_task_runner));
-  }
-
-  ~SynchronousOutputSurfaceLayerTreeHost() override {}
+  SynchronousOutputSurfaceClient()
+      : FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D) {}
 
   bool EnsureOutputSurfaceCreated() {
     base::MessageLoop::current()->PostDelayedTask(
@@ -67,25 +59,19 @@
     return output_surface_created_;
   }
 
-  void OnCreateAndInitializeOutputSurfaceAttempted(bool success) override {
-    LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted(success);
-    output_surface_created_ = success;
+  void DidInitializeOutputSurface() override {
+    FakeLayerTreeHostClient::DidInitializeOutputSurface();
+    output_surface_created_ = true;
+    run_loop_.Quit();
+  }
+
+  void DidFailToInitializeOutputSurface() override {
+    FakeLayerTreeHostClient::DidFailToInitializeOutputSurface();
+    output_surface_created_ = false;
     run_loop_.Quit();
   }
 
  private:
-  SynchronousOutputSurfaceLayerTreeHost(
-      LayerTreeHostClient* client,
-      SharedBitmapManager* manager,
-      const LayerTreeSettings& settings,
-      scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
-      : LayerTreeHost(client, manager, NULL, settings),
-        output_surface_created_(false) {
-    LayerTreeHost::InitializeThreaded(base::MessageLoopProxy::current(),
-                                      impl_task_runner,
-                                      nullptr);
-  }
-
   bool output_surface_created_;
   base::RunLoop run_loop_;
 };
@@ -97,7 +83,6 @@
         output_surface_(FakeOutputSurface::Create3d()),
         queue_(make_scoped_ptr(new ResourceUpdateQueue)),
         impl_thread_("ImplThread"),
-        fake_layer_tree_host_client_(FakeLayerTreeHostClient::DIRECT_3D),
         occlusion_(nullptr) {
     settings_.max_partial_texture_updates = std::numeric_limits<size_t>::max();
     settings_.layer_transforms_should_scale_layer_contents = true;
@@ -106,16 +91,16 @@
   void SetUp() override {
     impl_thread_.Start();
     shared_bitmap_manager_.reset(new TestSharedBitmapManager());
-    layer_tree_host_ = SynchronousOutputSurfaceLayerTreeHost::Create(
-        &fake_layer_tree_host_client_,
-        shared_bitmap_manager_.get(),
-        settings_,
-        impl_thread_.message_loop_proxy());
-    fake_layer_tree_host_client_.SetLayerTreeHost(layer_tree_host_.get());
+    layer_tree_host_ = LayerTreeHost::CreateThreaded(
+        &synchonous_output_surface_client_, shared_bitmap_manager_.get(),
+        nullptr, settings_, base::MessageLoopProxy::current(),
+        impl_thread_.message_loop_proxy(), nullptr);
+    synchonous_output_surface_client_.SetLayerTreeHost(layer_tree_host_.get());
     proxy_ = layer_tree_host_->proxy();
     resource_manager_ = PrioritizedResourceManager::Create(proxy_);
     layer_tree_host_->SetLayerTreeHostClientReady();
-    CHECK(layer_tree_host_->EnsureOutputSurfaceCreated());
+    CHECK(synchonous_output_surface_client_.EnsureOutputSurfaceCreated());
+
     layer_tree_host_->SetRootLayer(Layer::Create());
 
     CHECK(output_surface_->BindToClient(&output_surface_client_));
@@ -253,8 +238,8 @@
   scoped_ptr<ResourceUpdateQueue> queue_;
   PriorityCalculator priority_calculator_;
   base::Thread impl_thread_;
-  FakeLayerTreeHostClient fake_layer_tree_host_client_;
-  scoped_ptr<SynchronousOutputSurfaceLayerTreeHost> layer_tree_host_;
+  SynchronousOutputSurfaceClient synchonous_output_surface_client_;
+  scoped_ptr<LayerTreeHost> layer_tree_host_;
   scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
   scoped_ptr<PrioritizedResourceManager> resource_manager_;
   TestOcclusionTracker* occlusion_;
diff --git a/cc/output/delegating_renderer_unittest.cc b/cc/output/delegating_renderer_unittest.cc
index fffa0ac..b72c76b 100644
--- a/cc/output/delegating_renderer_unittest.cc
+++ b/cc/output/delegating_renderer_unittest.cc
@@ -17,7 +17,7 @@
   DelegatingRendererTest() : LayerTreeTest(), output_surface_(NULL) {}
   virtual ~DelegatingRendererTest() {}
 
-  scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) override {
+  scoped_ptr<OutputSurface> CreateOutputSurface() override {
     scoped_ptr<FakeOutputSurface> output_surface =
         FakeOutputSurface::CreateDelegating3d();
     output_surface_ = output_surface.get();
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 13cda6e..7896bb8 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -154,8 +154,6 @@
  public:
   static scoped_ptr<ScopedUseGrContext> Create(GLRenderer* renderer,
                                                DrawingFrame* frame) {
-    if (!renderer->output_surface_->context_provider()->GrContext())
-      return nullptr;
     return make_scoped_ptr(new ScopedUseGrContext(renderer, frame));
   }
 
@@ -1627,7 +1625,8 @@
   SetupQuadForAntialiasing(device_transform, quad, &local_quad, edge);
 
   ResourceProvider::ScopedSamplerGL quad_resource_lock(
-      resource_provider_, resource_id, GL_LINEAR);
+      resource_provider_, resource_id,
+      quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR);
   SamplerType sampler =
       SamplerTypeFromTextureTarget(quad_resource_lock.target());
 
@@ -1711,7 +1710,8 @@
 
   bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f);
   GLenum filter =
-      (scaled || !quad->quadTransform().IsIdentityOrIntegerTranslation())
+      (scaled || !quad->quadTransform().IsIdentityOrIntegerTranslation()) &&
+              !quad->nearest_neighbor
           ? GL_LINEAR
           : GL_NEAREST;
 
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index cb14db3..58205a9 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -1384,6 +1384,7 @@
   gfx::Rect viewport(this->device_viewport_size_);
   // TODO(enne): the renderer should figure this out on its own.
   ResourceFormat texture_format = RGBA_8888;
+  bool nearest_neighbor = false;
 
   RenderPassId id(1, 1);
   gfx::Transform transform_to_root;
@@ -1420,8 +1421,8 @@
   blue_quad->SetNew(blue_shared_state,
                     viewport,  // Intentionally bigger than clip.
                     gfx::Rect(), viewport, gfx::RectF(viewport),
-                    viewport.size(), texture_format, viewport, 1.f,
-                    blue_pile.get());
+                    viewport.size(), nearest_neighbor, texture_format, viewport,
+                    1.f, blue_pile.get());
 
   // One viewport-filling green quad.
   scoped_refptr<FakePicturePileImpl> green_pile =
@@ -1439,7 +1440,8 @@
       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, green_pile.get());
+                     nearest_neighbor, texture_format, viewport, 1.f,
+                     green_pile.get());
 
   RenderPassList pass_list;
   pass_list.push_back(pass.Pass());
@@ -1455,6 +1457,7 @@
   gfx::Size pile_tile_size(1000, 1000);
   gfx::Rect viewport(this->device_viewport_size_);
   ResourceFormat texture_format = RGBA_8888;
+  bool nearest_neighbor = false;
 
   RenderPassId id(1, 1);
   gfx::Transform transform_to_root;
@@ -1477,8 +1480,8 @@
   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, green_pile.get());
+                     gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor,
+                     texture_format, viewport, 1.f, green_pile.get());
 
   // One viewport-filling white quad.
   scoped_refptr<FakePicturePileImpl> white_pile =
@@ -1495,8 +1498,8 @@
   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, white_pile.get());
+                     gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor,
+                     texture_format, viewport, 1.f, white_pile.get());
 
   RenderPassList pass_list;
   pass_list.push_back(pass.Pass());
@@ -1532,6 +1535,7 @@
   gfx::Size pile_tile_size(1000, 1000);
   gfx::Rect viewport(this->device_viewport_size_);
   ResourceFormat texture_format = RGBA_8888;
+  bool nearest_neighbor = false;
 
   RenderPassId id(1, 1);
   gfx::Transform transform_to_root;
@@ -1562,8 +1566,8 @@
 
   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, pile.get());
+               gfx::RectF(0, 0, 2, 2), viewport.size(), nearest_neighbor,
+               texture_format, viewport, 1.f, pile.get());
 
   RenderPassList pass_list;
   pass_list.push_back(pass.Pass());
@@ -1576,11 +1580,118 @@
       ExactPixelComparator(true)));
 }
 
+// This disables filtering by setting |nearest_neighbor| on the PictureDrawQuad.
+TYPED_TEST(RendererPixelTest, PictureDrawQuadNearestNeighbor) {
+  gfx::Size pile_tile_size(1000, 1000);
+  gfx::Rect viewport(this->device_viewport_size_);
+  ResourceFormat texture_format = RGBA_8888;
+  bool nearest_neighbor = true;
+
+  RenderPassId id(1, 1);
+  gfx::Transform transform_to_root;
+  scoped_ptr<RenderPass> pass =
+      CreateTestRenderPass(id, viewport, transform_to_root);
+
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(2, 2);
+  {
+    SkAutoLockPixels lock(bitmap);
+    SkCanvas canvas(bitmap);
+    canvas.drawPoint(0, 0, SK_ColorGREEN);
+    canvas.drawPoint(0, 1, SK_ColorBLUE);
+    canvas.drawPoint(1, 0, SK_ColorBLUE);
+    canvas.drawPoint(1, 1, SK_ColorGREEN);
+  }
+
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFilledPile(pile_tile_size, viewport.size());
+  SkPaint paint;
+  paint.setFilterLevel(SkPaint::kLow_FilterLevel);
+  pile->add_draw_bitmap_with_paint(bitmap, gfx::Point(), paint);
+  pile->RerecordPile();
+
+  gfx::Transform content_to_target_transform;
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      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(), nearest_neighbor,
+               texture_format, viewport, 1.f, pile.get());
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+
+  EXPECT_TRUE(this->RunPixelTest(
+      &pass_list,
+      base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
+      ExactPixelComparator(true)));
+}
+
+// This disables filtering by setting |nearest_neighbor| on the TileDrawQuad.
+TYPED_TEST(RendererPixelTest, TileDrawQuadNearestNeighbor) {
+  gfx::Rect viewport(this->device_viewport_size_);
+  bool swizzle_contents = true;
+  bool nearest_neighbor = true;
+
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(2, 2);
+  {
+    SkAutoLockPixels lock(bitmap);
+    SkCanvas canvas(bitmap);
+    canvas.drawPoint(0, 0, SK_ColorGREEN);
+    canvas.drawPoint(0, 1, SK_ColorBLUE);
+    canvas.drawPoint(1, 0, SK_ColorBLUE);
+    canvas.drawPoint(1, 1, SK_ColorGREEN);
+  }
+
+  gfx::Size tile_size(2, 2);
+  ResourceProvider::ResourceId resource =
+      this->resource_provider_->CreateResource(
+          tile_size,
+          GL_CLAMP_TO_EDGE,
+          ResourceProvider::TextureHintImmutable,
+          RGBA_8888);
+
+  {
+    SkAutoLockPixels lock(bitmap);
+    this->resource_provider_->SetPixels(
+        resource,
+        static_cast<uint8_t*>(bitmap.getPixels()),
+        gfx::Rect(tile_size),
+        gfx::Rect(tile_size),
+        gfx::Vector2d());
+  }
+
+  RenderPassId id(1, 1);
+  gfx::Transform transform_to_root;
+  scoped_ptr<RenderPass> pass =
+      CreateTestRenderPass(id, viewport, transform_to_root);
+
+  gfx::Transform content_to_target_transform;
+  SharedQuadState* shared_state = CreateTestSharedQuadState(
+      content_to_target_transform, viewport, pass.get());
+
+  TileDrawQuad* quad = pass->CreateAndAppendDrawQuad<TileDrawQuad>();
+  quad->SetNew(shared_state, viewport, gfx::Rect(), viewport, resource,
+               gfx::Rect(tile_size), tile_size, swizzle_contents,
+               nearest_neighbor);
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+
+  EXPECT_TRUE(this->RunPixelTest(
+      &pass_list,
+      base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
+      ExactPixelComparator(true)));
+}
+
 TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
   gfx::Size pile_tile_size(1000, 1000);
   gfx::Rect viewport(this->device_viewport_size_);
   // TODO(enne): the renderer should figure this out on its own.
   ResourceFormat texture_format = RGBA_8888;
+  bool nearest_neighbor = false;
 
   RenderPassId id(1, 1);
   gfx::Transform transform_to_root;
@@ -1613,15 +1724,15 @@
       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,
-                      green_pile.get());
+                      green_rect1.size(), nearest_neighbor, 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,
-                      green_pile.get());
+                      green_rect2.size(), nearest_neighbor, 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.
@@ -1689,7 +1800,7 @@
   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.size(), nearest_neighbor, texture_format,
                     content_union_rect, contents_scale, pile.get());
 
   // Fill left half of viewport with green.
@@ -1874,6 +1985,7 @@
   gfx::Size pile_tile_size(1000, 1000);
   gfx::Rect viewport(this->device_viewport_size_);
   ResourceFormat texture_format = RGBA_4444;
+  bool nearest_neighbor = false;
 
   RenderPassId id(1, 1);
   gfx::Transform transform_to_root;
@@ -1895,7 +2007,8 @@
   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, blue_pile.get());
+                    nearest_neighbor, 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 e22e446..5bc7044 100644
--- a/cc/output/shader.cc
+++ b/cc/output/shader.cc
@@ -695,14 +695,14 @@
   // clang-format off
   static const std::string kFunctionApplyBlendMode = SHADER0(
       // clang-format on
-      uniform SamplerType s_backdropTexture;
+      uniform sampler2D s_backdropTexture;
       uniform TexCoordPrecision vec4 backdropRect;
 
       vec4 GetBackdropColor() {
         TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
         bgTexCoord.x /= backdropRect.z;
         bgTexCoord.y /= backdropRect.w;
-        return TextureLookup(s_backdropTexture, bgTexCoord);
+        return texture2D(s_backdropTexture, bgTexCoord);
       }
 
       vec4 ApplyBlendMode(vec4 src) {
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index ddd3473..1b18648 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -347,7 +347,8 @@
   // (http://crbug.com/280374).
   skia::RefPtr<SkDrawFilter> opacity_filter =
       skia::AdoptRef(new skia::OpacityDrawFilter(
-          quad->opacity(), frame->disable_picture_quad_image_filtering));
+          quad->opacity(), frame->disable_picture_quad_image_filtering ||
+                               quad->nearest_neighbor));
   DCHECK(!current_canvas_->getDrawFilter());
   current_canvas_->setDrawFilter(opacity_filter.get());
 
@@ -449,7 +450,9 @@
       QuadVertexRect(), quad->rect, quad->visible_rect);
 
   SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect);
-  current_paint_.setFilterLevel(SkPaint::kLow_FilterLevel);
+  current_paint_.setFilterLevel(quad->nearest_neighbor
+                                    ? SkPaint::kNone_FilterLevel
+                                    : SkPaint::kLow_FilterLevel);
   current_canvas_->drawBitmapRectToRect(
       *lock.sk_bitmap(),
       &uv_rect,
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index ea584ee..7f689a8 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -211,6 +211,7 @@
                      resource_cyan,
                      gfx::RectF(inner_size),
                      inner_size,
+                     false,
                      false);
   TileDrawQuad* outer_quad =
       root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
@@ -221,6 +222,7 @@
                      resource_yellow,
                      gfx::RectF(outer_size),
                      outer_size,
+                     false,
                      false);
 
   RenderPassList list;
@@ -294,6 +296,7 @@
                resource_cyan,
                gfx::RectF(tile_size),
                tile_size,
+               false,
                false);
   quad->visible_rect = visible_rect;
 
diff --git a/cc/quads/content_draw_quad_base.cc b/cc/quads/content_draw_quad_base.cc
index fd6e91b..7304498 100644
--- a/cc/quads/content_draw_quad_base.cc
+++ b/cc/quads/content_draw_quad_base.cc
@@ -25,13 +25,15 @@
                                  const gfx::Rect& visible_rect,
                                  const gfx::RectF& tex_coord_rect,
                                  const gfx::Size& texture_size,
-                                 bool swizzle_contents) {
+                                 bool swizzle_contents,
+                                 bool nearest_neighbor) {
   bool needs_blending = false;
   DrawQuad::SetAll(shared_quad_state, material, rect, opaque_rect,
                    visible_rect, needs_blending);
   this->tex_coord_rect = tex_coord_rect;
   this->texture_size = texture_size;
   this->swizzle_contents = swizzle_contents;
+  this->nearest_neighbor = nearest_neighbor;
 }
 
 void ContentDrawQuadBase::SetAll(const SharedQuadState* shared_quad_state,
@@ -42,12 +44,14 @@
                                  bool needs_blending,
                                  const gfx::RectF& tex_coord_rect,
                                  const gfx::Size& texture_size,
-                                 bool swizzle_contents) {
+                                 bool swizzle_contents,
+                                 bool nearest_neighbor) {
   DrawQuad::SetAll(shared_quad_state, material, rect, opaque_rect,
                    visible_rect, needs_blending);
   this->tex_coord_rect = tex_coord_rect;
   this->texture_size = texture_size;
   this->swizzle_contents = swizzle_contents;
+  this->nearest_neighbor = nearest_neighbor;
 }
 
 void ContentDrawQuadBase::ExtendValue(base::debug::TracedValue* value) const {
@@ -60,6 +64,7 @@
   value->EndDictionary();
 
   value->SetBoolean("swizzle_contents", swizzle_contents);
+  value->SetBoolean("nearest_neighbor", nearest_neighbor);
 }
 
 }  // namespace cc
diff --git a/cc/quads/content_draw_quad_base.h b/cc/quads/content_draw_quad_base.h
index b0e53dc..58aa727 100644
--- a/cc/quads/content_draw_quad_base.h
+++ b/cc/quads/content_draw_quad_base.h
@@ -23,7 +23,8 @@
               const gfx::Rect& visible_rect,
               const gfx::RectF& tex_coord_rect,
               const gfx::Size& texture_size,
-              bool swizzle_contents);
+              bool swizzle_contents,
+              bool nearest_neighbor);
 
   void SetAll(const SharedQuadState* shared_quad_state,
               DrawQuad::Material material,
@@ -33,11 +34,13 @@
               bool needs_blending,
               const gfx::RectF& tex_coord_rect,
               const gfx::Size& texture_size,
-              bool swizzle_contents);
+              bool swizzle_contents,
+              bool nearest_neighbor);
 
   gfx::RectF tex_coord_rect;
   gfx::Size texture_size;
   bool swizzle_contents;
+  bool nearest_neighbor;
 
  protected:
   ContentDrawQuadBase();
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc
index e65b326..97fea32 100644
--- a/cc/quads/draw_quad_unittest.cc
+++ b/cc/quads/draw_quad_unittest.cc
@@ -600,15 +600,17 @@
   gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
   gfx::Size texture_size(85, 32);
   bool swizzle_contents = true;
+  bool nearest_neighbor = true;
   CREATE_SHARED_STATE();
 
-  CREATE_QUAD_6_NEW(TileDrawQuad,
+  CREATE_QUAD_7_NEW(TileDrawQuad,
                     opaque_rect,
                     visible_rect,
                     resource_id,
                     tex_coord_rect,
                     texture_size,
-                    swizzle_contents);
+                    swizzle_contents,
+                    nearest_neighbor);
   EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material);
   EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
@@ -616,17 +618,20 @@
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(texture_size, copy_quad->texture_size);
   EXPECT_EQ(swizzle_contents, copy_quad->swizzle_contents);
+  EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
 
-  CREATE_QUAD_4_ALL(TileDrawQuad,
+  CREATE_QUAD_5_ALL(TileDrawQuad,
                     resource_id,
                     tex_coord_rect,
                     texture_size,
-                    swizzle_contents);
+                    swizzle_contents,
+                    nearest_neighbor);
   EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material);
   EXPECT_EQ(resource_id, copy_quad->resource_id);
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(texture_size, copy_quad->texture_size);
   EXPECT_EQ(swizzle_contents, copy_quad->swizzle_contents);
+  EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
 }
 
 TEST(DrawQuadTest, CopyYUVVideoDrawQuad) {
@@ -680,31 +685,34 @@
   gfx::Rect visible_rect(40, 50, 30, 20);
   gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
   gfx::Size texture_size(85, 32);
+  bool nearest_neighbor = true;
   ResourceFormat texture_format = RGBA_8888;
   gfx::Rect content_rect(30, 40, 20, 30);
   float contents_scale = 3.141592f;
   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,
-                    raster_source);
+  CREATE_QUAD_9_NEW(PictureDrawQuad, opaque_rect, visible_rect, tex_coord_rect,
+                    texture_size, nearest_neighbor, texture_format,
+                    content_rect, contents_scale, raster_source);
   EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
   EXPECT_EQ(opaque_rect, copy_quad->opaque_rect);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(texture_size, copy_quad->texture_size);
+  EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
   EXPECT_EQ(texture_format, copy_quad->texture_format);
   EXPECT_EQ(content_rect, copy_quad->content_rect);
   EXPECT_EQ(contents_scale, copy_quad->contents_scale);
   EXPECT_EQ(raster_source, copy_quad->raster_source);
 
-  CREATE_QUAD_6_ALL(PictureDrawQuad, tex_coord_rect, texture_size,
-                    texture_format, content_rect, contents_scale,
-                    raster_source);
+  CREATE_QUAD_7_ALL(PictureDrawQuad, tex_coord_rect, texture_size,
+                    nearest_neighbor, 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(nearest_neighbor, copy_quad->nearest_neighbor);
   EXPECT_EQ(texture_format, copy_quad->texture_format);
   EXPECT_EQ(content_rect, copy_quad->content_rect);
   EXPECT_EQ(contents_scale, copy_quad->contents_scale);
@@ -871,15 +879,17 @@
   gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
   gfx::Size texture_size(85, 32);
   bool swizzle_contents = true;
+  bool nearest_neighbor = true;
 
   CREATE_SHARED_STATE();
-  CREATE_QUAD_6_NEW(TileDrawQuad,
+  CREATE_QUAD_7_NEW(TileDrawQuad,
                     opaque_rect,
                     visible_rect,
                     resource_id,
                     tex_coord_rect,
                     texture_size,
-                    swizzle_contents);
+                    swizzle_contents,
+                    nearest_neighbor);
   EXPECT_EQ(resource_id, quad_new->resource_id);
   EXPECT_EQ(1, IterateAndCount(quad_new));
   EXPECT_EQ(resource_id + 1, quad_new->resource_id);
@@ -924,15 +934,16 @@
   gfx::Rect visible_rect(40, 50, 30, 20);
   gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
   gfx::Size texture_size(85, 32);
+  bool nearest_neighbor = true;
   ResourceFormat texture_format = RGBA_8888;
   gfx::Rect content_rect(30, 40, 20, 30);
   float contents_scale = 3.141592f;
   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,
-                    raster_source);
+  CREATE_QUAD_9_NEW(PictureDrawQuad, opaque_rect, visible_rect, tex_coord_rect,
+                    texture_size, nearest_neighbor, 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 bf329c2..2171542 100644
--- a/cc/quads/picture_draw_quad.cc
+++ b/cc/quads/picture_draw_quad.cc
@@ -23,6 +23,7 @@
                              const gfx::Rect& visible_rect,
                              const gfx::RectF& tex_coord_rect,
                              const gfx::Size& texture_size,
+                             bool nearest_neighbor,
                              ResourceFormat texture_format,
                              const gfx::Rect& content_rect,
                              float contents_scale,
@@ -35,7 +36,8 @@
       visible_rect,
       tex_coord_rect,
       texture_size,
-      !PlatformColor::SameComponentOrder(texture_format));
+      !PlatformColor::SameComponentOrder(texture_format),
+      nearest_neighbor);
   this->content_rect = content_rect;
   this->contents_scale = contents_scale;
   this->raster_source = raster_source;
@@ -49,6 +51,7 @@
                              bool needs_blending,
                              const gfx::RectF& tex_coord_rect,
                              const gfx::Size& texture_size,
+                             bool nearest_neighbor,
                              ResourceFormat texture_format,
                              const gfx::Rect& content_rect,
                              float contents_scale,
@@ -62,7 +65,8 @@
                               tex_coord_rect,
                               texture_size,
                               !PlatformColor::SameComponentOrder(
-                                  texture_format));
+                                  texture_format),
+                              nearest_neighbor);
   this->content_rect = content_rect;
   this->contents_scale = contents_scale;
   this->raster_source = raster_source;
diff --git a/cc/quads/picture_draw_quad.h b/cc/quads/picture_draw_quad.h
index 62c9f18..624b69c 100644
--- a/cc/quads/picture_draw_quad.h
+++ b/cc/quads/picture_draw_quad.h
@@ -28,6 +28,7 @@
               const gfx::Rect& visible_rect,
               const gfx::RectF& tex_coord_rect,
               const gfx::Size& texture_size,
+              bool nearest_neighbor,
               ResourceFormat texture_format,
               const gfx::Rect& content_rect,
               float contents_scale,
@@ -40,6 +41,7 @@
               bool needs_blending,
               const gfx::RectF& tex_coord_rect,
               const gfx::Size& texture_size,
+              bool nearest_neighbor,
               ResourceFormat texture_format,
               const gfx::Rect& content_rect,
               float contents_scale,
diff --git a/cc/quads/tile_draw_quad.cc b/cc/quads/tile_draw_quad.cc
index ea3a14a..88a4b3a 100644
--- a/cc/quads/tile_draw_quad.cc
+++ b/cc/quads/tile_draw_quad.cc
@@ -25,7 +25,8 @@
                           unsigned resource_id,
                           const gfx::RectF& tex_coord_rect,
                           const gfx::Size& texture_size,
-                          bool swizzle_contents) {
+                          bool swizzle_contents,
+                          bool nearest_neighbor) {
   ContentDrawQuadBase::SetNew(shared_quad_state,
                               DrawQuad::TILED_CONTENT,
                               rect,
@@ -33,7 +34,8 @@
                               visible_rect,
                               tex_coord_rect,
                               texture_size,
-                              swizzle_contents);
+                              swizzle_contents,
+                              nearest_neighbor);
   this->resource_id = resource_id;
 }
 
@@ -45,10 +47,12 @@
                           unsigned resource_id,
                           const gfx::RectF& tex_coord_rect,
                           const gfx::Size& texture_size,
-                          bool swizzle_contents) {
+                          bool swizzle_contents,
+                          bool nearest_neighbor) {
   ContentDrawQuadBase::SetAll(shared_quad_state, DrawQuad::TILED_CONTENT, rect,
                               opaque_rect, visible_rect, needs_blending,
-                              tex_coord_rect, texture_size, swizzle_contents);
+                              tex_coord_rect, texture_size, swizzle_contents,
+                              nearest_neighbor);
   this->resource_id = resource_id;
 }
 
diff --git a/cc/quads/tile_draw_quad.h b/cc/quads/tile_draw_quad.h
index d776057..e668ddb 100644
--- a/cc/quads/tile_draw_quad.h
+++ b/cc/quads/tile_draw_quad.h
@@ -21,7 +21,8 @@
               unsigned resource_id,
               const gfx::RectF& tex_coord_rect,
               const gfx::Size& texture_size,
-              bool swizzle_contents);
+              bool swizzle_contents,
+              bool nearest_neighbor);
 
   void SetAll(const SharedQuadState* shared_quad_state,
               const gfx::Rect& rect,
@@ -31,7 +32,8 @@
               unsigned resource_id,
               const gfx::RectF& tex_coord_rect,
               const gfx::Size& texture_size,
-              bool swizzle_contents);
+              bool swizzle_contents,
+              bool nearest_neighbor);
 
   unsigned resource_id;
 
diff --git a/cc/resources/display_list_recording_source.cc b/cc/resources/display_list_recording_source.cc
index 3c0e0e4..ab4c646 100644
--- a/cc/resources/display_list_recording_source.cc
+++ b/cc/resources/display_list_recording_source.cc
@@ -142,9 +142,8 @@
   if (display_list_->ApproximateOpCount() > kOpCountThatIsOkToAnalyze)
     return;
 
-  skia::AnalysisCanvas canvas(recorded_viewport_.width(),
-                              recorded_viewport_.height());
-  canvas.translate(-recorded_viewport_.x(), -recorded_viewport_.y());
+  gfx::Size layer_size = GetSize();
+  skia::AnalysisCanvas canvas(layer_size.width(), layer_size.height());
   display_list_->Raster(&canvas, nullptr, 1.f);
   is_solid_color_ = canvas.GetColorIfSolid(&solid_color_);
 }
diff --git a/cc/resources/eviction_tile_priority_queue.cc b/cc/resources/eviction_tile_priority_queue.cc
index 4d66987..cd681ef 100644
--- a/cc/resources/eviction_tile_priority_queue.cc
+++ b/cc/resources/eviction_tile_priority_queue.cc
@@ -200,6 +200,8 @@
 
   const Tile* active_tile = active_queue->Top();
   const Tile* pending_tile = pending_queue->Top();
+
+  // If tiles are the same, it doesn't matter which tree we return.
   if (active_tile == pending_tile)
     return ACTIVE_TREE;
 
@@ -208,6 +210,15 @@
   const TilePriority& pending_priority =
       pending_tile->priority_for_tree_priority(tree_priority);
 
+  // If the bins are the same and activation differs, then return the tree of
+  // the tile not required for activation.
+  if (active_priority.priority_bin == pending_priority.priority_bin &&
+      active_tile->required_for_activation() !=
+          pending_tile->required_for_activation()) {
+    return active_tile->required_for_activation() ? PENDING_TREE : ACTIVE_TREE;
+  }
+
+  // Return tile with a lower priority.
   if (pending_priority.IsHigherPriorityThan(active_priority))
     return ACTIVE_TREE;
   return PENDING_TREE;
diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc
index 6530866..ea7680c 100644
--- a/cc/resources/picture.cc
+++ b/cc/resources/picture.cc
@@ -121,7 +121,7 @@
   if (skpicture == NULL)
     return NULL;
 
-  gfx::Rect layer_rect(skpicture->width(), skpicture->height());
+  gfx::Rect layer_rect(gfx::SkIRectToRect(skpicture->cullRect().roundOut()));
   return make_scoped_refptr(new Picture(skpicture, layer_rect));
 }
 
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index e9e3b86..d2d5484 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -25,63 +25,44 @@
 
 const float kSoonBorderDistanceInScreenPixels = 312.f;
 
-class TileEvictionOrder {
- public:
-  explicit TileEvictionOrder(TreePriority tree_priority)
-      : tree_priority_(tree_priority) {}
-  ~TileEvictionOrder() {}
-
-  bool operator()(const Tile* a, const Tile* b) {
-    const TilePriority& a_priority =
-        a->priority_for_tree_priority(tree_priority_);
-    const TilePriority& b_priority =
-        b->priority_for_tree_priority(tree_priority_);
-
-    DCHECK(a_priority.priority_bin == b_priority.priority_bin);
-    DCHECK(a->required_for_activation() == b->required_for_activation());
-
-    // Or if a is occluded and b is unoccluded.
-    bool a_is_occluded = a->is_occluded_for_tree_priority(tree_priority_);
-    bool b_is_occluded = b->is_occluded_for_tree_priority(tree_priority_);
-    if (a_is_occluded != b_is_occluded)
-      return a_is_occluded;
-
-    // Or if a is farther away from visible.
-    return a_priority.distance_to_visible > b_priority.distance_to_visible;
-  }
-
- private:
-  TreePriority tree_priority_;
-};
-
 }  // namespace
 
 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
     float contents_scale,
     const gfx::Size& layer_bounds,
-    PictureLayerTilingClient* client) {
-  return make_scoped_ptr(new PictureLayerTiling(contents_scale,
-                                                layer_bounds,
-                                                client));
+    PictureLayerTilingClient* client,
+    size_t max_tiles_for_interest_area,
+    float skewport_target_time_in_seconds,
+    int skewport_extrapolation_limit_in_content_pixels) {
+  return make_scoped_ptr(new PictureLayerTiling(
+      contents_scale, layer_bounds, client, max_tiles_for_interest_area,
+      skewport_target_time_in_seconds,
+      skewport_extrapolation_limit_in_content_pixels));
 }
 
-PictureLayerTiling::PictureLayerTiling(float contents_scale,
-                                       const gfx::Size& layer_bounds,
-                                       PictureLayerTilingClient* client)
-    : contents_scale_(contents_scale),
+PictureLayerTiling::PictureLayerTiling(
+    float contents_scale,
+    const gfx::Size& layer_bounds,
+    PictureLayerTilingClient* client,
+    size_t max_tiles_for_interest_area,
+    float skewport_target_time_in_seconds,
+    int skewport_extrapolation_limit_in_content_pixels)
+    : max_tiles_for_interest_area_(max_tiles_for_interest_area),
+      skewport_target_time_in_seconds_(skewport_target_time_in_seconds),
+      skewport_extrapolation_limit_in_content_pixels_(
+          skewport_extrapolation_limit_in_content_pixels),
+      contents_scale_(contents_scale),
       layer_bounds_(layer_bounds),
       resolution_(NON_IDEAL_RESOLUTION),
       client_(client),
       tiling_data_(gfx::Size(), gfx::Size(), kBorderTexels),
       last_impl_frame_time_in_seconds_(0.0),
-      content_to_screen_scale_(0.f),
       can_require_tiles_for_activation_(false),
+      current_content_to_screen_scale_(0.f),
       has_visible_rect_tiles_(false),
       has_skewport_rect_tiles_(false),
       has_soon_border_rect_tiles_(false),
-      has_eventually_rect_tiles_(false),
-      eviction_tiles_cache_valid_(false),
-      eviction_cache_tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES) {
+      has_eventually_rect_tiles_(false) {
   gfx::Size content_bounds =
       gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale));
   gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
@@ -105,13 +86,13 @@
     it->second->set_shared(false);
 }
 
-void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) {
-  client_ = client;
-}
-
 Tile* PictureLayerTiling::CreateTile(int i,
                                      int j,
-                                     const PictureLayerTiling* twin_tiling) {
+                                     const PictureLayerTiling* twin_tiling,
+                                     PictureLayerTiling* recycled_twin) {
+  // Can't have both a (pending or active) twin and a recycled twin tiling.
+  DCHECK_IMPLIES(twin_tiling, !recycled_twin);
+  DCHECK_IMPLIES(recycled_twin, !twin_tiling);
   TileMapKey key(i, j);
   DCHECK(tiles_.find(key) == tiles_.end());
 
@@ -144,14 +125,24 @@
     DCHECK(!tile->is_shared());
     tile->set_tiling_index(i, j);
     tiles_[key] = tile;
+
+    if (recycled_twin) {
+      DCHECK(recycled_twin->tiles_.find(key) == recycled_twin->tiles_.end());
+      // Do what recycled_twin->CreateTile() would do.
+      tile->set_shared(true);
+      recycled_twin->tiles_[key] = tile;
+    }
   }
-  eviction_tiles_cache_valid_ = false;
   return tile.get();
 }
 
 void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
   const PictureLayerTiling* twin_tiling =
       client_->GetPendingOrActiveTwinTiling(this);
+  // There is no recycled twin during commit from the main thread which is when
+  // this occurs.
+  PictureLayerTiling* null_recycled_twin = nullptr;
+  DCHECK_EQ(null_recycled_twin, client_->GetRecycledTwinTiling(this));
   bool include_borders = false;
   for (TilingData::Iterator iter(
            &tiling_data_, live_tiles_rect_, include_borders);
@@ -161,116 +152,160 @@
     TileMap::iterator find = tiles_.find(key);
     if (find != tiles_.end())
       continue;
-    CreateTile(key.first, key.second, twin_tiling);
+    CreateTile(key.first, key.second, twin_tiling, null_recycled_twin);
   }
 
-  VerifyLiveTilesRect();
+  VerifyLiveTilesRect(false);
 }
 
-void PictureLayerTiling::UpdateTilesToCurrentRasterSource(
-    RasterSource* raster_source,
-    const Region& layer_invalidation,
-    const gfx::Size& new_layer_bounds) {
-  DCHECK(!new_layer_bounds.IsEmpty());
+void PictureLayerTiling::CloneTilesAndPropertiesFrom(
+    const PictureLayerTiling& twin_tiling) {
+  DCHECK_EQ(&twin_tiling, client_->GetPendingOrActiveTwinTiling(this));
 
+  Resize(twin_tiling.layer_bounds_);
+  DCHECK_EQ(twin_tiling.contents_scale_, contents_scale_);
+  DCHECK_EQ(twin_tiling.layer_bounds().ToString(), layer_bounds().ToString());
+  DCHECK_EQ(twin_tiling.tile_size().ToString(), tile_size().ToString());
+
+  resolution_ = twin_tiling.resolution_;
+
+  SetLiveTilesRect(twin_tiling.live_tiles_rect());
+
+  // Recreate unshared tiles.
+  std::vector<TileMapKey> to_remove;
+  for (const auto& tile_map_pair : tiles_) {
+    TileMapKey key = tile_map_pair.first;
+    Tile* tile = tile_map_pair.second.get();
+    if (!tile->is_shared())
+      to_remove.push_back(key);
+  }
+  // The recycled twin does not exist since there is a pending twin (which is
+  // |twin_tiling|).
+  PictureLayerTiling* null_recycled_twin = nullptr;
+  DCHECK_EQ(null_recycled_twin, client_->GetRecycledTwinTiling(this));
+  for (const auto& key : to_remove) {
+    RemoveTileAt(key.first, key.second, null_recycled_twin);
+    CreateTile(key.first, key.second, &twin_tiling, null_recycled_twin);
+  }
+
+  // Create any missing tiles from the |twin_tiling|.
+  for (const auto& tile_map_pair : twin_tiling.tiles_) {
+    TileMapKey key = tile_map_pair.first;
+    Tile* tile = tile_map_pair.second.get();
+    if (!tile->is_shared())
+      CreateTile(key.first, key.second, &twin_tiling, null_recycled_twin);
+  }
+
+  DCHECK_EQ(twin_tiling.tiles_.size(), tiles_.size());
+#if DCHECK_IS_ON
+  for (const auto& tile_map_pair : tiles_)
+    DCHECK(tile_map_pair.second->is_shared());
+  VerifyLiveTilesRect(false);
+#endif
+
+  UpdateTilePriorityRects(twin_tiling.current_content_to_screen_scale_,
+                          twin_tiling.current_visible_rect_,
+                          twin_tiling.current_skewport_rect_,
+                          twin_tiling.current_soon_border_rect_,
+                          twin_tiling.current_eventually_rect_,
+                          twin_tiling.current_occlusion_in_layer_space_);
+}
+
+void PictureLayerTiling::Resize(const gfx::Size& new_layer_bounds) {
+  gfx::Size layer_bounds = new_layer_bounds;
   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_) {
-    if (tile_size.IsEmpty()) {
-      layer_bounds_ = gfx::Size();
-      content_bounds = gfx::Size();
-    } else {
-      layer_bounds_ = new_layer_bounds;
-    }
-
-    // The SetLiveTilesRect() method would drop tiles outside the new bounds,
-    // but may do so incorrectly if resizing the tiling causes the number of
-    // tiles in the tiling_data_ to change.
-    gfx::Rect content_rect(content_bounds);
-    int before_left = tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.x());
-    int before_top = tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.y());
-    int before_right =
-        tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
-    int before_bottom =
-        tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
-
-    // The live_tiles_rect_ is clamped to stay within the tiling size as we
-    // change it.
-    live_tiles_rect_.Intersect(content_rect);
-    tiling_data_.SetTilingSize(content_bounds);
-
-    int after_right = -1;
-    int after_bottom = -1;
-    if (!live_tiles_rect_.IsEmpty()) {
-      after_right =
-          tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
-      after_bottom =
-          tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
-    }
-
-    // There is no recycled twin since this is run on the pending tiling.
-    PictureLayerTiling* recycled_twin = NULL;
-    DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this));
-    DCHECK_EQ(PENDING_TREE, client_->GetTree());
-
-    // Drop tiles outside the new layer bounds if the layer shrank.
-    for (int i = after_right + 1; i <= before_right; ++i) {
-      for (int j = before_top; j <= before_bottom; ++j)
-        RemoveTileAt(i, j, recycled_twin);
-    }
-    for (int i = before_left; i <= after_right; ++i) {
-      for (int j = after_bottom + 1; j <= before_bottom; ++j)
-        RemoveTileAt(i, j, recycled_twin);
-    }
-
-    // If the layer grew, the live_tiles_rect_ is not changed, but a new row
-    // and/or column of tiles may now exist inside the same live_tiles_rect_.
-    const PictureLayerTiling* twin_tiling =
-        client_->GetPendingOrActiveTwinTiling(this);
-    if (after_right > before_right) {
-      DCHECK_EQ(after_right, before_right + 1);
-      for (int j = before_top; j <= after_bottom; ++j)
-        CreateTile(after_right, j, twin_tiling);
-    }
-    if (after_bottom > before_bottom) {
-      DCHECK_EQ(after_bottom, before_bottom + 1);
-      for (int i = before_left; i <= before_right; ++i)
-        CreateTile(i, after_bottom, twin_tiling);
-    }
+  if (tile_size.IsEmpty()) {
+    layer_bounds = gfx::Size();
+    content_bounds = gfx::Size();
   }
 
+  // The layer bounds are only allowed to be empty when the tile size is empty.
+  // Otherwise we should not have such a tiling in the first place.
+  DCHECK_IMPLIES(!tile_size.IsEmpty(), !layer_bounds_.IsEmpty());
+
+  bool resized = layer_bounds != layer_bounds_;
+  layer_bounds_ = layer_bounds;
+
   if (tile_size != tiling_data_.max_texture_size()) {
+    tiling_data_.SetTilingSize(content_bounds);
     tiling_data_.SetMaxTextureSize(tile_size);
     // When the tile size changes, the TilingData positions no longer work
-    // as valid keys to the TileMap, so just drop all tiles.
+    // as valid keys to the TileMap, so just drop all tiles and clear the live
+    // tiles rect.
     Reset();
-  } else {
-    Invalidate(layer_invalidation);
+    return;
   }
 
-  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
-    it->second->set_raster_source(raster_source);
-  VerifyLiveTilesRect();
+  if (!resized)
+    return;
+
+  // The SetLiveTilesRect() method would drop tiles outside the new bounds,
+  // but may do so incorrectly if resizing the tiling causes the number of
+  // tiles in the tiling_data_ to change.
+  gfx::Rect content_rect(content_bounds);
+  int before_left = tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.x());
+  int before_top = tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.y());
+  int before_right =
+      tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
+  int before_bottom =
+      tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
+
+  // The live_tiles_rect_ is clamped to stay within the tiling size as we
+  // change it.
+  live_tiles_rect_.Intersect(content_rect);
+  tiling_data_.SetTilingSize(content_bounds);
+
+  int after_right = -1;
+  int after_bottom = -1;
+  if (!live_tiles_rect_.IsEmpty()) {
+    after_right =
+        tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
+    after_bottom =
+        tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
+  }
+
+  // There is no recycled twin since this is run on the pending tiling
+  // during commit, and on the active tree during activate.
+  PictureLayerTiling* null_recycled_twin = nullptr;
+  DCHECK_EQ(null_recycled_twin, client_->GetRecycledTwinTiling(this));
+
+  // Drop tiles outside the new layer bounds if the layer shrank.
+  for (int i = after_right + 1; i <= before_right; ++i) {
+    for (int j = before_top; j <= before_bottom; ++j)
+      RemoveTileAt(i, j, null_recycled_twin);
+  }
+  for (int i = before_left; i <= after_right; ++i) {
+    for (int j = after_bottom + 1; j <= before_bottom; ++j)
+      RemoveTileAt(i, j, null_recycled_twin);
+  }
+
+  // If the layer grew, the live_tiles_rect_ is not changed, but a new row
+  // and/or column of tiles may now exist inside the same live_tiles_rect_.
+  const PictureLayerTiling* twin_tiling =
+      client_->GetPendingOrActiveTwinTiling(this);
+  if (after_right > before_right) {
+    DCHECK_EQ(after_right, before_right + 1);
+    for (int j = before_top; j <= after_bottom; ++j)
+      CreateTile(after_right, j, twin_tiling, null_recycled_twin);
+  }
+  if (after_bottom > before_bottom) {
+    DCHECK_EQ(after_bottom, before_bottom + 1);
+    for (int i = before_left; i <= before_right; ++i)
+      CreateTile(i, after_bottom, twin_tiling, null_recycled_twin);
+  }
 }
 
-void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_region) {
-  bool recreate_invalidated_tiles = false;
-  DoInvalidate(layer_region, recreate_invalidated_tiles);
-}
-
-void PictureLayerTiling::Invalidate(const Region& layer_region) {
-  bool recreate_invalidated_tiles = true;
-  DoInvalidate(layer_region, recreate_invalidated_tiles);
-}
-
-void PictureLayerTiling::DoInvalidate(const Region& layer_region,
-                                      bool recreate_invalidated_tiles) {
+void PictureLayerTiling::Invalidate(const Region& layer_invalidation) {
+  if (live_tiles_rect_.IsEmpty())
+    return;
   std::vector<TileMapKey> new_tile_keys;
   gfx::Rect expanded_live_tiles_rect =
       tiling_data_.ExpandRectIgnoringBordersToTileBounds(live_tiles_rect_);
-  for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) {
+  for (Region::Iterator iter(layer_invalidation); iter.has_rect();
+       iter.next()) {
     gfx::Rect layer_rect = iter.rect();
     gfx::Rect content_rect =
         gfx::ScaleToEnclosingRect(layer_rect, contents_scale_);
@@ -291,25 +326,40 @@
              &tiling_data_, content_rect, include_borders);
          iter;
          ++iter) {
-      // There is no recycled twin since this is run on the pending tiling.
-      PictureLayerTiling* recycled_twin = NULL;
-      DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this));
-      DCHECK_EQ(PENDING_TREE, client_->GetTree());
-      if (RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin))
+      // There is no recycled twin for the pending tree during commit, or for
+      // the active tree during activation.
+      PictureLayerTiling* null_recycled_twin = nullptr;
+      DCHECK_EQ(null_recycled_twin, client_->GetRecycledTwinTiling(this));
+      if (RemoveTileAt(iter.index_x(), iter.index_y(), null_recycled_twin))
         new_tile_keys.push_back(iter.index());
     }
   }
 
-  if (recreate_invalidated_tiles && !new_tile_keys.empty()) {
+  if (!new_tile_keys.empty()) {
+    // During commit from the main thread, invalidations can never be shared
+    // with the active tree since the active tree has different content there.
+    // And when invalidating an active-tree tiling, it means there was no
+    // pending tiling to clone from.
+    const PictureLayerTiling* null_twin_tiling = nullptr;
+    PictureLayerTiling* null_recycled_twin = nullptr;
+    DCHECK_EQ(null_recycled_twin, client_->GetRecycledTwinTiling(this));
     for (size_t i = 0; i < new_tile_keys.size(); ++i) {
-      // Don't try to share a tile with the twin layer, it's been invalidated so
-      // we have to make our own tile here.
-      const PictureLayerTiling* twin_tiling = NULL;
-      CreateTile(new_tile_keys[i].first, new_tile_keys[i].second, twin_tiling);
+      CreateTile(new_tile_keys[i].first, new_tile_keys[i].second,
+                 null_twin_tiling, null_recycled_twin);
     }
   }
 }
 
+void PictureLayerTiling::SetRasterSource(
+    scoped_refptr<RasterSource> raster_source) {
+  // Shared (ie. non-invalidated) tiles on the pending tree are updated to use
+  // the new raster source. When this raster source is activated, the raster
+  // source will remain valid for shared tiles in the active tree.
+  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
+    it->second->set_raster_source(raster_source);
+  VerifyLiveTilesRect(false);
+}
+
 PictureLayerTiling::CoverageIterator::CoverageIterator()
     : tiling_(NULL),
       current_tile_(NULL),
@@ -468,10 +518,9 @@
     return false;
   found->second->set_shared(false);
   tiles_.erase(found);
-  eviction_tiles_cache_valid_ = false;
   if (recycled_twin) {
-    // Recycled twin does not also have a recycled twin, so pass NULL.
-    recycled_twin->RemoveTileAt(i, j, NULL);
+    // Recycled twin does not also have a recycled twin, so pass null.
+    recycled_twin->RemoveTileAt(i, j, nullptr);
   }
   return true;
 }
@@ -482,10 +531,9 @@
   for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
     it->second->set_shared(false);
     if (recycled_twin)
-      recycled_twin->RemoveTileAt(it->first.first, it->first.second, NULL);
+      recycled_twin->RemoveTileAt(it->first.first, it->first.second, nullptr);
   }
   tiles_.clear();
-  eviction_tiles_cache_valid_ = false;
 }
 
 gfx::Rect PictureLayerTiling::ComputeSkewport(
@@ -500,10 +548,8 @@
   if (time_delta == 0.0)
     return skewport;
 
-  float skewport_target_time_in_seconds =
-      client_->GetSkewportTargetTimeInSeconds();
   double extrapolation_multiplier =
-      skewport_target_time_in_seconds / time_delta;
+      skewport_target_time_in_seconds_ / time_delta;
 
   int old_x = last_visible_rect_in_content_space_.x();
   int old_y = last_visible_rect_in_content_space_.y();
@@ -515,12 +561,11 @@
   int new_right = visible_rect_in_content_space.right();
   int new_bottom = visible_rect_in_content_space.bottom();
 
-  int skewport_limit = client_->GetSkewportExtrapolationLimitInContentPixels();
-
-  // Compute the maximum skewport based on |skewport_limit|.
+  // Compute the maximum skewport based on
+  // |skewport_extrapolation_limit_in_content_pixels_|.
   gfx::Rect max_skewport = skewport;
-  max_skewport.Inset(
-      -skewport_limit, -skewport_limit, -skewport_limit, -skewport_limit);
+  max_skewport.Inset(-skewport_extrapolation_limit_in_content_pixels_,
+                     -skewport_extrapolation_limit_in_content_pixels_);
 
   // Inset the skewport by the needed adjustment.
   skewport.Inset(extrapolation_multiplier * (new_x - old_x),
@@ -564,11 +609,9 @@
   DCHECK(skewport.Contains(visible_rect_in_content_space));
 
   // Calculate the eventually/live tiles rect.
-  size_t max_tiles_for_interest_area = client_->GetMaxTilesForInterestArea();
-
   gfx::Size tile_size = tiling_data_.max_texture_size();
   int64 eventually_rect_area =
-      max_tiles_for_interest_area * tile_size.width() * tile_size.height();
+      max_tiles_for_interest_area_ * tile_size.width() * tile_size.height();
 
   gfx::Rect eventually_rect =
       ExpandRectEquallyToAreaBoundedBy(visible_rect_in_content_space,
@@ -582,29 +625,36 @@
       << " eventually_rect: " << eventually_rect.ToString();
 
   // Calculate the soon border rect.
-  content_to_screen_scale_ = ideal_contents_scale / contents_scale_;
+  float content_to_screen_scale = ideal_contents_scale / contents_scale_;
   gfx::Rect soon_border_rect = visible_rect_in_content_space;
-  float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale_;
+  float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale;
   soon_border_rect.Inset(-border, -border, -border, -border);
 
-  // Update the tiling state.
-  SetLiveTilesRect(eventually_rect);
-
   last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
   last_viewport_in_layer_space_ = viewport_in_layer_space;
   last_visible_rect_in_content_space_ = visible_rect_in_content_space;
 
-  eviction_tiles_cache_valid_ = false;
+  SetLiveTilesRect(eventually_rect);
+  UpdateTilePriorityRects(
+      content_to_screen_scale, visible_rect_in_content_space, skewport,
+      soon_border_rect, eventually_rect, occlusion_in_layer_space);
+}
 
+void PictureLayerTiling::UpdateTilePriorityRects(
+    float content_to_screen_scale,
+    const gfx::Rect& visible_rect_in_content_space,
+    const gfx::Rect& skewport,
+    const gfx::Rect& soon_border_rect,
+    const gfx::Rect& eventually_rect,
+    const Occlusion& occlusion_in_layer_space) {
   current_visible_rect_ = visible_rect_in_content_space;
   current_skewport_rect_ = skewport;
   current_soon_border_rect_ = soon_border_rect;
   current_eventually_rect_ = eventually_rect;
   current_occlusion_in_layer_space_ = occlusion_in_layer_space;
+  current_content_to_screen_scale_ = content_to_screen_scale;
 
-  // Update has_*_tiles state.
   gfx::Rect tiling_rect(tiling_size());
-
   has_visible_rect_tiles_ = tiling_rect.Intersects(current_visible_rect_);
   has_skewport_rect_tiles_ = tiling_rect.Intersects(current_skewport_rect_);
   has_soon_border_rect_tiles_ =
@@ -621,8 +671,9 @@
   if (live_tiles_rect_ == new_live_tiles_rect)
     return;
 
-  // Iterate to delete all tiles outside of our new live_tiles rect.
   PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this);
+
+  // Iterate to delete all tiles outside of our new live_tiles rect.
   for (TilingData::DifferenceIterator iter(&tiling_data_,
                                            live_tiles_rect_,
                                            new_live_tiles_rect);
@@ -641,16 +692,20 @@
        iter;
        ++iter) {
     TileMapKey key(iter.index());
-    CreateTile(key.first, key.second, twin_tiling);
+    CreateTile(key.first, key.second, twin_tiling, recycled_twin);
   }
 
   live_tiles_rect_ = new_live_tiles_rect;
-  VerifyLiveTilesRect();
+  VerifyLiveTilesRect(false);
+  if (recycled_twin) {
+    recycled_twin->live_tiles_rect_ = live_tiles_rect_;
+    recycled_twin->VerifyLiveTilesRect(true);
+  }
 }
 
-void PictureLayerTiling::VerifyLiveTilesRect() {
+void PictureLayerTiling::VerifyLiveTilesRect(bool is_on_recycle_tree) const {
 #if DCHECK_IS_ON
-  for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+  for (auto it = tiles_.begin(); it != tiles_.end(); ++it) {
     if (!it->second.get())
       continue;
     DCHECK(it->first.first < tiling_data_.num_tiles_x())
@@ -667,6 +722,7 @@
         << " tile bounds "
         << tiling_data_.TileBounds(it->first.first, it->first.second).ToString()
         << " live_tiles_rect " << live_tiles_rect_.ToString();
+    DCHECK_IMPLIES(is_on_recycle_tree, it->second->is_shared());
   }
 #endif
 }
@@ -805,10 +861,10 @@
     tile->set_required_for_draw(false);
   tile->set_is_occluded(tree, false);
 
-  DCHECK_GT(content_to_screen_scale_, 0.f);
+  DCHECK_GT(current_content_to_screen_scale_, 0.f);
   float distance_to_visible =
       current_visible_rect_.ManhattanInternalDistance(tile_bounds) *
-      content_to_screen_scale_;
+      current_content_to_screen_scale_;
 
   if (max_tile_priority_bin <= TilePriority::SOON &&
       (current_soon_border_rect_.Intersects(tile_bounds) ||
@@ -998,92 +1054,6 @@
   return result;
 }
 
-void PictureLayerTiling::UpdateEvictionCacheIfNeeded(
-    TreePriority tree_priority) {
-  if (eviction_tiles_cache_valid_ &&
-      eviction_cache_tree_priority_ == tree_priority)
-    return;
-
-  eviction_tiles_now_.clear();
-  eviction_tiles_now_and_required_for_activation_.clear();
-  eviction_tiles_soon_.clear();
-  eviction_tiles_soon_and_required_for_activation_.clear();
-  eviction_tiles_eventually_.clear();
-  eviction_tiles_eventually_and_required_for_activation_.clear();
-
-  for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
-    Tile* tile = it->second.get();
-    UpdateTileAndTwinPriority(tile);
-    const TilePriority& priority =
-        tile->priority_for_tree_priority(tree_priority);
-    switch (priority.priority_bin) {
-      case TilePriority::EVENTUALLY:
-        if (tile->required_for_activation())
-          eviction_tiles_eventually_and_required_for_activation_.push_back(
-              tile);
-        else
-          eviction_tiles_eventually_.push_back(tile);
-        break;
-      case TilePriority::SOON:
-        if (tile->required_for_activation())
-          eviction_tiles_soon_and_required_for_activation_.push_back(tile);
-        else
-          eviction_tiles_soon_.push_back(tile);
-        break;
-      case TilePriority::NOW:
-        if (tile->required_for_activation())
-          eviction_tiles_now_and_required_for_activation_.push_back(tile);
-        else
-          eviction_tiles_now_.push_back(tile);
-        break;
-    }
-  }
-
-  // TODO(vmpstr): Do this lazily. One option is to have a "sorted" flag that
-  // can be updated for each of the queues.
-  TileEvictionOrder sort_order(tree_priority);
-  std::sort(eviction_tiles_now_.begin(), eviction_tiles_now_.end(), sort_order);
-  std::sort(eviction_tiles_now_and_required_for_activation_.begin(),
-            eviction_tiles_now_and_required_for_activation_.end(),
-            sort_order);
-  std::sort(
-      eviction_tiles_soon_.begin(), eviction_tiles_soon_.end(), sort_order);
-  std::sort(eviction_tiles_soon_and_required_for_activation_.begin(),
-            eviction_tiles_soon_and_required_for_activation_.end(),
-            sort_order);
-  std::sort(eviction_tiles_eventually_.begin(),
-            eviction_tiles_eventually_.end(),
-            sort_order);
-  std::sort(eviction_tiles_eventually_and_required_for_activation_.begin(),
-            eviction_tiles_eventually_and_required_for_activation_.end(),
-            sort_order);
-
-  eviction_tiles_cache_valid_ = true;
-  eviction_cache_tree_priority_ = tree_priority;
-}
-
-const std::vector<Tile*>* PictureLayerTiling::GetEvictionTiles(
-    TreePriority tree_priority,
-    EvictionCategory category) {
-  UpdateEvictionCacheIfNeeded(tree_priority);
-  switch (category) {
-    case EVENTUALLY:
-      return &eviction_tiles_eventually_;
-    case EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
-      return &eviction_tiles_eventually_and_required_for_activation_;
-    case SOON:
-      return &eviction_tiles_soon_;
-    case SOON_AND_REQUIRED_FOR_ACTIVATION:
-      return &eviction_tiles_soon_and_required_for_activation_;
-    case NOW:
-      return &eviction_tiles_now_;
-    case NOW_AND_REQUIRED_FOR_ACTIVATION:
-      return &eviction_tiles_now_and_required_for_activation_;
-  }
-  NOTREACHED();
-  return &eviction_tiles_eventually_;
-}
-
 PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator()
     : tiling_(NULL), current_tile_(NULL) {}
 
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index daa0485..4b80aa0 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -48,9 +48,6 @@
   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;
   virtual WhichTree GetTree() const = 0;
   virtual bool RequiresHighResToDraw() const = 0;
 
@@ -62,15 +59,6 @@
  public:
   static const int kBorderTexels = 1;
 
-  enum EvictionCategory {
-    EVENTUALLY,
-    EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION,
-    SOON,
-    SOON_AND_REQUIRED_FOR_ACTIVATION,
-    NOW,
-    NOW_AND_REQUIRED_FOR_ACTIVATION
-  };
-
   class CC_EXPORT TilingRasterTileIterator {
    public:
     TilingRasterTileIterator();
@@ -121,18 +109,24 @@
   ~PictureLayerTiling();
 
   // Create a tiling with no tiles.  CreateTiles must be called to add some.
+  // TODO(danakj): Pass the raster_source here instead of the size, store the
+  // raster source instead of layer bounds?
   static scoped_ptr<PictureLayerTiling> Create(
       float contents_scale,
       const gfx::Size& layer_bounds,
-      PictureLayerTilingClient* client);
-  gfx::Size layer_bounds() const { return layer_bounds_; }
-  void UpdateTilesToCurrentRasterSource(RasterSource* raster_source,
-                                        const Region& layer_invalidation,
-                                        const gfx::Size& new_layer_bounds);
-  void CreateMissingTilesInLiveTilesRect();
-  void RemoveTilesInRegion(const Region& layer_region);
+      PictureLayerTilingClient* client,
+      size_t max_tiles_for_interest_area,
+      float skewport_target_time_in_seconds,
+      int skewport_extrapolation_limit_in_content_pixels);
 
-  void SetClient(PictureLayerTilingClient* client);
+  gfx::Size layer_bounds() const { return layer_bounds_; }
+  void Resize(const gfx::Size& new_layer_bounds);
+  void Invalidate(const Region& layer_invalidation);
+  void SetRasterSource(scoped_refptr<RasterSource> raster_source);
+  void CreateMissingTilesInLiveTilesRect();
+
+  void CloneTilesAndPropertiesFrom(const PictureLayerTiling& twin_tiling);
+
   void set_resolution(TileResolution resolution) { resolution_ = resolution; }
   TileResolution resolution() const { return resolution_; }
   void set_can_require_tiles_for_activation(bool can_require_tiles) {
@@ -288,10 +282,16 @@
 
   PictureLayerTiling(float contents_scale,
                      const gfx::Size& layer_bounds,
-                     PictureLayerTilingClient* client);
+                     PictureLayerTilingClient* client,
+                     size_t max_tiles_for_interest_area,
+                     float skewport_target_time_in_seconds,
+                     int skewport_extrapolation_limit_in_content_pixels);
   void SetLiveTilesRect(const gfx::Rect& live_tiles_rect);
-  void VerifyLiveTilesRect();
-  Tile* CreateTile(int i, int j, const PictureLayerTiling* twin_tiling);
+  void VerifyLiveTilesRect(bool is_on_recycle_tree) const;
+  Tile* CreateTile(int i,
+                   int j,
+                   const PictureLayerTiling* twin_tiling,
+                   PictureLayerTiling* recycled_twin);
   // Returns true if the Tile existed and was removed from the tiling.
   bool RemoveTileAt(int i, int j, PictureLayerTiling* recycled_twin);
 
@@ -303,18 +303,21 @@
                             const gfx::Rect& visible_rect_in_content_space)
       const;
 
-  void UpdateEvictionCacheIfNeeded(TreePriority tree_priority);
-  const std::vector<Tile*>* GetEvictionTiles(TreePriority tree_priority,
-                                             EvictionCategory category);
-
-  void Invalidate(const Region& layer_region);
-
-  void DoInvalidate(const Region& layer_region,
-                    bool recreate_invalidated_tiles);
+  // Save the required data for computing tile priorities later.
+  void UpdateTilePriorityRects(float content_to_screen_scale_,
+                               const gfx::Rect& visible_rect_in_content_space,
+                               const gfx::Rect& skewport,
+                               const gfx::Rect& soon_border_rect,
+                               const gfx::Rect& eventually_rect,
+                               const Occlusion& occlusion_in_layer_space);
 
   void UpdateTileAndTwinPriority(Tile* tile) const;
   void UpdateTilePriority(Tile* tile) const;
 
+  const size_t max_tiles_for_interest_area_;
+  const float skewport_target_time_in_seconds_;
+  const int skewport_extrapolation_limit_in_content_pixels_;
+
   // Given properties.
   float contents_scale_;
   gfx::Size layer_bounds_;
@@ -330,36 +333,23 @@
   double last_impl_frame_time_in_seconds_;
   gfx::Rect last_viewport_in_layer_space_;
   gfx::Rect last_visible_rect_in_content_space_;
-  float content_to_screen_scale_;
 
   bool can_require_tiles_for_activation_;
 
-  // Iteration rects in content space
+  // Iteration rects in content space.
   gfx::Rect current_visible_rect_;
   gfx::Rect current_skewport_rect_;
   gfx::Rect current_soon_border_rect_;
   gfx::Rect current_eventually_rect_;
+  // Other properties used for tile iteration and prioritization.
+  float current_content_to_screen_scale_;
+  Occlusion current_occlusion_in_layer_space_;
 
   bool has_visible_rect_tiles_;
   bool has_skewport_rect_tiles_;
   bool has_soon_border_rect_tiles_;
   bool has_eventually_rect_tiles_;
 
-  Occlusion current_occlusion_in_layer_space_;
-
-  // TODO(reveman): Remove this in favour of an array of eviction_tiles_ when we
-  // change all enums to have a consistent way of getting the count/last
-  // element.
-  std::vector<Tile*> eviction_tiles_now_;
-  std::vector<Tile*> eviction_tiles_now_and_required_for_activation_;
-  std::vector<Tile*> eviction_tiles_soon_;
-  std::vector<Tile*> eviction_tiles_soon_and_required_for_activation_;
-  std::vector<Tile*> eviction_tiles_eventually_;
-  std::vector<Tile*> eviction_tiles_eventually_and_required_for_activation_;
-
-  bool eviction_tiles_cache_valid_;
-  TreePriority eviction_cache_tree_priority_;
-
  private:
   DISALLOW_ASSIGN(PictureLayerTiling);
 
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index 3944e46..ee41bef 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -44,11 +44,14 @@
   }
 
   void SetUp() override {
+    LayerTreeSettings defaults;
     picture_layer_tiling_client_.SetTileSize(gfx::Size(256, 256));
-    picture_layer_tiling_client_.set_max_tiles_for_interest_area(250);
     picture_layer_tiling_client_.set_tree(PENDING_TREE);
     picture_layer_tiling_ = PictureLayerTiling::Create(
-        1, gfx::Size(256 * 50, 256 * 50), &picture_layer_tiling_client_);
+        1, gfx::Size(256 * 50, 256 * 50), &picture_layer_tiling_client_,
+        defaults.max_tiles_for_interest_area,
+        defaults.skewport_target_time_in_seconds,
+        defaults.skewport_extrapolation_limit_in_content_pixels);
     picture_layer_tiling_->CreateAllTilesForTesting();
   }
 
@@ -57,9 +60,7 @@
   void RunInvalidateTest(const std::string& test_name, const Region& region) {
     timer_.Reset();
     do {
-      picture_layer_tiling_->UpdateTilesToCurrentRasterSource(
-          picture_layer_tiling_client_.raster_source(), region,
-          picture_layer_tiling_->tiling_size());
+      picture_layer_tiling_->Invalidate(region);
       timer_.NextLap();
     } while (!timer_.HasTimeLimitExpired());
 
@@ -126,8 +127,12 @@
   void RunRasterIteratorConstructTest(const std::string& test_name,
                                       const gfx::Rect& viewport) {
     gfx::Size bounds(viewport.size());
-    picture_layer_tiling_ =
-        PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
+    LayerTreeSettings defaults;
+    picture_layer_tiling_ = PictureLayerTiling::Create(
+        1, bounds, &picture_layer_tiling_client_,
+        defaults.max_tiles_for_interest_area,
+        defaults.skewport_target_time_in_seconds,
+        defaults.skewport_extrapolation_limit_in_content_pixels);
     picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
     picture_layer_tiling_->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
                                                     Occlusion());
@@ -151,8 +156,12 @@
                                                 int num_tiles,
                                                 const gfx::Rect& viewport) {
     gfx::Size bounds(10000, 10000);
-    picture_layer_tiling_ =
-        PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
+    LayerTreeSettings defaults;
+    picture_layer_tiling_ = PictureLayerTiling::Create(
+        1, bounds, &picture_layer_tiling_client_,
+        defaults.max_tiles_for_interest_area,
+        defaults.skewport_target_time_in_seconds,
+        defaults.skewport_extrapolation_limit_in_content_pixels);
     picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
     picture_layer_tiling_->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
                                                     Occlusion());
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc
index 51896a5..a3348bc 100644
--- a/cc/resources/picture_layer_tiling_set.cc
+++ b/cc/resources/picture_layer_tiling_set.cc
@@ -29,26 +29,98 @@
 
 // static
 scoped_ptr<PictureLayerTilingSet> PictureLayerTilingSet::Create(
-    PictureLayerTilingClient* client) {
-  return make_scoped_ptr(new PictureLayerTilingSet(client));
+    PictureLayerTilingClient* client,
+    size_t max_tiles_for_interest_area,
+    float skewport_target_time_in_seconds,
+    int skewport_extrapolation_limit_in_content_pixels) {
+  return make_scoped_ptr(new PictureLayerTilingSet(
+      client, max_tiles_for_interest_area, skewport_target_time_in_seconds,
+      skewport_extrapolation_limit_in_content_pixels));
 }
 
-PictureLayerTilingSet::PictureLayerTilingSet(PictureLayerTilingClient* client)
-    : client_(client) {
+PictureLayerTilingSet::PictureLayerTilingSet(
+    PictureLayerTilingClient* client,
+    size_t max_tiles_for_interest_area,
+    float skewport_target_time_in_seconds,
+    int skewport_extrapolation_limit_in_content_pixels)
+    : max_tiles_for_interest_area_(max_tiles_for_interest_area),
+      skewport_target_time_in_seconds_(skewport_target_time_in_seconds),
+      skewport_extrapolation_limit_in_content_pixels_(
+          skewport_extrapolation_limit_in_content_pixels),
+      client_(client) {
 }
 
 PictureLayerTilingSet::~PictureLayerTilingSet() {
 }
 
-void PictureLayerTilingSet::SetClient(PictureLayerTilingClient* client) {
-  client_ = client;
-  for (size_t i = 0; i < tilings_.size(); ++i)
-    tilings_[i]->SetClient(client_);
-}
+void PictureLayerTilingSet::UpdateTilingsToCurrentRasterSource(
+    RasterSource* raster_source,
+    const PictureLayerTilingSet* twin_set,
+    const gfx::Size& layer_bounds,
+    const Region& layer_invalidation,
+    float minimum_contents_scale) {
+  RemoveTilingsBelowScale(minimum_contents_scale);
 
-void PictureLayerTilingSet::RemoveTilesInRegion(const Region& region) {
-  for (size_t i = 0; i < tilings_.size(); ++i)
-    tilings_[i]->RemoveTilesInRegion(region);
+  // Copy over tilings that are shared with the |twin_set| tiling set (if it
+  // exists).
+  if (twin_set) {
+    for (PictureLayerTiling* twin_tiling : twin_set->tilings_) {
+      float contents_scale = twin_tiling->contents_scale();
+      DCHECK_GE(contents_scale, minimum_contents_scale);
+
+      PictureLayerTiling* this_tiling = FindTilingWithScale(contents_scale);
+      if (!this_tiling) {
+        scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
+            contents_scale, layer_bounds, client_, max_tiles_for_interest_area_,
+            skewport_target_time_in_seconds_,
+            skewport_extrapolation_limit_in_content_pixels_);
+        tilings_.push_back(new_tiling.Pass());
+        this_tiling = tilings_.back();
+      }
+      this_tiling->CloneTilesAndPropertiesFrom(*twin_tiling);
+    }
+  }
+
+  // For unshared tilings, invalidate tiles and update them to the new raster
+  // source.
+  for (PictureLayerTiling* tiling : tilings_) {
+    if (twin_set && twin_set->FindTilingWithScale(tiling->contents_scale()))
+      continue;
+
+    tiling->Resize(layer_bounds);
+    tiling->Invalidate(layer_invalidation);
+    tiling->SetRasterSource(raster_source);
+    // This is needed for cases where the live tiles rect didn't change but
+    // recordings exist in the raster source that did not exist on the last
+    // raster source.
+    tiling->CreateMissingTilesInLiveTilesRect();
+
+    // If |twin_set| is present, use the resolutions from there. Otherwise leave
+    // all resolutions as they are.
+    if (twin_set)
+      tiling->set_resolution(NON_IDEAL_RESOLUTION);
+  }
+
+  tilings_.sort(LargestToSmallestScaleFunctor());
+
+#if DCHECK_IS_ON
+  for (PictureLayerTiling* tiling : tilings_) {
+    DCHECK(tiling->tile_size() ==
+           client_->CalculateTileSize(tiling->tiling_size()))
+        << "tile_size: " << tiling->tile_size().ToString()
+        << " tiling_size: " << tiling->tiling_size().ToString()
+        << " CalculateTileSize: "
+        << client_->CalculateTileSize(tiling->tiling_size()).ToString();
+  }
+
+  if (!tilings_.empty()) {
+    size_t num_high_res = std::count_if(tilings_.begin(), tilings_.end(),
+                                        [](PictureLayerTiling* tiling) {
+      return tiling->resolution() == HIGH_RESOLUTION;
+    });
+    DCHECK_EQ(1u, num_high_res);
+  }
+#endif
 }
 
 void PictureLayerTilingSet::CleanUpTilings(
@@ -91,14 +163,6 @@
   }
 
   for (auto* tiling : to_remove) {
-    PictureLayerTiling* twin_tiling =
-        twin_set ? twin_set->FindTilingWithScale(tiling->contents_scale())
-                 : nullptr;
-    // Only remove tilings from the twin layer if they have
-    // NON_IDEAL_RESOLUTION.
-    if (twin_tiling && twin_tiling->resolution() == NON_IDEAL_RESOLUTION)
-      twin_set->Remove(twin_tiling);
-
     PictureLayerTiling* recycled_twin_tiling =
         recycled_twin_set
             ? recycled_twin_set->FindTilingWithScale(tiling->contents_scale())
@@ -113,16 +177,24 @@
   }
 }
 
+void PictureLayerTilingSet::RemoveNonIdealTilings() {
+  auto to_remove = tilings_.remove_if([](PictureLayerTiling* t) {
+    return t->resolution() == NON_IDEAL_RESOLUTION;
+  });
+  tilings_.erase(to_remove, tilings_.end());
+}
+
 void PictureLayerTilingSet::MarkAllTilingsNonIdeal() {
   for (auto* tiling : tilings_)
     tiling->set_resolution(NON_IDEAL_RESOLUTION);
 }
 
-bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other,
-                                        const gfx::Size& new_layer_bounds,
-                                        const Region& layer_invalidation,
-                                        float minimum_contents_scale,
-                                        RasterSource* raster_source) {
+bool PictureLayerTilingSet::SyncTilingsForTesting(
+    const PictureLayerTilingSet& other,
+    const gfx::Size& new_layer_bounds,
+    const Region& layer_invalidation,
+    float minimum_contents_scale,
+    RasterSource* raster_source) {
   if (new_layer_bounds.IsEmpty()) {
     RemoveAllTilings();
     return false;
@@ -151,8 +223,9 @@
     if (PictureLayerTiling* this_tiling = FindTilingWithScale(contents_scale)) {
       this_tiling->set_resolution(other.tilings_[i]->resolution());
 
-      this_tiling->UpdateTilesToCurrentRasterSource(
-          raster_source, layer_invalidation, new_layer_bounds);
+      this_tiling->Resize(new_layer_bounds);
+      this_tiling->Invalidate(layer_invalidation);
+      this_tiling->SetRasterSource(raster_source);
       this_tiling->CreateMissingTilesInLiveTilesRect();
       if (this_tiling->resolution() == HIGH_RESOLUTION)
         have_high_res_tiling = true;
@@ -166,9 +239,9 @@
       continue;
     }
     scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
-        contents_scale,
-        new_layer_bounds,
-        client_);
+        contents_scale, new_layer_bounds, client_, max_tiles_for_interest_area_,
+        skewport_target_time_in_seconds_,
+        skewport_extrapolation_limit_in_content_pixels_);
     new_tiling->set_resolution(other.tilings_[i]->resolution());
     if (new_tiling->resolution() == HIGH_RESOLUTION)
       have_high_res_tiling = true;
@@ -185,8 +258,10 @@
   for (size_t i = 0; i < tilings_.size(); ++i)
     DCHECK_NE(tilings_[i]->contents_scale(), contents_scale);
 
-  tilings_.push_back(
-      PictureLayerTiling::Create(contents_scale, layer_bounds, client_));
+  tilings_.push_back(PictureLayerTiling::Create(
+      contents_scale, layer_bounds, client_, max_tiles_for_interest_area_,
+      skewport_target_time_in_seconds_,
+      skewport_extrapolation_limit_in_content_pixels_));
   PictureLayerTiling* appended = tilings_.back();
 
   tilings_.sort(LargestToSmallestScaleFunctor());
@@ -222,6 +297,14 @@
   return *iter;
 }
 
+void PictureLayerTilingSet::RemoveTilingsBelowScale(float minimum_scale) {
+  auto to_remove =
+      tilings_.remove_if([minimum_scale](PictureLayerTiling* tiling) {
+        return tiling->contents_scale() < minimum_scale;
+      });
+  tilings_.erase(to_remove, tilings_.end());
+}
+
 void PictureLayerTilingSet::RemoveAllTilings() {
   tilings_.clear();
 }
diff --git a/cc/resources/picture_layer_tiling_set.h b/cc/resources/picture_layer_tiling_set.h
index f0d0fd7..4038b32 100644
--- a/cc/resources/picture_layer_tiling_set.h
+++ b/cc/resources/picture_layer_tiling_set.h
@@ -38,31 +38,42 @@
   };
 
   static scoped_ptr<PictureLayerTilingSet> Create(
-      PictureLayerTilingClient* client);
+      PictureLayerTilingClient* client,
+      size_t max_tiles_for_interest_area,
+      float skewport_target_time_in_seconds,
+      int skewport_extrapolation_limit_in_content);
 
   ~PictureLayerTilingSet();
 
-  void SetClient(PictureLayerTilingClient* client);
   const PictureLayerTilingClient* client() const { return client_; }
 
-  void RemoveTilesInRegion(const Region& region);
   void CleanUpTilings(float min_acceptable_high_res_scale,
                       float max_acceptable_high_res_scale,
                       const std::vector<PictureLayerTiling*>& needed_tilings,
                       bool should_have_low_res,
                       PictureLayerTilingSet* twin_set,
                       PictureLayerTilingSet* recycled_twin_set);
-
+  void RemoveNonIdealTilings();
   // Make this set of tilings match the same set of content scales from |other|.
   // Delete any tilings that don't meet |minimum_contents_scale|.  Recreate
   // any tiles that intersect |layer_invalidation|.  Update the size of all
   // tilings to |new_layer_bounds|.
   // Returns true if we had at least one high res tiling synced.
-  bool SyncTilings(const PictureLayerTilingSet& other,
-                   const gfx::Size& new_layer_bounds,
-                   const Region& layer_invalidation,
-                   float minimum_contents_scale,
-                   RasterSource* raster_source);
+  // TODO(danakj): Remove this !!!
+  bool SyncTilingsForTesting(const PictureLayerTilingSet& other,
+                             const gfx::Size& new_layer_bounds,
+                             const Region& layer_invalidation,
+                             float minimum_contents_scale,
+                             RasterSource* raster_source);
+
+  void UpdateTilingsToCurrentRasterSource(
+      RasterSource* raster_source,
+      const PictureLayerTilingSet* twin_set,
+      // TODO(danakj): Don't need to pass layer bounds here, we have the raster
+      // source already, and they are the same as the raster source size.
+      const gfx::Size& layer_bounds,
+      const Region& layer_invalidation,
+      float minimum_contents_scale);
 
   PictureLayerTiling* AddTiling(float contents_scale,
                                 const gfx::Size& layer_bounds);
@@ -89,6 +100,9 @@
   // exist.
   float GetMaximumContentsScale() const;
 
+  // Removes all tilings with a contents scale < |minimum_scale|.
+  void RemoveTilingsBelowScale(float minimum_scale);
+
   // Remove all tilings.
   void RemoveAllTilings();
 
@@ -155,14 +169,22 @@
   TilingRange GetTilingRange(TilingRangeType type) const;
 
  private:
-  explicit PictureLayerTilingSet(PictureLayerTilingClient* client);
+  explicit PictureLayerTilingSet(
+      PictureLayerTilingClient* client,
+      size_t max_tiles_for_interest_area,
+      float skewport_target_time_in_seconds,
+      int skewport_extrapolation_limit_in_content_pixels);
 
   // Remove one tiling.
   void Remove(PictureLayerTiling* tiling);
 
-  PictureLayerTilingClient* client_;
   ScopedPtrVector<PictureLayerTiling> tilings_;
 
+  const size_t max_tiles_for_interest_area_;
+  const float skewport_target_time_in_seconds_;
+  const int skewport_extrapolation_limit_in_content_pixels_;
+  PictureLayerTilingClient* client_;
+
   friend class Iterator;
   DISALLOW_COPY_AND_ASSIGN(PictureLayerTilingSet);
 };
diff --git a/cc/resources/picture_layer_tiling_set_unittest.cc b/cc/resources/picture_layer_tiling_set_unittest.cc
index 7acc55b..cfde42e 100644
--- a/cc/resources/picture_layer_tiling_set_unittest.cc
+++ b/cc/resources/picture_layer_tiling_set_unittest.cc
@@ -18,10 +18,19 @@
 namespace cc {
 namespace {
 
+scoped_ptr<PictureLayerTilingSet> CreateTilingSet(
+    PictureLayerTilingClient* client) {
+  LayerTreeSettings defaults;
+  return PictureLayerTilingSet::Create(
+      client, defaults.max_tiles_for_interest_area,
+      defaults.skewport_target_time_in_seconds,
+      defaults.skewport_extrapolation_limit_in_content_pixels);
+}
+
 TEST(PictureLayerTilingSetTest, NoResources) {
   FakePictureLayerTilingClient client;
   gfx::Size layer_bounds(1000, 800);
-  auto set = PictureLayerTilingSet::Create(&client);
+  auto set = CreateTilingSet(&client);
   client.SetTileSize(gfx::Size(256, 256));
 
   set->AddTiling(1.0, layer_bounds);
@@ -59,7 +68,7 @@
   PictureLayerTiling* high_res_tiling;
   PictureLayerTiling* low_res_tiling;
 
-  auto set = PictureLayerTilingSet::Create(&client);
+  auto set = CreateTilingSet(&client);
   set->AddTiling(2.0, layer_bounds);
   high_res_tiling = set->AddTiling(1.0, layer_bounds);
   high_res_tiling->set_resolution(HIGH_RESOLUTION);
@@ -91,7 +100,7 @@
   EXPECT_EQ(4u, lower_than_low_res_range.start);
   EXPECT_EQ(5u, lower_than_low_res_range.end);
 
-  auto set_without_low_res = PictureLayerTilingSet::Create(&client);
+  auto set_without_low_res = CreateTilingSet(&client);
   set_without_low_res->AddTiling(2.0, layer_bounds);
   high_res_tiling = set_without_low_res->AddTiling(1.0, layer_bounds);
   high_res_tiling->set_resolution(HIGH_RESOLUTION);
@@ -121,7 +130,7 @@
       PictureLayerTilingSet::LOWER_THAN_LOW_RES);
   EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
 
-  auto set_with_only_high_and_low_res = PictureLayerTilingSet::Create(&client);
+  auto set_with_only_high_and_low_res = CreateTilingSet(&client);
   high_res_tiling =
       set_with_only_high_and_low_res->AddTiling(1.0, layer_bounds);
   high_res_tiling->set_resolution(HIGH_RESOLUTION);
@@ -153,7 +162,7 @@
       PictureLayerTilingSet::LOWER_THAN_LOW_RES);
   EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
 
-  auto set_with_only_high_res = PictureLayerTilingSet::Create(&client);
+  auto set_with_only_high_res = CreateTilingSet(&client);
   high_res_tiling = set_with_only_high_res->AddTiling(1.0, layer_bounds);
   high_res_tiling->set_resolution(HIGH_RESOLUTION);
 
@@ -209,7 +218,7 @@
     client.SetTileSize(gfx::Size(256, 256));
     client.set_tree(PENDING_TREE);
     gfx::Size layer_bounds(1000, 800);
-    auto set = PictureLayerTilingSet::Create(&client);
+    auto set = CreateTilingSet(&client);
 
     float scale = min_scale;
     for (int i = 0; i < num_tilings; ++i, scale += scale_increment) {
@@ -288,8 +297,8 @@
     source_client_.set_tree(PENDING_TREE);
     target_client_.SetTileSize(tile_size_);
     target_client_.set_tree(PENDING_TREE);
-    source_ = PictureLayerTilingSet::Create(&source_client_);
-    target_ = PictureLayerTilingSet::Create(&target_client_);
+    source_ = CreateTilingSet(&source_client_);
+    target_ = CreateTilingSet(&target_client_);
   }
 
   // Sync from source to target.
@@ -301,8 +310,9 @@
     for (size_t i = 0; i < target_->num_tilings(); ++i)
       target_->tiling_at(i)->CreateAllTilesForTesting();
 
-    target_->SyncTilings(*source_.get(), new_bounds, invalidation,
-                         minimum_scale, target_client_.raster_source());
+    target_->SyncTilingsForTesting(*source_.get(), new_bounds, invalidation,
+                                   minimum_scale,
+                                   target_client_.raster_source());
   }
   void SyncTilings(const gfx::Size& new_bounds) {
     Region invalidation;
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index 9190b98..1ed4613 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -54,17 +54,16 @@
   static scoped_ptr<TestablePictureLayerTiling> Create(
       float contents_scale,
       const gfx::Size& layer_bounds,
-      PictureLayerTilingClient* client) {
+      PictureLayerTilingClient* client,
+      const LayerTreeSettings& settings) {
     return make_scoped_ptr(new TestablePictureLayerTiling(
-        contents_scale,
-        layer_bounds,
-        client));
+        contents_scale, layer_bounds, client,
+        settings.max_tiles_for_interest_area,
+        settings.skewport_target_time_in_seconds,
+        settings.skewport_extrapolation_limit_in_content_pixels));
   }
 
   gfx::Rect live_tiles_rect() const { return live_tiles_rect_; }
-  bool eviction_tiles_cache_valid() const {
-    return eviction_tiles_cache_valid_;
-  }
 
   using PictureLayerTiling::ComputeSkewport;
   using PictureLayerTiling::RemoveTileAt;
@@ -72,8 +71,16 @@
  protected:
   TestablePictureLayerTiling(float contents_scale,
                              const gfx::Size& layer_bounds,
-                             PictureLayerTilingClient* client)
-      : PictureLayerTiling(contents_scale, layer_bounds, client) { }
+                             PictureLayerTilingClient* client,
+                             size_t max_tiles_for_interest_area,
+                             float skewport_target_time,
+                             int skewport_extrapolation_limit)
+      : PictureLayerTiling(contents_scale,
+                           layer_bounds,
+                           client,
+                           max_tiles_for_interest_area,
+                           skewport_target_time,
+                           skewport_extrapolation_limit) {}
 };
 
 class PictureLayerTilingIteratorTest : public testing::Test {
@@ -86,9 +93,8 @@
                   const gfx::Size& layer_bounds) {
     client_.SetTileSize(tile_size);
     client_.set_tree(PENDING_TREE);
-    tiling_ = TestablePictureLayerTiling::Create(contents_scale,
-                                                 layer_bounds,
-                                                 &client_);
+    tiling_ = TestablePictureLayerTiling::Create(contents_scale, layer_bounds,
+                                                 &client_, LayerTreeSettings());
   }
 
   void SetLiveRectAndVerifyTiles(const gfx::Rect& live_tiles_rect) {
@@ -180,10 +186,6 @@
     VerifyTilesExactlyCoverRect(rect_scale, dest_rect, clamped_rect);
   }
 
-  void set_max_tiles_for_interest_area(size_t area) {
-    client_.set_max_tiles_for_interest_area(area);
-  }
-
  protected:
   FakePictureLayerTilingClient client_;
   scoped_ptr<TestablePictureLayerTiling> tiling_;
@@ -208,14 +210,15 @@
 
   Region invalidation =
       SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size));
-  tiling_->UpdateTilesToCurrentRasterSource(client_.raster_source(),
-                                            invalidation, gfx::Size(200, 200));
+  tiling_->Resize(gfx::Size(200, 200));
+  EXPECT_TRUE(tiling_->TileAt(0, 0));
+  tiling_->Invalidate(invalidation);
   EXPECT_FALSE(tiling_->TileAt(0, 0));
 }
 
 TEST_F(PictureLayerTilingIteratorTest, CreateMissingTilesStaysInsideLiveRect) {
   // The tiling has three rows and columns.
-  Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 250));
+  Initialize(gfx::Size(100, 100), 1.f, gfx::Size(250, 250));
   EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
   EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y());
 
@@ -243,7 +246,7 @@
 
 TEST_F(PictureLayerTilingIteratorTest, ResizeTilingOverTileBorders) {
   // The tiling has four rows and three columns.
-  Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350));
+  Initialize(gfx::Size(100, 100), 1.f, gfx::Size(250, 350));
   EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
   EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
 
@@ -263,9 +266,7 @@
 
   // 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_->UpdateTilesToCurrentRasterSource(
-      client_.raster_source(), invalidation, gfx::Size(right + 1, bottom + 1));
+  tiling_->Resize(gfx::Size(right + 1, bottom + 1));
   EXPECT_EQ(2, tiling_->TilingDataForTesting().num_tiles_x());
   EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y());
 
@@ -282,8 +283,7 @@
 
   // Growing outside the current right/bottom tiles border pixels should create
   // the tiles again, even though the live rect has not changed size.
-  tiling_->UpdateTilesToCurrentRasterSource(
-      client_.raster_source(), invalidation, gfx::Size(right + 2, bottom + 2));
+  tiling_->Resize(gfx::Size(right + 2, bottom + 2));
   EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
   EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
 
@@ -306,7 +306,7 @@
 
 TEST_F(PictureLayerTilingIteratorTest, ResizeLiveTileRectOverTileBorders) {
   // The tiling has three rows and columns.
-  Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350));
+  Initialize(gfx::Size(100, 100), 1.f, gfx::Size(250, 350));
   EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
   EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
 
@@ -371,7 +371,7 @@
 
 TEST_F(PictureLayerTilingIteratorTest, ResizeLiveTileRectOverSameTiles) {
   // The tiling has four rows and three columns.
-  Initialize(gfx::Size(100, 100), 1, gfx::Size(250, 350));
+  Initialize(gfx::Size(100, 100), 1.f, gfx::Size(250, 350));
   EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
   EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
 
@@ -419,8 +419,9 @@
 
   Region invalidation =
       SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size));
-  tiling_->UpdateTilesToCurrentRasterSource(client_.raster_source(),
-                                            invalidation, gfx::Size(200, 200));
+  tiling_->Resize(gfx::Size(200, 200));
+  EXPECT_TRUE(tiling_->TileAt(0, 0));
+  tiling_->Invalidate(invalidation);
   EXPECT_FALSE(tiling_->TileAt(0, 0));
 
   // The original tile was the same size after resize, but it would include new
@@ -430,7 +431,7 @@
 }
 
 TEST_F(PictureLayerTilingIteratorTest, LiveTilesExactlyCoverLiveTileRect) {
-  Initialize(gfx::Size(100, 100), 1, gfx::Size(1099, 801));
+  Initialize(gfx::Size(100, 100), 1.f, gfx::Size(1099, 801));
   SetLiveRectAndVerifyTiles(gfx::Rect(100, 100));
   SetLiveRectAndVerifyTiles(gfx::Rect(101, 99));
   SetLiveRectAndVerifyTiles(gfx::Rect(1099, 1));
@@ -440,13 +441,13 @@
 }
 
 TEST_F(PictureLayerTilingIteratorTest, IteratorCoversLayerBoundsNoScale) {
-  Initialize(gfx::Size(100, 100), 1, gfx::Size(1099, 801));
+  Initialize(gfx::Size(100, 100), 1.f, gfx::Size(1099, 801));
   VerifyTilesExactlyCoverRect(1, gfx::Rect());
   VerifyTilesExactlyCoverRect(1, gfx::Rect(0, 0, 1099, 801));
   VerifyTilesExactlyCoverRect(1, gfx::Rect(52, 83, 789, 412));
 
   // With borders, a size of 3x3 = 1 pixel of content.
-  Initialize(gfx::Size(3, 3), 1, gfx::Size(10, 10));
+  Initialize(gfx::Size(3, 3), 1.f, gfx::Size(10, 10));
   VerifyTilesExactlyCoverRect(1, gfx::Rect(0, 0, 1, 1));
   VerifyTilesExactlyCoverRect(1, gfx::Rect(0, 0, 2, 2));
   VerifyTilesExactlyCoverRect(1, gfx::Rect(1, 1, 2, 2));
@@ -532,7 +533,6 @@
 
 TEST(PictureLayerTilingTest, SkewportLimits) {
   FakePictureLayerTilingClient client;
-  client.set_skewport_extrapolation_limit_in_content_pixels(75);
   client.set_tree(ACTIVE_TREE);
   scoped_ptr<TestablePictureLayerTiling> tiling;
 
@@ -540,7 +540,11 @@
   gfx::Size layer_bounds(200, 200);
 
   client.SetTileSize(gfx::Size(100, 100));
-  tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
+  LayerTreeSettings settings;
+  settings.max_tiles_for_interest_area = 10000;
+  settings.skewport_extrapolation_limit_in_content_pixels = 75;
+  tiling =
+      TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client, settings);
 
   tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
 
@@ -606,7 +610,8 @@
 
   client.SetTileSize(gfx::Size(100, 100));
   client.set_tree(ACTIVE_TREE);
-  tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
+  tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client,
+                                              LayerTreeSettings());
 
   tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
 
@@ -665,13 +670,16 @@
 
   client.SetTileSize(gfx::Size(10, 10));
   client.set_tree(ACTIVE_TREE);
+  LayerTreeSettings settings;
+  settings.max_tiles_for_interest_area = 10000;
 
   // Tiling at 0.25 scale: this should create 47x47 tiles of size 10x10.
   // The reason is that each tile has a one pixel border, so tile at (1, 2)
   // for instance begins at (8, 16) pixels. So tile at (46, 46) will begin at
   // (368, 368) and extend to the end of 1500 * 0.25 = 375 edge of the
   // tiling.
-  tiling = TestablePictureLayerTiling::Create(0.25f, layer_bounds, &client);
+  tiling = TestablePictureLayerTiling::Create(0.25f, layer_bounds, &client,
+                                              settings);
   gfx::Rect viewport_in_content_space =
       gfx::ToEnclosedRect(gfx::ScaleRect(viewport, 0.25f));
 
@@ -825,7 +833,8 @@
   EXPECT_FLOAT_EQ(8.f, priority.distance_to_visible);
 
   // Test additional scales.
-  tiling = TestablePictureLayerTiling::Create(0.2f, layer_bounds, &client);
+  tiling = TestablePictureLayerTiling::Create(0.2f, layer_bounds, &client,
+                                              LayerTreeSettings());
   tiling->ComputeTilePriorityRects(viewport, 1.0f, 4.0, Occlusion());
   tiling->UpdateAllTilePrioritiesForTesting();
 
@@ -1085,8 +1094,11 @@
 
   client.SetTileSize(gfx::Size(30, 30));
   client.set_tree(ACTIVE_TREE);
+  LayerTreeSettings settings;
+  settings.max_tiles_for_interest_area = 10000;
 
-  tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
+  tiling =
+      TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client, settings);
   tiling->ComputeTilePriorityRects(viewport, 1.0f, 1.0, Occlusion());
   tiling->UpdateAllTilePrioritiesForTesting();
 
@@ -1190,8 +1202,11 @@
 
   client.SetTileSize(gfx::Size(30, 30));
   client.set_tree(ACTIVE_TREE);
+  LayerTreeSettings settings;
+  settings.max_tiles_for_interest_area = 10000;
 
-  tiling = TestablePictureLayerTiling::Create(1.f, layer_bounds, &client);
+  tiling =
+      TestablePictureLayerTiling::Create(1.f, layer_bounds, &client, settings);
   tiling->ComputeTilePriorityRects(viewport, 1.0f, 1.0, Occlusion());
   tiling->ComputeTilePriorityRects(moved_viewport, 1.0f, 2.0, Occlusion());
   tiling->UpdateAllTilePrioritiesForTesting();
@@ -1326,14 +1341,19 @@
 TEST_F(PictureLayerTilingIteratorTest,
        TilesExistLargeViewportAndLayerWithSmallVisibleArea) {
   gfx::Size layer_bounds(10000, 10000);
-  Initialize(gfx::Size(100, 100), 1.f, layer_bounds);
+  client_.SetTileSize(gfx::Size(100, 100));
+  client_.set_tree(PENDING_TREE);
+  LayerTreeSettings settings;
+  settings.max_tiles_for_interest_area = 1;
+
+  tiling_ =
+      TestablePictureLayerTiling::Create(1.f, layer_bounds, &client_, settings);
   VerifyTilesExactlyCoverRect(1.f, gfx::Rect(layer_bounds));
   VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, false));
 
   gfx::Rect visible_rect(8000, 8000, 50, 50);
 
   client_.set_tree(ACTIVE_TREE);
-  set_max_tiles_for_interest_area(1);
   tiling_->ComputeTilePriorityRects(visible_rect,  // visible content rect
                                     1.f,           // current contents scale
                                     1.0,           // current frame time
@@ -1350,7 +1370,10 @@
   client_.SetTileSize(tile_size);
   client_.set_tree(PENDING_TREE);
 
-  auto active_set = PictureLayerTilingSet::Create(&client_);
+  LayerTreeSettings defaults;
+  auto active_set = PictureLayerTilingSet::Create(
+      &client_, 10000, defaults.skewport_target_time_in_seconds,
+      defaults.skewport_extrapolation_limit_in_content_pixels);
 
   active_set->AddTiling(1.f, layer_bounds);
 
@@ -1367,10 +1390,12 @@
               base::Bind(&TileExists, true));
 
   // Add the same tilings to the pending set.
-  auto pending_set = PictureLayerTilingSet::Create(&client_);
+  auto pending_set = PictureLayerTilingSet::Create(
+      &client_, 10000, defaults.skewport_target_time_in_seconds,
+      defaults.skewport_extrapolation_limit_in_content_pixels);
   Region invalidation;
-  pending_set->SyncTilings(*active_set, layer_bounds, invalidation, 0.f,
-                           client_.raster_source());
+  pending_set->SyncTilingsForTesting(*active_set, layer_bounds, invalidation,
+                                     0.f, client_.raster_source());
 
   // The pending tiling starts with no tiles.
   VerifyTiles(pending_set->tiling_at(0), 1.f, gfx::Rect(layer_bounds),
@@ -1407,8 +1432,8 @@
   client.SetTileSize(gfx::Size(100, 100));
   client.set_tree(ACTIVE_TREE);
   tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                              current_layer_bounds,
-                                              &client);
+                                              current_layer_bounds, &client,
+                                              LayerTreeSettings());
 
   tiling->ComputeTilePriorityRects(viewport_in_layer_space,
                                    current_layer_contents_scale,
@@ -1461,8 +1486,8 @@
   client.SetTileSize(gfx::Size(100, 100));
   client.set_tree(ACTIVE_TREE);
   tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                              current_layer_bounds,
-                                              &client);
+                                              current_layer_bounds, &client,
+                                              LayerTreeSettings());
 
   tiling->ComputeTilePriorityRects(viewport_in_layer_space,
                                    current_layer_contents_scale,
@@ -1525,8 +1550,8 @@
   client.SetTileSize(gfx::Size(100, 100));
   client.set_tree(ACTIVE_TREE);
   tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                              current_layer_bounds,
-                                              &client);
+                                              current_layer_bounds, &client,
+                                              LayerTreeSettings());
 
   tiling->ComputeTilePriorityRects(viewport_in_layer_space,
                                    current_layer_contents_scale,
@@ -1583,8 +1608,8 @@
   client.SetTileSize(gfx::Size(100, 100));
   client.set_tree(ACTIVE_TREE);
   tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                              current_layer_bounds,
-                                              &client);
+                                              current_layer_bounds, &client,
+                                              LayerTreeSettings());
 
   tiling->ComputeTilePriorityRects(viewport_in_layer_space,
                                    current_layer_contents_scale,
@@ -1665,8 +1690,8 @@
   client.SetTileSize(gfx::Size(100, 100));
   client.set_tree(ACTIVE_TREE);
   tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                              current_layer_bounds,
-                                              &client);
+                                              current_layer_bounds, &client,
+                                              LayerTreeSettings());
 
   tiling->ComputeTilePriorityRects(viewport_in_layer_space,
                                    current_layer_contents_scale,
@@ -1757,8 +1782,8 @@
   client.SetTileSize(gfx::Size(100, 100));
   client.set_tree(ACTIVE_TREE);
   tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                              current_layer_bounds,
-                                              &client);
+                                              current_layer_bounds, &client,
+                                              LayerTreeSettings());
 
   tiling->ComputeTilePriorityRects(viewport_in_layer_space,
                                    current_layer_contents_scale,
@@ -1818,9 +1843,11 @@
 
   client.SetTileSize(gfx::Size(100, 100));
   client.set_tree(ACTIVE_TREE);
+  LayerTreeSettings settings;
+  settings.max_tiles_for_interest_area = 10000;
   tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                              current_layer_bounds,
-                                              &client);
+                                              current_layer_bounds, &client,
+                                              settings);
 
   // previous ("last") frame
   tiling->ComputeTilePriorityRects(viewport_in_layer_space,
@@ -1894,8 +1921,8 @@
   client.SetTileSize(gfx::Size(100, 100));
   client.set_tree(ACTIVE_TREE);
   tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                              current_layer_bounds,
-                                              &client);
+                                              current_layer_bounds, &client,
+                                              LayerTreeSettings());
 
   // previous ("last") frame
   tiling->ComputeTilePriorityRects(viewport_in_layer_space,
@@ -1942,10 +1969,11 @@
 
   active_client.SetTileSize(gfx::Size(100, 100));
   active_client.set_tree(ACTIVE_TREE);
-  active_client.set_max_tiles_for_interest_area(10);
+  LayerTreeSettings settings;
+  settings.max_tiles_for_interest_area = 10;
   active_tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
                                                      gfx::Size(10000, 10000),
-                                                     &active_client);
+                                                     &active_client, settings);
   // Create all tiles on this tiling.
   active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f,
                                           Occlusion());
@@ -1954,12 +1982,11 @@
   recycle_client.SetTileSize(gfx::Size(100, 100));
   recycle_client.set_tree(PENDING_TREE);
   recycle_client.set_twin_tiling(active_tiling.get());
-  recycle_client.set_max_tiles_for_interest_area(10);
 
   scoped_ptr<TestablePictureLayerTiling> recycle_tiling;
-  recycle_tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                                      gfx::Size(10000, 10000),
-                                                      &recycle_client);
+  recycle_tiling = TestablePictureLayerTiling::Create(
+      1.0f,  // contents_scale
+      gfx::Size(10000, 10000), &recycle_client, settings);
 
   // Create all tiles on the second tiling. All tiles should be shared.
   recycle_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f,
@@ -1986,9 +2013,9 @@
   active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 3.0,
                                           Occlusion());
 
-  // Ensure that we now have a tile here, but the recycle tiling does not.
+  // Ensure that we now have a tile here on both tilings again.
   EXPECT_TRUE(active_tiling->TileAt(0, 0));
-  EXPECT_FALSE(recycle_tiling->TileAt(0, 0));
+  EXPECT_TRUE(recycle_tiling->TileAt(0, 0));
 }
 
 TEST(PictureLayerTilingTest, RecycledTilesClearedOnReset) {
@@ -1997,9 +2024,9 @@
 
   active_client.SetTileSize(gfx::Size(100, 100));
   active_client.set_tree(ACTIVE_TREE);
-  active_tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                                     gfx::Size(100, 100),
-                                                     &active_client);
+  active_tiling = TestablePictureLayerTiling::Create(
+      1.0f,  // contents_scale
+      gfx::Size(100, 100), &active_client, LayerTreeSettings());
   // Create all tiles on this tiling.
   active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f,
                                           Occlusion());
@@ -2008,12 +2035,13 @@
   recycle_client.SetTileSize(gfx::Size(100, 100));
   recycle_client.set_tree(PENDING_TREE);
   recycle_client.set_twin_tiling(active_tiling.get());
-  recycle_client.set_max_tiles_for_interest_area(10);
 
+  LayerTreeSettings settings;
+  settings.max_tiles_for_interest_area = 10;
   scoped_ptr<TestablePictureLayerTiling> recycle_tiling;
-  recycle_tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
-                                                      gfx::Size(100, 100),
-                                                      &recycle_client);
+  recycle_tiling = TestablePictureLayerTiling::Create(
+      1.0f,  // contents_scale
+      gfx::Size(100, 100), &recycle_client, settings);
 
   // Create all tiles on the recycle tiling. All tiles should be shared.
   recycle_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f,
@@ -2037,7 +2065,7 @@
 
 TEST_F(PictureLayerTilingIteratorTest, ResizeTilesAndUpdateToCurrent) {
   // The tiling has four rows and three columns.
-  Initialize(gfx::Size(150, 100), 1, gfx::Size(250, 150));
+  Initialize(gfx::Size(150, 100), 1.f, gfx::Size(250, 150));
   tiling_->CreateAllTilesForTesting();
   EXPECT_EQ(150, tiling_->TilingDataForTesting().max_texture_size().width());
   EXPECT_EQ(100, tiling_->TilingDataForTesting().max_texture_size().height());
@@ -2050,9 +2078,7 @@
   EXPECT_EQ(150, tiling_->TilingDataForTesting().max_texture_size().width());
   EXPECT_EQ(100, tiling_->TilingDataForTesting().max_texture_size().height());
 
-  Region invalidation;
-  tiling_->UpdateTilesToCurrentRasterSource(client_.raster_source(),
-                                            invalidation, gfx::Size(250, 150));
+  tiling_->Resize(gfx::Size(250, 150));
 
   // Tile size in the tiling should be resized to 250x200.
   EXPECT_EQ(250, tiling_->TilingDataForTesting().max_texture_size().width());
diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc
index 698fe2c..31bc2d3 100644
--- a/cc/resources/picture_pile.cc
+++ b/cc/resources/picture_pile.cc
@@ -693,9 +693,10 @@
     if (it->second.GetPicture() != picture)
       return;
   }
-  skia::AnalysisCanvas canvas(recorded_viewport_.width(),
-                              recorded_viewport_.height());
-  canvas.translate(-recorded_viewport_.x(), -recorded_viewport_.y());
+
+  gfx::Size layer_size = GetSize();
+  skia::AnalysisCanvas canvas(layer_size.width(), layer_size.height());
+
   picture->Raster(&canvas, nullptr, Region(), 1.0f);
   is_solid_color_ = canvas.GetColorIfSolid(&solid_color_);
 }
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index c0e8f1b..5b8bcd2 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -622,21 +622,11 @@
                         RGBA_8888);
   } else {
     DCHECK(mailbox.IsSharedMemory());
-    base::SharedMemory* shared_memory = mailbox.shared_memory();
-    DCHECK(shared_memory->memory());
-    uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory());
+    SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
+    uint8_t* pixels = shared_bitmap->pixels();
     DCHECK(pixels);
-    scoped_ptr<SharedBitmap> shared_bitmap;
-    if (shared_bitmap_manager_) {
-      shared_bitmap =
-          shared_bitmap_manager_->GetBitmapForSharedMemory(shared_memory);
-    }
-    resource = Resource(pixels,
-                        shared_bitmap.release(),
-                        mailbox.shared_memory_size(),
-                        Resource::External,
-                        GL_LINEAR,
-                        GL_CLAMP_TO_EDGE);
+    resource = Resource(pixels, shared_bitmap, mailbox.shared_memory_size(),
+                        Resource::External, GL_LINEAR, GL_CLAMP_TO_EDGE);
   }
   resource.allocated = true;
   resource.mailbox = mailbox;
@@ -714,13 +704,8 @@
       }
     } else {
       DCHECK(resource->mailbox.IsSharedMemory());
-      base::SharedMemory* shared_memory = resource->mailbox.shared_memory();
-      if (resource->pixels && shared_memory) {
-        DCHECK(shared_memory->memory() == resource->pixels);
-        resource->pixels = NULL;
-        delete resource->shared_bitmap;
-        resource->shared_bitmap = NULL;
-      }
+      resource->shared_bitmap = nullptr;
+      resource->pixels = nullptr;
     }
     resource->release_callback_impl.Run(
         sync_point, lost_resource, blocking_main_thread_task_runner_);
@@ -1123,11 +1108,6 @@
       !resource_->sk_surface.get() ||
       !SurfaceHasMatchingProperties(use_distance_field_text, can_use_lcd_text);
   if (create_surface) {
-    class GrContext* gr_context = resource_provider_->GrContext();
-    // TODO(alokp): Implement TestContextProvider::GrContext().
-    if (!gr_context)
-      return nullptr;
-
     resource_provider_->LazyAllocate(resource_);
 
     GrBackendTextureDesc desc;
@@ -1137,6 +1117,8 @@
     desc.fConfig = ToGrPixelConfig(resource_->format);
     desc.fOrigin = kTopLeft_GrSurfaceOrigin;
     desc.fTextureHandle = resource_->gl_id;
+
+    class GrContext* gr_context = resource_provider_->GrContext();
     skia::RefPtr<GrTexture> gr_texture =
         skia::AdoptRef(gr_context->wrapBackendTexture(desc));
     if (!gr_texture)
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index 2c8ed58..53741ab 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -59,15 +59,15 @@
   *release_main_thread_task_runner = main_thread_task_runner;
 }
 
-static void SharedMemoryReleaseCallback(
-    scoped_ptr<base::SharedMemory> memory,
+static void SharedBitmapReleaseCallback(
+    scoped_ptr<SharedBitmap> bitmap,
     uint32 sync_point,
     bool lost_resource,
     BlockingTaskRunner* main_thread_task_runner) {
 }
 
-static void ReleaseSharedMemoryCallback(
-    scoped_ptr<base::SharedMemory> shared_memory,
+static void ReleaseSharedBitmapCallback(
+    scoped_ptr<SharedBitmap> shared_bitmap,
     bool* release_called,
     uint32* release_sync_point,
     bool* lost_resource_result,
@@ -79,15 +79,16 @@
   *lost_resource_result = lost_resource;
 }
 
-static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory(
+static scoped_ptr<SharedBitmap> CreateAndFillSharedBitmap(
+    SharedBitmapManager* manager,
     const gfx::Size& size,
     uint32_t value) {
-  scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
-  CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea()));
-  uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_memory->memory());
+  scoped_ptr<SharedBitmap> shared_bitmap = manager->AllocateSharedBitmap(size);
+  CHECK(shared_bitmap);
+  uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_bitmap->pixels());
   CHECK(pixels);
   std::fill_n(pixels, size.GetArea(), value);
-  return shared_memory.Pass();
+  return shared_bitmap.Pass();
 }
 
 class TextureStateTrackingContext : public TestWebGraphicsContext3D {
@@ -466,32 +467,26 @@
       *sync_point = child_context_->insertSyncPoint();
       EXPECT_LT(0u, *sync_point);
 
-      scoped_ptr<base::SharedMemory> shared_memory;
+      scoped_ptr<SharedBitmap> shared_bitmap;
       scoped_ptr<SingleReleaseCallbackImpl> callback =
-          SingleReleaseCallbackImpl::Create(
-              base::Bind(ReleaseSharedMemoryCallback,
-                         base::Passed(&shared_memory),
-                         release_called,
-                         release_sync_point,
-                         lost_resource));
+          SingleReleaseCallbackImpl::Create(base::Bind(
+              ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
+              release_called, release_sync_point, lost_resource));
       return child_resource_provider_->CreateResourceFromTextureMailbox(
           TextureMailbox(gpu_mailbox, GL_TEXTURE_2D, *sync_point),
           callback.Pass());
     } else {
       gfx::Size size(64, 64);
-      scoped_ptr<base::SharedMemory> shared_memory(
-          CreateAndFillSharedMemory(size, 0));
+      scoped_ptr<SharedBitmap> shared_bitmap(
+          CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, 0));
 
-      base::SharedMemory* shared_memory_ptr = shared_memory.get();
+      SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
       scoped_ptr<SingleReleaseCallbackImpl> callback =
-          SingleReleaseCallbackImpl::Create(
-              base::Bind(ReleaseSharedMemoryCallback,
-                         base::Passed(&shared_memory),
-                         release_called,
-                         release_sync_point,
-                         lost_resource));
+          SingleReleaseCallbackImpl::Create(base::Bind(
+              ReleaseSharedBitmapCallback, base::Passed(&shared_bitmap),
+              release_called, release_sync_point, lost_resource));
       return child_resource_provider_->CreateResourceFromTextureMailbox(
-          TextureMailbox(shared_memory_ptr, size), callback.Pass());
+          TextureMailbox(shared_bitmap_ptr, size), callback.Pass());
     }
   }
 
@@ -982,14 +977,14 @@
   uint8_t data2[4] = { 5, 5, 5, 5 };
   child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
 
-  scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
-  shared_memory->CreateAndMapAnonymous(1);
-  base::SharedMemory* shared_memory_ptr = shared_memory.get();
+  scoped_ptr<SharedBitmap> shared_bitmap(CreateAndFillSharedBitmap(
+      shared_bitmap_manager_.get(), gfx::Size(1, 1), 0));
+  SharedBitmap* shared_bitmap_ptr = shared_bitmap.get();
   ResourceProvider::ResourceId id3 =
       child_resource_provider_->CreateResourceFromTextureMailbox(
-          TextureMailbox(shared_memory_ptr, gfx::Size(1, 1)),
+          TextureMailbox(shared_bitmap_ptr, gfx::Size(1, 1)),
           SingleReleaseCallbackImpl::Create(base::Bind(
-              &SharedMemoryReleaseCallback, base::Passed(&shared_memory))));
+              &SharedBitmapReleaseCallback, base::Passed(&shared_bitmap))));
 
   ReturnedResourceArray returned_to_child;
   int child_id =
@@ -2556,8 +2551,8 @@
 
   gfx::Size size(64, 64);
   const uint32_t kBadBeef = 0xbadbeef;
-  scoped_ptr<base::SharedMemory> shared_memory(
-      CreateAndFillSharedMemory(size, kBadBeef));
+  scoped_ptr<SharedBitmap> shared_bitmap(
+      CreateAndFillSharedBitmap(shared_bitmap_manager_.get(), size, kBadBeef));
 
   FakeOutputSurfaceClient output_surface_client;
   scoped_ptr<OutputSurface> output_surface(
@@ -2582,7 +2577,7 @@
                                                    &release_sync_point,
                                                    &lost_resource,
                                                    &main_thread_task_runner));
-  TextureMailbox mailbox(shared_memory.get(), size);
+  TextureMailbox mailbox(shared_bitmap.get(), size);
 
   ResourceProvider::ResourceId id =
       resource_provider->CreateResourceFromTextureMailbox(
diff --git a/cc/resources/scoped_gpu_raster.cc b/cc/resources/scoped_gpu_raster.cc
index 517c7a7..9d1dfe5 100644
--- a/cc/resources/scoped_gpu_raster.cc
+++ b/cc/resources/scoped_gpu_raster.cc
@@ -30,18 +30,14 @@
   gl->PushGroupMarkerEXT(0, "GpuRasterization");
 
   class GrContext* gr_context = context_provider_->GrContext();
-  // TODO(sohanjg): Remove when TestContextProvider gives a GrContext.
-  if (gr_context)
-    gr_context->resetContext();
+  gr_context->resetContext();
 }
 
 void ScopedGpuRaster::EndGpuRaster() {
   GLES2Interface* gl = context_provider_->ContextGL();
 
   class GrContext* gr_context = context_provider_->GrContext();
-  // TODO(sohanjg): Remove when TestContextProvider gives a GrContext.
-  if (gr_context)
-    gr_context->flush();
+  gr_context->flush();
 
   // TODO(alokp): Use a trace macro to push/pop markers.
   // Using push/pop functions directly incurs cost to evaluate function
diff --git a/cc/resources/shared_bitmap.h b/cc/resources/shared_bitmap.h
index bbf0823..6980afb 100644
--- a/cc/resources/shared_bitmap.h
+++ b/cc/resources/shared_bitmap.h
@@ -6,13 +6,10 @@
 #define CC_RESOURCES_SHARED_BITMAP_H_
 
 #include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "ui/gfx/geometry/size.h"
 
-namespace base { class SharedMemory; }
-
 namespace cc {
 typedef gpu::Mailbox SharedBitmapId;
 
@@ -24,8 +21,6 @@
 
   uint8* pixels() { return pixels_; }
 
-  virtual base::SharedMemory* memory() = 0;
-
   const SharedBitmapId& id() { return id_; }
 
   // Returns true if the size is valid and false otherwise.
diff --git a/cc/resources/shared_bitmap_manager.h b/cc/resources/shared_bitmap_manager.h
index fe61b09..d5239e4 100644
--- a/cc/resources/shared_bitmap_manager.h
+++ b/cc/resources/shared_bitmap_manager.h
@@ -6,6 +6,7 @@
 #define CC_RESOURCES_SHARED_BITMAP_MANAGER_H_
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
 #include "cc/resources/shared_bitmap.h"
 #include "ui/gfx/geometry/size.h"
@@ -21,8 +22,6 @@
   virtual scoped_ptr<SharedBitmap> GetSharedBitmapFromId(
       const gfx::Size&,
       const SharedBitmapId&) = 0;
-  virtual scoped_ptr<SharedBitmap> GetBitmapForSharedMemory(
-      base::SharedMemory*) = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SharedBitmapManager);
diff --git a/cc/resources/texture_mailbox.cc b/cc/resources/texture_mailbox.cc
index 07cbec0..9bf242e 100644
--- a/cc/resources/texture_mailbox.cc
+++ b/cc/resources/texture_mailbox.cc
@@ -9,25 +9,28 @@
 
 namespace cc {
 
-TextureMailbox::TextureMailbox() : shared_memory_(NULL) {}
+TextureMailbox::TextureMailbox() : shared_bitmap_(NULL) {
+}
 
 TextureMailbox::TextureMailbox(const gpu::MailboxHolder& mailbox_holder)
     : mailbox_holder_(mailbox_holder),
-      shared_memory_(NULL),
+      shared_bitmap_(NULL),
       allow_overlay_(false),
-      nearest_neighbor_(false) {}
+      nearest_neighbor_(false) {
+}
 
 TextureMailbox::TextureMailbox(const gpu::Mailbox& mailbox,
                                uint32 target,
                                uint32 sync_point)
     : mailbox_holder_(mailbox, target, sync_point),
-      shared_memory_(NULL),
+      shared_bitmap_(NULL),
       allow_overlay_(false),
-      nearest_neighbor_(false) {}
+      nearest_neighbor_(false) {
+}
 
-TextureMailbox::TextureMailbox(base::SharedMemory* shared_memory,
+TextureMailbox::TextureMailbox(SharedBitmap* shared_bitmap,
                                const gfx::Size& size)
-    : shared_memory_(shared_memory),
+    : shared_bitmap_(shared_bitmap),
       shared_memory_size_(size),
       allow_overlay_(false),
       nearest_neighbor_(false) {
@@ -44,8 +47,7 @@
                                   other.mailbox_holder_.mailbox.name,
                                   sizeof(mailbox_holder_.mailbox.name));
   } else if (other.IsSharedMemory()) {
-    return IsSharedMemory() &&
-           shared_memory_->handle() == other.shared_memory_->handle();
+    return IsSharedMemory() && (shared_bitmap_ == other.shared_bitmap_);
   }
 
   DCHECK(!other.IsValid());
diff --git a/cc/resources/texture_mailbox.h b/cc/resources/texture_mailbox.h
index 9bf41e1..cec60ce 100644
--- a/cc/resources/texture_mailbox.h
+++ b/cc/resources/texture_mailbox.h
@@ -13,6 +13,7 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace cc {
+class SharedBitmap;
 
 // TODO(skaslev, danakj) Rename this class more apropriately since now it
 // can hold a shared memory resource as well as a texture mailbox.
@@ -21,13 +22,13 @@
   TextureMailbox();
   explicit TextureMailbox(const gpu::MailboxHolder& mailbox_holder);
   TextureMailbox(const gpu::Mailbox& mailbox, uint32 target, uint32 sync_point);
-  TextureMailbox(base::SharedMemory* shared_memory, const gfx::Size& size);
+  TextureMailbox(SharedBitmap* shared_bitmap, const gfx::Size& size);
 
   ~TextureMailbox();
 
   bool IsValid() const { return IsTexture() || IsSharedMemory(); }
   bool IsTexture() const { return !mailbox_holder_.mailbox.IsZero(); }
-  bool IsSharedMemory() const { return shared_memory_ != NULL; }
+  bool IsSharedMemory() const { return shared_bitmap_ != NULL; }
 
   bool Equals(const TextureMailbox&) const;
 
@@ -46,13 +47,13 @@
     nearest_neighbor_ = nearest_neighbor;
   }
 
-  base::SharedMemory* shared_memory() const { return shared_memory_; }
+  SharedBitmap* shared_bitmap() const { return shared_bitmap_; }
   gfx::Size shared_memory_size() const { return shared_memory_size_; }
   size_t SharedMemorySizeInBytes() const;
 
  private:
   gpu::MailboxHolder mailbox_holder_;
-  base::SharedMemory* shared_memory_;
+  SharedBitmap* shared_bitmap_;
   gfx::Size shared_memory_size_;
   bool allow_overlay_;
   bool nearest_neighbor_;
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 7ab1fbf..309c2b3 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -41,7 +41,6 @@
       const void* tile_id,
       int source_frame_number,
       bool analyze_picture,
-      RenderingStatsInstrumentation* rendering_stats,
       const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>&
           reply,
       ImageDecodeTask::Vector* dependencies)
@@ -54,7 +53,6 @@
         tile_id_(tile_id),
         source_frame_number_(source_frame_number),
         analyze_picture_(analyze_picture),
-        rendering_stats_(rendering_stats),
         reply_(reply) {}
 
   // Overridden from Task:
@@ -128,7 +126,6 @@
   const void* tile_id_;
   int source_frame_number_;
   bool analyze_picture_;
-  RenderingStatsInstrumentation* rendering_stats_;
   const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>
       reply_;
   scoped_ptr<RasterBuffer> raster_buffer_;
@@ -140,11 +137,9 @@
  public:
   ImageDecodeTaskImpl(SkPixelRef* pixel_ref,
                       int layer_id,
-                      RenderingStatsInstrumentation* rendering_stats,
                       const base::Callback<void(bool was_canceled)>& reply)
       : pixel_ref_(skia::SharePtr(pixel_ref)),
         layer_id_(layer_id),
-        rendering_stats_(rendering_stats),
         reply_(reply) {}
 
   // Overridden from Task:
@@ -169,7 +164,6 @@
  private:
   skia::RefPtr<SkPixelRef> pixel_ref_;
   int layer_id_;
-  RenderingStatsInstrumentation* rendering_stats_;
   const base::Callback<void(bool was_canceled)> reply_;
 
   DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
@@ -209,11 +203,10 @@
     base::SequencedTaskRunner* task_runner,
     ResourcePool* resource_pool,
     TileTaskRunner* tile_task_runner,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation,
     size_t scheduled_raster_task_limit) {
-  return make_scoped_ptr(new TileManager(
-      client, task_runner, resource_pool, tile_task_runner,
-      rendering_stats_instrumentation, scheduled_raster_task_limit));
+  return make_scoped_ptr(new TileManager(client, task_runner, resource_pool,
+                                         tile_task_runner,
+                                         scheduled_raster_task_limit));
 }
 
 TileManager::TileManager(
@@ -221,7 +214,6 @@
     const scoped_refptr<base::SequencedTaskRunner>& task_runner,
     ResourcePool* resource_pool,
     TileTaskRunner* tile_task_runner,
-    RenderingStatsInstrumentation* rendering_stats_instrumentation,
     size_t scheduled_raster_task_limit)
     : client_(client),
       task_runner_(task_runner),
@@ -229,7 +221,6 @@
       tile_task_runner_(tile_task_runner),
       scheduled_raster_task_limit_(scheduled_raster_task_limit),
       all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
-      rendering_stats_instrumentation_(rendering_stats_instrumentation),
       did_check_for_completed_tasks_since_last_schedule_tasks_(true),
       did_oom_on_last_assign_(false),
       ready_to_activate_check_notifier_(
@@ -719,7 +710,6 @@
   return make_scoped_refptr(new ImageDecodeTaskImpl(
       pixel_ref,
       tile->layer_id(),
-      rendering_stats_instrumentation_,
       base::Bind(&TileManager::OnImageDecodeTaskCompleted,
                  base::Unretained(this),
                  tile->layer_id(),
@@ -766,7 +756,6 @@
                          static_cast<const void*>(tile),
                          tile->source_frame_number(),
                          tile->use_picture_analysis(),
-                         rendering_stats_instrumentation_,
                          base::Bind(&TileManager::OnRasterTaskCompleted,
                                     base::Unretained(this),
                                     tile->id(),
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index 638fecb..a5005bf 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -16,7 +16,6 @@
 #include "base/values.h"
 #include "cc/base/ref_counted_managed.h"
 #include "cc/base/unique_notifier.h"
-#include "cc/debug/rendering_stats_instrumentation.h"
 #include "cc/resources/eviction_tile_priority_queue.h"
 #include "cc/resources/managed_tile_state.h"
 #include "cc/resources/memory_history.h"
@@ -102,7 +101,6 @@
       base::SequencedTaskRunner* task_runner,
       ResourcePool* resource_pool,
       TileTaskRunner* tile_task_runner,
-      RenderingStatsInstrumentation* rendering_stats_instrumentation,
       size_t scheduled_raster_task_limit);
   ~TileManager() override;
 
@@ -176,7 +174,6 @@
               const scoped_refptr<base::SequencedTaskRunner>& task_runner,
               ResourcePool* resource_pool,
               TileTaskRunner* tile_task_runner,
-              RenderingStatsInstrumentation* rendering_stats_instrumentation,
               size_t scheduled_raster_task_limit);
 
   void FreeResourcesForReleasedTiles();
@@ -260,8 +257,6 @@
   bool all_tiles_that_need_to_be_rasterized_are_scheduled_;
   MemoryHistory::Entry memory_stats_from_last_assign_;
 
-  RenderingStatsInstrumentation* rendering_stats_instrumentation_;
-
   bool did_check_for_completed_tasks_since_last_schedule_tasks_;
   bool did_oom_on_last_assign_;
 
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index fdd876e..eb5d737 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -109,7 +109,7 @@
     if (old_pending_root) {
       pending_layer.reset(
           static_cast<FakePictureLayerImpl*>(old_pending_root.release()));
-      pending_layer->SetRasterSource(pile);
+      pending_layer->SetRasterSourceOnPending(pile, Region());
     } else {
       pending_layer =
           FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, pile);
@@ -124,14 +124,6 @@
     pending_layer_->DoPostCommitInitializationIfNeeded();
   }
 
-  void CreateHighLowResAndSetAllTilesVisible() {
-    // Active layer must get updated first so pending layer can share from it.
-    active_layer_->CreateDefaultTilingsAndTiles();
-    active_layer_->SetAllTilesVisible();
-    pending_layer_->CreateDefaultTilingsAndTiles();
-    pending_layer_->SetAllTilesVisible();
-  }
-
   TileManager* tile_manager() { return host_impl_.tile_manager(); }
 
  protected:
@@ -195,10 +187,8 @@
 
   // Invalidate the pending tree.
   pending_layer_->set_invalidation(invalidation);
-  pending_layer_->HighResTiling()->UpdateTilesToCurrentRasterSource(
-      pending_layer_->raster_source(), invalidation, gfx::Size(1000, 1000));
-  pending_layer_->LowResTiling()->UpdateTilesToCurrentRasterSource(
-      pending_layer_->raster_source(), invalidation, gfx::Size(1000, 1000));
+  pending_layer_->HighResTiling()->Invalidate(invalidation);
+  pending_layer_->LowResTiling()->Invalidate(invalidation);
 
   active_layer_->ResetAllTilesPriorities();
   pending_layer_->ResetAllTilesPriorities();
@@ -445,10 +435,8 @@
 
   // Invalidate the pending tree.
   pending_layer_->set_invalidation(invalidation);
-  pending_layer_->HighResTiling()->UpdateTilesToCurrentRasterSource(
-      pending_layer_->raster_source(), invalidation, gfx::Size(1000, 1000));
-  pending_layer_->LowResTiling()->UpdateTilesToCurrentRasterSource(
-      pending_layer_->raster_source(), invalidation, gfx::Size(1000, 1000));
+  pending_layer_->HighResTiling()->Invalidate(invalidation);
+  pending_layer_->LowResTiling()->Invalidate(invalidation);
 
   active_layer_->ResetAllTilesPriorities();
   pending_layer_->ResetAllTilesPriorities();
@@ -495,6 +483,8 @@
   // Here we expect to get increasing ACTIVE_TREE priority_bin.
   queue.Reset();
   host_impl_.BuildEvictionQueue(&queue, SMOOTHNESS_TAKES_PRIORITY);
+  int distance_increasing = 0;
+  int distance_decreasing = 0;
   while (!queue.IsEmpty()) {
     Tile* tile = queue.Top();
     EXPECT_TRUE(tile);
@@ -511,8 +501,11 @@
                 tile->required_for_activation());
       if (last_tile->required_for_activation() ==
           tile->required_for_activation()) {
-        EXPECT_GE(last_tile->priority(ACTIVE_TREE).distance_to_visible,
-                  tile->priority(ACTIVE_TREE).distance_to_visible);
+        if (last_tile->priority(ACTIVE_TREE).distance_to_visible >=
+            tile->priority(ACTIVE_TREE).distance_to_visible)
+          ++distance_decreasing;
+        else
+          ++distance_increasing;
       }
     }
 
@@ -522,6 +515,8 @@
     queue.Pop();
   }
 
+  EXPECT_EQ(3, distance_increasing);
+  EXPECT_EQ(16, distance_decreasing);
   EXPECT_EQ(tile_count, smoothness_tiles.size());
   EXPECT_EQ(all_tiles, smoothness_tiles);
 
@@ -530,6 +525,8 @@
   // Here we expect to get increasing PENDING_TREE priority_bin.
   queue.Reset();
   host_impl_.BuildEvictionQueue(&queue, NEW_CONTENT_TAKES_PRIORITY);
+  distance_decreasing = 0;
+  distance_increasing = 0;
   while (!queue.IsEmpty()) {
     Tile* tile = queue.Top();
     EXPECT_TRUE(tile);
@@ -545,8 +542,11 @@
                 tile->required_for_activation());
       if (last_tile->required_for_activation() ==
           tile->required_for_activation()) {
-        EXPECT_GE(last_tile->priority(PENDING_TREE).distance_to_visible,
-                  tile->priority(PENDING_TREE).distance_to_visible);
+        if (last_tile->priority(PENDING_TREE).distance_to_visible >=
+            tile->priority(PENDING_TREE).distance_to_visible)
+          ++distance_decreasing;
+        else
+          ++distance_increasing;
       }
     }
 
@@ -555,6 +555,8 @@
     queue.Pop();
   }
 
+  EXPECT_EQ(3, distance_increasing);
+  EXPECT_EQ(16, distance_decreasing);
   EXPECT_EQ(tile_count, new_content_tiles.size());
   EXPECT_EQ(all_tiles, new_content_tiles);
 }
diff --git a/cc/resources/tiling_set_eviction_queue.cc b/cc/resources/tiling_set_eviction_queue.cc
index 8c5ff52..18f659e 100644
--- a/cc/resources/tiling_set_eviction_queue.cc
+++ b/cc/resources/tiling_set_eviction_queue.cc
@@ -2,38 +2,53 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
 #include "cc/resources/tiling_set_eviction_queue.h"
 
 namespace cc {
 
 TilingSetEvictionQueue::TilingSetEvictionQueue()
     : tiling_set_(nullptr),
+      tree_(ACTIVE_TREE),
       tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES),
-      current_category_(PictureLayerTiling::EVENTUALLY),
+      skip_all_shared_tiles_(false),
+      skip_shared_out_of_order_tiles_(false),
+      processing_soon_border_rect_(false),
+      processing_tiling_with_required_for_activation_tiles_(false),
+      tiling_index_with_required_for_activation_tiles_(0u),
+      current_priority_bin_(TilePriority::EVENTUALLY),
       current_tiling_index_(0u),
       current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
-      current_eviction_tile_(nullptr),
-      eviction_tiles_(nullptr),
-      next_eviction_tile_index_(0u) {
+      current_eviction_tile_(nullptr) {
 }
 
 TilingSetEvictionQueue::TilingSetEvictionQueue(
     PictureLayerTilingSet* tiling_set,
-    TreePriority tree_priority)
+    TreePriority tree_priority,
+    bool skip_shared_out_of_order_tiles)
     : tiling_set_(tiling_set),
+      tree_(tiling_set->client()->GetTree()),
       tree_priority_(tree_priority),
-      current_category_(PictureLayerTiling::EVENTUALLY),
+      skip_all_shared_tiles_(
+          skip_shared_out_of_order_tiles &&
+          tree_priority == (tree_ == ACTIVE_TREE ? NEW_CONTENT_TAKES_PRIORITY
+                                                 : SMOOTHNESS_TAKES_PRIORITY)),
+      skip_shared_out_of_order_tiles_(skip_shared_out_of_order_tiles),
+      processing_soon_border_rect_(false),
+      processing_tiling_with_required_for_activation_tiles_(false),
+      tiling_index_with_required_for_activation_tiles_(0u),
+      current_priority_bin_(TilePriority::EVENTUALLY),
       current_tiling_index_(0u),
       current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
-      current_eviction_tile_(nullptr),
-      eviction_tiles_(nullptr),
-      next_eviction_tile_index_(0u) {
-  DCHECK(tiling_set_);
-
+      current_eviction_tile_(nullptr) {
   // Early out if the layer has no tilings.
   if (!tiling_set_->num_tilings())
     return;
 
+  tiling_index_with_required_for_activation_tiles_ =
+      TilingIndexWithRequiredForActivationTiles();
+
   current_tiling_index_ = CurrentTilingRange().start - 1u;
   AdvanceToNextValidTiling();
 }
@@ -62,60 +77,132 @@
   return current_eviction_tile_;
 }
 
-bool TilingSetEvictionQueue::AdvanceToNextCategory() {
-  // Advance to the next category. This is done only after all tiling range
-  // types within the previous category have been gone through.
-  DCHECK_EQ(current_tiling_range_type_, PictureLayerTilingSet::HIGH_RES);
-
-  switch (current_category_) {
-    case PictureLayerTiling::EVENTUALLY:
-      current_category_ =
-          PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION;
-      return true;
-    case PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
-      current_category_ = PictureLayerTiling::SOON;
-      return true;
-    case PictureLayerTiling::SOON:
-      current_category_ = PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION;
-      return true;
-    case PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION:
-      current_category_ = PictureLayerTiling::NOW;
-      return true;
-    case PictureLayerTiling::NOW:
-      current_category_ = PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION;
-      return true;
-    case PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION:
-      return false;
-  }
-  NOTREACHED();
-  return false;
-}
-
 bool TilingSetEvictionQueue::AdvanceToNextEvictionTile() {
-  // Advance to the next eviction tile within the current category and tiling.
-  // This is done while advancing to a new tiling (in which case the next
-  // eviction tile index is 0) and while popping the current tile (in which
-  // case the next eviction tile index is greater than 0).
-  DCHECK_EQ(next_eviction_tile_index_ > 0, current_eviction_tile_ != nullptr);
+  // Advance to the next eviction tile within the current priority bin and
+  // tiling. This is done while advancing to a new tiling and while popping
+  // the current tile.
 
-  while (next_eviction_tile_index_ < eviction_tiles_->size()) {
-    Tile* tile = (*eviction_tiles_)[next_eviction_tile_index_];
-    ++next_eviction_tile_index_;
-    if (tile->HasResources()) {
+  bool required_for_activation =
+      processing_tiling_with_required_for_activation_tiles_;
+
+  for (;;) {
+    while (spiral_iterator_) {
+      std::pair<int, int> next_index = spiral_iterator_.index();
+      Tile* tile = current_tiling_->TileAt(next_index.first, next_index.second);
+      ++spiral_iterator_;
+      if (!tile || !tile->HasResources())
+        continue;
+      if (skip_all_shared_tiles_ && tile->is_shared())
+        continue;
+      current_tiling_->UpdateTileAndTwinPriority(tile);
+      if (skip_shared_out_of_order_tiles_ && IsSharedOutOfOrderTile(tile))
+        continue;
+      if (tile->required_for_activation() != required_for_activation)
+        continue;
       current_eviction_tile_ = tile;
       return true;
     }
+    if (processing_soon_border_rect_) {
+      // Advance from soon border rect to skewport rect.
+      processing_soon_border_rect_ = false;
+      if (current_tiling_->has_skewport_rect_tiles_) {
+        spiral_iterator_ = TilingData::ReverseSpiralDifferenceIterator(
+            &current_tiling_->tiling_data_,
+            current_tiling_->current_skewport_rect_,
+            current_tiling_->current_visible_rect_,
+            current_tiling_->current_visible_rect_);
+        continue;
+      }
+    }
+    break;
+  }
+
+  TilePriority::PriorityBin max_tile_priority_bin =
+      current_tiling_->client_->GetMaxTilePriorityBin();
+  while (visible_iterator_) {
+    std::pair<int, int> next_index = visible_iterator_.index();
+    Tile* tile = current_tiling_->TileAt(next_index.first, next_index.second);
+    ++visible_iterator_;
+    if (!tile || !tile->HasResources())
+      continue;
+    if (skip_all_shared_tiles_ && tile->is_shared())
+      continue;
+    // If the max tile priority is not NOW, updated priorities for tiles
+    // returned by the visible iterator will not have NOW (but EVENTUALLY)
+    // priority bin and cannot therefore be required for activation tiles nor
+    // occluded NOW tiles in the current tiling.
+    if (max_tile_priority_bin <= TilePriority::NOW) {
+      // If the current tiling is a pending tree tiling, required for
+      // activation tiles can be detected without updating tile priorities.
+      if (tree_ == PENDING_TREE &&
+          current_tiling_->IsTileRequiredForActivationIfVisible(tile) !=
+              required_for_activation) {
+        continue;
+      }
+      // Unoccluded NOW tiles should be evicted (and thus returned) only after
+      // all occluded NOW tiles.
+      if (!current_tiling_->IsTileOccluded(tile)) {
+        unoccluded_now_tiles_.push_back(tile);
+        continue;
+      }
+    }
+    current_tiling_->UpdateTileAndTwinPriority(tile);
+    if (skip_shared_out_of_order_tiles_ && IsSharedOutOfOrderTile(tile))
+      continue;
+    if (tile->required_for_activation() != required_for_activation)
+      continue;
+    current_eviction_tile_ = tile;
+    return true;
+  }
+
+  while (!unoccluded_now_tiles_.empty()) {
+    // All (unoccluded) NOW tiles have the same priority bin (NOW) and the same
+    // distance to visible (0.0), so it does not matter that tiles are popped
+    // in reversed (FILO) order.
+    Tile* tile = unoccluded_now_tiles_.back();
+    unoccluded_now_tiles_.pop_back();
+    DCHECK(tile);
+    if (!tile->HasResources())
+      continue;
+    current_tiling_->UpdateTileAndTwinPriority(tile);
+    if (skip_shared_out_of_order_tiles_ && IsSharedOutOfOrderTile(tile))
+      continue;
+    if (tile->required_for_activation() != required_for_activation)
+      continue;
+    current_eviction_tile_ = tile;
+    return true;
   }
 
   current_eviction_tile_ = nullptr;
   return false;
 }
 
+bool TilingSetEvictionQueue::AdvanceToNextPriorityBin() {
+  // Advance to the next priority bin. This is done only after all tiling range
+  // types (including the required for activation tiling) within the previous
+  // priority bin have been gone through.
+  DCHECK_EQ(current_tiling_range_type_, PictureLayerTilingSet::HIGH_RES);
+
+  switch (current_priority_bin_) {
+    case TilePriority::EVENTUALLY:
+      current_priority_bin_ = TilePriority::SOON;
+      return true;
+    case TilePriority::SOON:
+      current_priority_bin_ = TilePriority::NOW;
+      return true;
+    case TilePriority::NOW:
+      return false;
+  }
+  NOTREACHED();
+  return false;
+}
+
 bool TilingSetEvictionQueue::AdvanceToNextTilingRangeType() {
-  // Advance to the next tiling range type within the current category or to
-  // the first tiling range type within the next category. This is done only
-  // after all tilings within the previous tiling range type have been gone
-  // through.
+  // Advance to the next tiling range type within the current priority bin, to
+  // the required for activation tiling range type within the current priority
+  // bin or to the first tiling range type within the next priority bin. This
+  // is done only after all tilings within the previous tiling range type have
+  // been gone through.
   DCHECK_EQ(current_tiling_index_, CurrentTilingRange().end);
 
   switch (current_tiling_range_type_) {
@@ -133,7 +220,15 @@
       current_tiling_range_type_ = PictureLayerTilingSet::HIGH_RES;
       return true;
     case PictureLayerTilingSet::HIGH_RES:
-      if (!AdvanceToNextCategory())
+      if (!processing_tiling_with_required_for_activation_tiles_ &&
+          tiling_index_with_required_for_activation_tiles_ <
+              tiling_set_->num_tilings()) {
+        processing_tiling_with_required_for_activation_tiles_ = true;
+        return true;
+      }
+      processing_tiling_with_required_for_activation_tiles_ = false;
+
+      if (!AdvanceToNextPriorityBin())
         return false;
 
       current_tiling_range_type_ = PictureLayerTilingSet::HIGHER_THAN_HIGH_RES;
@@ -145,10 +240,10 @@
 
 bool TilingSetEvictionQueue::AdvanceToNextValidTiling() {
   // Advance to the next tiling within current tiling range type or to
-  // the first tiling within the next tiling range type or category until
+  // the first tiling within the next tiling range type or priority bin until
   // the next eviction tile is found. This is done only after all eviction
-  // tiles within the previous tiling within the current category and tiling
-  // range type have been gone through.
+  // tiles within the previous tiling within the current priority bin and
+  // tiling range type have been gone through.
   DCHECK(!current_eviction_tile_);
   DCHECK_NE(current_tiling_index_, CurrentTilingRange().end);
 
@@ -159,18 +254,54 @@
         return false;
       current_tiling_index_ = CurrentTilingRange().start;
     }
+    current_tiling_ = tiling_set_->tiling_at(CurrentTilingIndex());
 
-    PictureLayerTiling* tiling = tiling_set_->tiling_at(CurrentTilingIndex());
-    eviction_tiles_ =
-        tiling->GetEvictionTiles(tree_priority_, current_category_);
-    next_eviction_tile_index_ = 0u;
-    if (AdvanceToNextEvictionTile())
-      return true;
+    switch (current_priority_bin_) {
+      case TilePriority::EVENTUALLY:
+        if (current_tiling_->has_eventually_rect_tiles_) {
+          spiral_iterator_ = TilingData::ReverseSpiralDifferenceIterator(
+              &current_tiling_->tiling_data_,
+              current_tiling_->current_eventually_rect_,
+              current_tiling_->current_skewport_rect_,
+              current_tiling_->current_soon_border_rect_);
+          if (AdvanceToNextEvictionTile())
+            return true;
+        }
+        break;
+      case TilePriority::SOON:
+        if (current_tiling_->has_skewport_rect_tiles_ ||
+            current_tiling_->has_soon_border_rect_tiles_) {
+          processing_soon_border_rect_ = true;
+          if (current_tiling_->has_soon_border_rect_tiles_)
+            spiral_iterator_ = TilingData::ReverseSpiralDifferenceIterator(
+                &current_tiling_->tiling_data_,
+                current_tiling_->current_soon_border_rect_,
+                current_tiling_->current_skewport_rect_,
+                current_tiling_->current_visible_rect_);
+          if (AdvanceToNextEvictionTile())
+            return true;
+        }
+        break;
+      case TilePriority::NOW:
+        if (current_tiling_->has_visible_rect_tiles_) {
+          visible_iterator_ =
+              TilingData::Iterator(&current_tiling_->tiling_data_,
+                                   current_tiling_->current_visible_rect_,
+                                   false /* include_borders */);
+          if (AdvanceToNextEvictionTile())
+            return true;
+        }
+        break;
+    }
   }
 }
 
 PictureLayerTilingSet::TilingRange
 TilingSetEvictionQueue::CurrentTilingRange() const {
+  if (processing_tiling_with_required_for_activation_tiles_)
+    return PictureLayerTilingSet::TilingRange(
+        tiling_index_with_required_for_activation_tiles_,
+        tiling_index_with_required_for_activation_tiles_ + 1);
   return tiling_set_->GetTilingRange(current_tiling_range_type_);
 }
 
@@ -194,4 +325,77 @@
   return 0;
 }
 
+bool TilingSetEvictionQueue::IsSharedOutOfOrderTile(const Tile* tile) const {
+  if (!tile->is_shared())
+    return false;
+
+  switch (tree_priority_) {
+    case SMOOTHNESS_TAKES_PRIORITY:
+      DCHECK_EQ(ACTIVE_TREE, tree_);
+      return false;
+    case NEW_CONTENT_TAKES_PRIORITY:
+      DCHECK_EQ(PENDING_TREE, tree_);
+      return false;
+    case SAME_PRIORITY_FOR_BOTH_TREES:
+      break;
+    case NUM_TREE_PRIORITIES:
+      NOTREACHED();
+      break;
+  }
+
+  // The priority for tile priority of a shared tile will be a combined
+  // priority thus return shared tiles from a higher priority tree as
+  // it is out of order for a lower priority tree.
+  WhichTree twin_tree = tree_ == ACTIVE_TREE ? PENDING_TREE : ACTIVE_TREE;
+  const TilePriority& priority = tile->priority(tree_);
+  const TilePriority& twin_priority = tile->priority(twin_tree);
+  if (priority.priority_bin != twin_priority.priority_bin)
+    return priority.priority_bin > twin_priority.priority_bin;
+  const bool occluded = tile->is_occluded(tree_);
+  const bool twin_occluded = tile->is_occluded(twin_tree);
+  if (occluded != twin_occluded)
+    return occluded;
+  if (priority.distance_to_visible != twin_priority.distance_to_visible)
+    return priority.distance_to_visible > twin_priority.distance_to_visible;
+
+  // If priorities are the same, it does not matter which tree returns
+  // the tile. Let's pick the pending tree.
+  return tree_ != PENDING_TREE;
 }
+
+size_t TilingSetEvictionQueue::TilingIndexWithRequiredForActivationTiles()
+    const {
+  // Returns the tiling index of the tiling with requuired for activation tiles.
+  // If no such tiling exists, returns the past-the-last index (num_tilings).
+  size_t num_tilings = tiling_set_->num_tilings();
+
+  if (tree_ == PENDING_TREE) {
+    // For the pending tree, the tiling with required for activation tiles is
+    // the high res one.
+    PictureLayerTilingSet::TilingRange high_res_tiling_range =
+        tiling_set_->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
+    if (high_res_tiling_range.start != high_res_tiling_range.end)
+      return high_res_tiling_range.start;
+  } else {
+    DCHECK_EQ(ACTIVE_TREE, tree_);
+    // Only pending tree tiles can be required for activation. They can appear
+    // also in the active tree only if they are shared. If we skip all shared
+    // tiles, there is no need to find them as they will not be returned.
+    if (skip_all_shared_tiles_)
+      return num_tilings;
+
+    // For the active tree, the tiling with required for activation tiles is
+    // the one whose twin tiling is the high res pending tiling.
+    for (size_t i = 0; i < num_tilings; ++i) {
+      const PictureLayerTiling* tiling = tiling_set_->tiling_at(i);
+      const PictureLayerTiling* pending_tiling =
+          tiling_set_->client()->GetPendingOrActiveTwinTiling(tiling);
+      if (pending_tiling && pending_tiling->resolution() == HIGH_RESOLUTION)
+        return i;
+    }
+  }
+
+  return num_tilings;
+}
+
+}  // namespace cc
diff --git a/cc/resources/tiling_set_eviction_queue.h b/cc/resources/tiling_set_eviction_queue.h
index f88ce3b..4463cc3 100644
--- a/cc/resources/tiling_set_eviction_queue.h
+++ b/cc/resources/tiling_set_eviction_queue.h
@@ -5,16 +5,79 @@
 #ifndef CC_RESOURCES_TILING_SET_EVICTION_QUEUE_H_
 #define CC_RESOURCES_TILING_SET_EVICTION_QUEUE_H_
 
+#include <vector>
+
 #include "cc/base/cc_export.h"
 #include "cc/resources/picture_layer_tiling_set.h"
 
 namespace cc {
 
+// This eviction queue returned tiles from all tilings in a tiling set in
+// the following order:
+// 1) Eventually rect tiles (EVENTUALLY tiles).
+//    1) Eventually rect tiles not required for activation from each tiling in
+//       the tiling set, in turn, in the following order:
+//       1) the first higher than high res tiling, the second one and so on
+//       2) the first lower than low res tiling, the second one and so on
+//       3) the first between high and low res tiling, the second one and so on
+//       4) low res tiling
+//       5) high res tiling
+//    2) Eventually rect tiles required for activation from the tiling with
+//       required for activation tiles. In the case of a pending tree tiling
+//       set that is the high res tiling. In the case of an active tree tiling
+//       set that is a tiling whose twin tiling is a pending tree high res
+//       tiling.
+// 2) Soon border rect and skewport rect tiles (whose priority bin is SOON
+//    unless the max tile priority bin is lowered by PictureLayerTilingClient).
+//    1) Soon border rect and skewport rect tiles not required for activation
+//       from each tiling in the tiling set.
+//        * Tilings are iterated in the same order as in the case of eventually
+//          rect tiles not required for activation.
+//        * For each tiling, first soon border rect tiles and then skewport
+//          rect tiles are returned.
+//    2) Soon border rect and skewport rect tiles required for activation from
+//       the tiling with required for activation tiles.
+//        * First soon border rect tiles and then skewport rect tiles are
+//          returned.
+// 3) Visible rect tiles (whose priority bin is NOW unless the max tile
+//    priority bin is lowered by PictureLayerTilingClient).
+//    1) Visible rect tiles not required for activation from each tiling in
+//       the tiling set.
+//        * Tilings are iterated in the same order as in the case of eventually
+//          rect tiles not required for activation.
+//        * For each tiling, first occluded tiles and then unoccluded tiles
+//          are returned.
+//    2) Visible rect tiles required for activation from the tiling with
+//       required for activation tiles.
+//        * First occluded tiles and then unoccluded tiles are returned.
+//    If the max tile priority bin is lowered by PictureLayerTilingClient,
+//    occlusion is not taken into account as occlusion is meaningful only for
+//    NOW tiles.
+//
+// Within each tiling and tile priority rect, tiles are returned in reverse
+// spiral order i.e. in (mostly) decreasing distance-to-visible order.
+//
+// If the skip_shared_out_of_order_tiles value passed to the constructor is
+// true (like it should be when there is a twin layer with a twin tiling set),
+// eviction queue does not return shared which are out of order because their
+// priority for tree priority is lowered or raised by a twin layer.
+//  * If tree_priority is SAME_PRIORITY_FOR_BOTH_TREES, this happens for
+//    a tile specific lower priority tree eviction queue (because priority for
+//    tree priority is a merged priority).
+//  * If tree priority is NEW_CONTENT_TAKES_PRIORITY, this happens for
+//    an active tree eviction queue (because priority for tree priority is
+//    the pending priority).
+//  * If tree_priority is SMOOTHNESS_TAKES_PRIORITY, this happens for a pending
+//    tree eviction queue (because priority for tree priority is the active
+//    priority).
+// Those skipped shared out of order tiles are when returned only by the twin
+// eviction queue.
 class CC_EXPORT TilingSetEvictionQueue {
  public:
   TilingSetEvictionQueue();
   TilingSetEvictionQueue(PictureLayerTilingSet* tiling_set,
-                         TreePriority tree_priority);
+                         TreePriority tree_priority,
+                         bool skip_shared_out_of_order_tiles);
   ~TilingSetEvictionQueue();
 
   Tile* Top();
@@ -23,26 +86,36 @@
   bool IsEmpty() const;
 
  private:
-  bool AdvanceToNextCategory();
   bool AdvanceToNextEvictionTile();
+  bool AdvanceToNextPriorityBin();
   bool AdvanceToNextTilingRangeType();
   bool AdvanceToNextValidTiling();
 
   PictureLayerTilingSet::TilingRange CurrentTilingRange() const;
   size_t CurrentTilingIndex() const;
+  bool IsSharedOutOfOrderTile(const Tile* tile) const;
+  size_t TilingIndexWithRequiredForActivationTiles() const;
 
   PictureLayerTilingSet* tiling_set_;
+  WhichTree tree_;
   TreePriority tree_priority_;
+  bool skip_all_shared_tiles_;
+  bool skip_shared_out_of_order_tiles_;
+  bool processing_soon_border_rect_;
+  bool processing_tiling_with_required_for_activation_tiles_;
+  size_t tiling_index_with_required_for_activation_tiles_;
 
-  PictureLayerTiling::EvictionCategory current_category_;
+  TilePriority::PriorityBin current_priority_bin_;
+  PictureLayerTiling* current_tiling_;
   size_t current_tiling_index_;
   PictureLayerTilingSet::TilingRangeType current_tiling_range_type_;
   Tile* current_eviction_tile_;
 
-  const std::vector<Tile*>* eviction_tiles_;
-  size_t next_eviction_tile_index_;
+  TilingData::ReverseSpiralDifferenceIterator spiral_iterator_;
+  TilingData::Iterator visible_iterator_;
+  std::vector<Tile*> unoccluded_now_tiles_;
 };
 
 }  // namespace cc
 
-#endif  // CC_RESOURCES_TILING_SET_RASTER_QUEUE_H_
+#endif  // CC_RESOURCES_TILING_SET_EVICTION_QUEUE_H_
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 2c9a688..edbea9b 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -4,6 +4,8 @@
 
 #include "cc/resources/video_resource_updater.h"
 
+#include <algorithm>
+
 #include "base/bind.h"
 #include "base/debug/trace_event.h"
 #include "cc/output/gl_renderer.h"
@@ -48,6 +50,7 @@
       resource_size(resource_size),
       resource_format(resource_format),
       mailbox(mailbox),
+      ref_count(0),
       frame_ptr(nullptr),
       plane_index(0) {
 }
@@ -81,17 +84,43 @@
 }
 
 VideoResourceUpdater::~VideoResourceUpdater() {
-  while (!all_resources_.empty()) {
-    resource_provider_->DeleteResource(all_resources_.back());
-    all_resources_.pop_back();
-  }
+  for (const PlaneResource& plane_resource : all_resources_)
+    resource_provider_->DeleteResource(plane_resource.resource_id);
 }
 
-void VideoResourceUpdater::DeleteResource(unsigned resource_id) {
-  resource_provider_->DeleteResource(resource_id);
-  all_resources_.erase(std::remove(all_resources_.begin(),
-                                   all_resources_.end(),
-                                   resource_id));
+VideoResourceUpdater::ResourceList::iterator
+VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size,
+                                       ResourceFormat format,
+                                       bool has_mailbox) {
+  // TODO(danakj): Abstract out hw/sw resource create/delete from
+  // ResourceProvider and stop using ResourceProvider in this class.
+  const ResourceProvider::ResourceId resource_id =
+      resource_provider_->CreateResource(plane_size, GL_CLAMP_TO_EDGE,
+                                         ResourceProvider::TextureHintImmutable,
+                                         format);
+  if (resource_id == 0)
+    return all_resources_.end();
+
+  gpu::Mailbox mailbox;
+  if (has_mailbox) {
+    DCHECK(context_provider_);
+
+    gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
+
+    GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
+    ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id);
+    GLC(gl, gl->ProduceTextureDirectCHROMIUM(lock.texture_id(), GL_TEXTURE_2D,
+                                             mailbox.name));
+  }
+  all_resources_.push_front(
+      PlaneResource(resource_id, plane_size, format, mailbox));
+  return all_resources_.begin();
+}
+
+void VideoResourceUpdater::DeleteResource(ResourceList::iterator resource_it) {
+  DCHECK_EQ(resource_it->ref_count, 0);
+  resource_provider_->DeleteResource(resource_it->resource_id);
+  all_resources_.erase(resource_it);
 }
 
 VideoFrameExternalResources VideoResourceUpdater::
@@ -157,19 +186,15 @@
 #endif  // defined(VIDEO_HOLE)
 
   // Only YUV software video frames are supported.
-  DCHECK(input_frame_format == media::VideoFrame::YV12 ||
-         input_frame_format == media::VideoFrame::I420 ||
-         input_frame_format == media::VideoFrame::YV12A ||
-         input_frame_format == media::VideoFrame::YV12J ||
-         input_frame_format == media::VideoFrame::YV16 ||
-         input_frame_format == media::VideoFrame::YV24);
   if (input_frame_format != media::VideoFrame::YV12 &&
       input_frame_format != media::VideoFrame::I420 &&
       input_frame_format != media::VideoFrame::YV12A &&
       input_frame_format != media::VideoFrame::YV12J &&
       input_frame_format != media::VideoFrame::YV16 &&
-      input_frame_format != media::VideoFrame::YV24)
+      input_frame_format != media::VideoFrame::YV24) {
+    NOTREACHED() << input_frame_format;
     return VideoFrameExternalResources();
+  }
 
   bool software_compositor = context_provider_ == NULL;
 
@@ -186,81 +211,69 @@
     output_plane_count = 1;
   }
 
-  int max_resource_size = resource_provider_->max_texture_size();
-  std::vector<PlaneResource> plane_resources;
-  bool allocation_success = true;
+  // Drop recycled resources that are the wrong format.
+  for (auto it = all_resources_.begin(); it != all_resources_.end();) {
+    if (it->ref_count == 0 && it->resource_format != output_resource_format)
+      DeleteResource(it++);
+    else
+      ++it;
+  }
 
+  const int max_resource_size = resource_provider_->max_texture_size();
+  std::vector<ResourceList::iterator> plane_resources;
   for (size_t i = 0; i < output_plane_count; ++i) {
     gfx::Size output_plane_resource_size =
         SoftwarePlaneDimension(video_frame, software_compositor, i);
     if (output_plane_resource_size.IsEmpty() ||
         output_plane_resource_size.width() > max_resource_size ||
         output_plane_resource_size.height() > max_resource_size) {
-      allocation_success = false;
       break;
     }
 
     // Try recycle a previously-allocated resource.
-    auto recycled_it = recycled_resources_.end();
-    for (auto it = recycled_resources_.begin(); it != recycled_resources_.end();
-         ++it) {
-      const bool resource_matches =
-          it->resource_format == output_resource_format &&
-          it->resource_size == output_plane_resource_size;
-      const bool in_use = software_compositor &&
-                          resource_provider_->InUseByConsumer(it->resource_id);
-      if (resource_matches && !in_use) {
-        // We found a recycled resource with the allocation size and format we
-        // are looking for.
-        recycled_it = it;
-        // Keep looking for a recycled resource that also contains the data we
-        // are planning to put in it.
-        if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i))
+    ResourceList::iterator resource_it = all_resources_.end();
+    for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) {
+      if (it->resource_size == output_plane_resource_size &&
+          it->resource_format == output_resource_format) {
+        if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i)) {
+          // Bingo, we found a resource that already contains the data we are
+          // planning to put in it. It's safe to reuse it even if
+          // resource_provider_ holds some references to it, because those
+          // references are read-only.
+          resource_it = it;
           break;
+        }
+
+        // This extra check is needed because resources backed by SharedMemory
+        // are not ref-counted, unlike mailboxes. Full discussion in
+        // codereview.chromium.org/145273021.
+        const bool in_use =
+            software_compositor &&
+            resource_provider_->InUseByConsumer(it->resource_id);
+        if (it->ref_count == 0 && !in_use) {
+          // We found a resource with the correct size that we can overwrite.
+          resource_it = it;
+        }
       }
     }
 
-    // Check if we can avoid allocating a new resource.
-    if (recycled_it != recycled_resources_.end()) {
-      plane_resources.push_back(*recycled_it);
-      recycled_resources_.erase(recycled_it);
-      continue;
+    // Check if we need to allocate a new resource.
+    if (resource_it == all_resources_.end()) {
+      resource_it =
+          AllocateResource(output_plane_resource_size, output_resource_format,
+                           !software_compositor);
     }
-
-    // TODO(danakj): Abstract out hw/sw resource create/delete from
-    // ResourceProvider and stop using ResourceProvider in this class.
-    const ResourceProvider::ResourceId resource_id =
-        resource_provider_->CreateResource(
-            output_plane_resource_size, GL_CLAMP_TO_EDGE,
-            ResourceProvider::TextureHintImmutable, output_resource_format);
-    if (resource_id == 0) {
-      allocation_success = false;
+    if (resource_it == all_resources_.end())
       break;
-    }
-    all_resources_.push_back(resource_id);
 
-    gpu::Mailbox mailbox;
-    if (!software_compositor) {
-      DCHECK(context_provider_);
-
-      gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
-
-      GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
-      ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id);
-      GLC(gl, gl->ProduceTextureDirectCHROMIUM(lock.texture_id(), GL_TEXTURE_2D,
-                                               mailbox.name));
-    }
-
-    DCHECK(software_compositor || !mailbox.IsZero());
-    plane_resources.push_back(PlaneResource(resource_id,
-                                            output_plane_resource_size,
-                                            output_resource_format,
-                                            mailbox));
+    ++resource_it->ref_count;
+    plane_resources.push_back(resource_it);
   }
 
-  if (!allocation_success) {
-    for (size_t i = 0; i < plane_resources.size(); ++i)
-      DeleteResource(plane_resources[i].resource_id);
+  if (plane_resources.size() != output_plane_count) {
+    // Allocation failed, nothing will be returned so restore reference counts.
+    for (ResourceList::iterator resource_it : plane_resources)
+      --resource_it->ref_count;
     return VideoFrameExternalResources();
   }
 
@@ -268,54 +281,52 @@
 
   if (software_compositor) {
     DCHECK_EQ(plane_resources.size(), 1u);
-    DCHECK_EQ(plane_resources[0].resource_format, kRGBResourceFormat);
-    DCHECK(plane_resources[0].mailbox.IsZero());
+    PlaneResource& plane_resource = *plane_resources[0];
+    DCHECK_EQ(plane_resource.resource_format, kRGBResourceFormat);
+    DCHECK(plane_resource.mailbox.IsZero());
 
-    if (!PlaneResourceMatchesUniqueID(plane_resources[0], video_frame.get(),
-                                      0)) {
+    if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), 0)) {
       // We need to transfer data from |video_frame| to the plane resource.
       if (!video_renderer_)
         video_renderer_.reset(new media::SkCanvasVideoRenderer);
 
       ResourceProvider::ScopedWriteLockSoftware lock(
-          resource_provider_, plane_resources[0].resource_id);
+          resource_provider_, plane_resource.resource_id);
       SkCanvas canvas(lock.sk_bitmap());
       video_renderer_->Copy(video_frame, &canvas);
-      SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resources[0]);
+      SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resource);
     }
 
-    external_resources.software_resources.push_back(
-        plane_resources[0].resource_id);
+    external_resources.software_resources.push_back(plane_resource.resource_id);
     external_resources.software_release_callback =
-        base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[0]);
+        base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id);
     external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
-
     return external_resources;
   }
 
   for (size_t i = 0; i < plane_resources.size(); ++i) {
+    PlaneResource& plane_resource = *plane_resources[i];
     // Update each plane's resource id with its content.
-    DCHECK_EQ(plane_resources[i].resource_format,
+    DCHECK_EQ(plane_resource.resource_format,
               resource_provider_->yuv_resource_format());
 
-    if (!PlaneResourceMatchesUniqueID(plane_resources[i], video_frame.get(),
-                                      i)) {
+    if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), i)) {
       // We need to transfer data from |video_frame| to the plane resource.
       const uint8_t* input_plane_pixels = video_frame->data(i);
 
       gfx::Rect image_rect(0, 0, video_frame->stride(i),
-                           plane_resources[i].resource_size.height());
-      gfx::Rect source_rect(plane_resources[i].resource_size);
-      resource_provider_->SetPixels(plane_resources[i].resource_id,
+                           plane_resource.resource_size.height());
+      gfx::Rect source_rect(plane_resource.resource_size);
+      resource_provider_->SetPixels(plane_resource.resource_id,
                                     input_plane_pixels, image_rect, source_rect,
                                     gfx::Vector2d());
-      SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resources[i]);
+      SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resource);
     }
 
     external_resources.mailboxes.push_back(
-        TextureMailbox(plane_resources[i].mailbox, GL_TEXTURE_2D, 0));
+        TextureMailbox(plane_resource.mailbox, GL_TEXTURE_2D, 0));
     external_resources.release_callbacks.push_back(
-        base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[i]));
+        base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id));
   }
 
   external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
@@ -382,7 +393,7 @@
 // static
 void VideoResourceUpdater::RecycleResource(
     base::WeakPtr<VideoResourceUpdater> updater,
-    PlaneResource data,
+    ResourceProvider::ResourceId resource_id,
     uint32 sync_point,
     bool lost_resource,
     BlockingTaskRunner* main_thread_task_runner) {
@@ -391,6 +402,14 @@
     return;
   }
 
+  const ResourceList::iterator resource_it = std::find_if(
+      updater->all_resources_.begin(), updater->all_resources_.end(),
+      [resource_id](const PlaneResource& plane_resource) {
+        return plane_resource.resource_id == resource_id;
+      });
+  if (resource_it == updater->all_resources_.end())
+    return;
+
   ContextProvider* context_provider = updater->context_provider_;
   if (context_provider && sync_point) {
     GLC(context_provider->ContextGL(),
@@ -398,19 +417,13 @@
   }
 
   if (lost_resource) {
-    updater->DeleteResource(data.resource_id);
+    resource_it->ref_count = 0;
+    updater->DeleteResource(resource_it);
     return;
   }
 
-  // Drop recycled resources that are the wrong format.
-  while (!updater->recycled_resources_.empty() &&
-         updater->recycled_resources_.back().resource_format !=
-             data.resource_format) {
-    updater->DeleteResource(updater->recycled_resources_.back().resource_id);
-    updater->recycled_resources_.pop_back();
-  }
-
-  updater->recycled_resources_.push_back(data);
+  --resource_it->ref_count;
+  DCHECK_GE(resource_it->ref_count, 0);
 }
 
 }  // namespace cc
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index 38f6033..622fe68 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -5,6 +5,7 @@
 #ifndef CC_RESOURCES_VIDEO_RESOURCE_UPDATER_H_
 #define CC_RESOURCES_VIDEO_RESOURCE_UPDATER_H_
 
+#include <list>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -78,6 +79,9 @@
     gfx::Size resource_size;
     ResourceFormat resource_format;
     gpu::Mailbox mailbox;
+    // The balance between the number of times this resource has been returned
+    // from CreateForSoftwarePlanes vs released in RecycleResource.
+    int ref_count;
     // These last three members will be used for identifying the data stored in
     // this resource, and uniquely identifies a media::VideoFrame plane. The
     // frame pointer will only be used for pointer comparison, i.e. the
@@ -100,7 +104,13 @@
                                        int plane_index,
                                        PlaneResource* plane_resource);
 
-  void DeleteResource(unsigned resource_id);
+  // This needs to be a container where iterators can be erased without
+  // invalidating other iterators.
+  typedef std::list<PlaneResource> ResourceList;
+  ResourceList::iterator AllocateResource(const gfx::Size& plane_size,
+                                          ResourceFormat format,
+                                          bool has_mailbox);
+  void DeleteResource(ResourceList::iterator resource_it);
   bool VerifyFrame(const scoped_refptr<media::VideoFrame>& video_frame);
   VideoFrameExternalResources CreateForHardwarePlanes(
       const scoped_refptr<media::VideoFrame>& video_frame);
@@ -108,7 +118,7 @@
       const scoped_refptr<media::VideoFrame>& video_frame);
 
   static void RecycleResource(base::WeakPtr<VideoResourceUpdater> updater,
-                              PlaneResource data,
+                              unsigned resource_id,
                               uint32 sync_point,
                               bool lost_resource,
                               BlockingTaskRunner* main_thread_task_runner);
@@ -122,10 +132,9 @@
   ResourceProvider* resource_provider_;
   scoped_ptr<media::SkCanvasVideoRenderer> video_renderer_;
 
-  std::vector<unsigned> all_resources_;
   // Recycle resources so that we can reduce the number of allocations and
   // data transfers.
-  std::vector<PlaneResource> recycled_resources_;
+  ResourceList all_resources_;
 
   DISALLOW_COPY_AND_ASSIGN(VideoResourceUpdater);
 };
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index 1e3481b..5433bcf 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -115,26 +115,36 @@
   // Expect exactly three texture uploads, one for each plane.
   EXPECT_EQ(3, context3d_->UploadCount());
 
-  const ResourceProvider::ResourceId y_resource =
-      resource_provider3d_->CreateResourceFromTextureMailbox(
-          resources.mailboxes[media::VideoFrame::kYPlane],
-          SingleReleaseCallbackImpl::Create(
-              resources.release_callbacks[media::VideoFrame::kYPlane]));
-  const ResourceProvider::ResourceId u_resource =
-      resource_provider3d_->CreateResourceFromTextureMailbox(
-          resources.mailboxes[media::VideoFrame::kUPlane],
-          SingleReleaseCallbackImpl::Create(
-              resources.release_callbacks[media::VideoFrame::kUPlane]));
-  const ResourceProvider::ResourceId v_resource =
-      resource_provider3d_->CreateResourceFromTextureMailbox(
-          resources.mailboxes[media::VideoFrame::kVPlane],
-          SingleReleaseCallbackImpl::Create(
-              resources.release_callbacks[media::VideoFrame::kVPlane]));
+  // Simulate the ResourceProvider releasing the resources back to the video
+  // updater.
+  for (ReleaseCallbackImpl& release_callback : resources.release_callbacks)
+    release_callback.Run(0, false, nullptr);
 
-  // Delete the resources.
-  resource_provider3d_->DeleteResource(y_resource);
-  resource_provider3d_->DeleteResource(u_resource);
-  resource_provider3d_->DeleteResource(v_resource);
+  // Allocate resources for the same frame.
+  context3d_->ResetUploadCount();
+  resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+  EXPECT_EQ(size_t(3), resources.mailboxes.size());
+  EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+  // The data should be reused so expect no texture uploads.
+  EXPECT_EQ(0, context3d_->UploadCount());
+}
+
+TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDelete) {
+  VideoResourceUpdater updater(output_surface3d_->context_provider(),
+                               resource_provider3d_.get());
+  scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
+  video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
+
+  // Allocate the resources for a YUV video frame.
+  context3d_->ResetUploadCount();
+  VideoFrameExternalResources resources =
+      updater.CreateExternalResourcesFromVideoFrame(video_frame);
+  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+  EXPECT_EQ(size_t(3), resources.mailboxes.size());
+  EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+  // Expect exactly three texture uploads, one for each plane.
+  EXPECT_EQ(3, context3d_->UploadCount());
 
   // Allocate resources for the same frame.
   context3d_->ResetUploadCount();
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 3e7653f..143c3ff 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -723,10 +723,6 @@
   RescheduleBeginImplFrameDeadlineIfNeeded();
 }
 
-bool Scheduler::WillDrawIfNeeded() const {
-  return !state_machine_.PendingDrawsShouldBeAborted();
-}
-
 scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue()
     const {
   scoped_refptr<base::debug::TracedValue> state =
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 27dbee3..dea7c3e 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -153,8 +153,6 @@
     return !begin_impl_frame_deadline_task_.IsCancelled();
   }
 
-  bool WillDrawIfNeeded() const;
-
   base::TimeTicks AnticipatedDrawTime() const;
 
   void NotifyBeginMainFrameStarted();
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index 7bbfa37..5f413b3 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -9,24 +9,44 @@
 #include "cc/test/begin_frame_args_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#define EXPECT_ACTION_UPDATE_STATE(action)                                   \
-  EXPECT_STREQ(SchedulerStateMachine::ActionToString(action),                \
-               SchedulerStateMachine::ActionToString(state.NextAction()))    \
-      << state.AsValue()->ToString();                                        \
-  if (action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE ||   \
-      action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED) {        \
-    EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, \
-              state.begin_impl_frame_state())                                \
-        << state.AsValue()->ToString();                                      \
-  }                                                                          \
-  state.UpdateState(action);                                                 \
-  if (action == SchedulerStateMachine::ACTION_NONE) {                        \
-    if (state.begin_impl_frame_state() ==                                    \
-        SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)  \
-      state.OnBeginImplFrameDeadlinePending();                               \
-    if (state.begin_impl_frame_state() ==                                    \
-        SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)       \
-      state.OnBeginImplFrameIdle();                                          \
+// Macro to compare two enum values and get nice output.
+// Without:
+//   Value of: actual()      Actual: 7
+//   Expected: expected()  Which is: 0
+// With:
+//   Value of: actual()      Actual: "ACTION_ANIMATE"
+//   Expected: expected()  Which is: "ACTION_NONE"
+#define EXPECT_ENUM_EQ(enum_tostring, expected, actual)        \
+  EXPECT_STREQ(SchedulerStateMachine::enum_tostring(expected), \
+               SchedulerStateMachine::enum_tostring(actual))
+
+#define EXPECT_IMPL_FRAME_STATE(expected)               \
+  EXPECT_ENUM_EQ(BeginImplFrameStateToString, expected, \
+                 state.begin_impl_frame_state())        \
+      << state.AsValue()->ToString()
+
+#define EXPECT_COMMIT_STATE(expected) \
+  EXPECT_ENUM_EQ(CommitStateToString, expected, state.CommitState())
+
+#define EXPECT_ACTION(expected)                                \
+  EXPECT_ENUM_EQ(ActionToString, expected, state.NextAction()) \
+      << state.AsValue()->ToString()
+
+#define EXPECT_ACTION_UPDATE_STATE(action)                                  \
+  EXPECT_ACTION(action);                                                    \
+  if (action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE ||  \
+      action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED) {       \
+    EXPECT_IMPL_FRAME_STATE(                                                \
+        SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);     \
+  }                                                                         \
+  state.UpdateState(action);                                                \
+  if (action == SchedulerStateMachine::ACTION_NONE) {                       \
+    if (state.begin_impl_frame_state() ==                                   \
+        SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) \
+      state.OnBeginImplFrameDeadlinePending();                              \
+    if (state.begin_impl_frame_state() ==                                   \
+        SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)      \
+      state.OnBeginImplFrameIdle();                                         \
   }
 
 namespace cc {
@@ -177,8 +197,8 @@
     state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
     state.SetVisible(true);
     state.UpdateState(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-    EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-              state.CommitState());
+    EXPECT_COMMIT_STATE(
+        SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
     EXPECT_FALSE(state.NeedsCommit());
   }
 }
@@ -210,7 +230,7 @@
   state.NotifyReadyToCommit();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
 
   state.OnBeginImplFrameDeadline();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -243,7 +263,7 @@
   state.DidSwapBuffersComplete();
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
 }
 
 TEST(SchedulerStateMachineTest,
@@ -621,19 +641,16 @@
       expected_action = SchedulerStateMachine::ACTION_COMMIT;
     } else {
       expected_action = SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
-      EXPECT_EQ(state.NextAction(), SchedulerStateMachine::ACTION_ANIMATE)
-          << state.AsValue()->ToString();
+      EXPECT_ACTION(SchedulerStateMachine::ACTION_ANIMATE);
       state.UpdateState(state.NextAction());
     }
 
     // Case 1: needs_commit=false.
-    EXPECT_EQ(state.NextAction(), expected_action)
-        << state.AsValue()->ToString();
+    EXPECT_ACTION(expected_action);
 
     // Case 2: needs_commit=true.
     state.SetNeedsCommit();
-    EXPECT_EQ(state.NextAction(), expected_action)
-        << state.AsValue()->ToString();
+    EXPECT_ACTION(expected_action);
   }
 }
 
@@ -740,8 +757,8 @@
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
 
   // Now, while the frame is in progress, set another commit.
   state.SetNeedsCommit();
@@ -750,33 +767,31 @@
   // Let the frame finish.
   state.NotifyBeginMainFrameStarted();
   state.NotifyReadyToCommit();
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
 
   // Expect to commit regardless of BeginImplFrame state.
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
 
   state.OnBeginImplFrameDeadlinePending();
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
 
   state.OnBeginImplFrameDeadline();
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
 
   state.OnBeginImplFrameIdle();
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
 
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
 
   // Finish the commit, then make sure we start the next commit immediately
   // and draw on the next BeginImplFrame.
@@ -813,16 +828,15 @@
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   EXPECT_FALSE(state.NeedsCommit());
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
   // Tell the scheduler the frame finished.
   state.NotifyBeginMainFrameStarted();
   state.NotifyReadyToCommit();
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
 
   // Commit.
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
@@ -843,7 +857,7 @@
 
   // Should be synchronized, no draw needed, no action needed.
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
   EXPECT_FALSE(state.needs_redraw());
 }
 
@@ -864,16 +878,15 @@
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   EXPECT_FALSE(state.NeedsCommit());
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
   // Tell the scheduler the frame finished.
   state.NotifyBeginMainFrameStarted();
   state.NotifyReadyToCommit();
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
 
   // Commit.
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
@@ -881,8 +894,7 @@
   EXPECT_TRUE(state.needs_redraw());
 
   // Now commit should wait for draw.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW);
 
   // Swap throttled. Do not draw.
   state.DidSwapBuffers();
@@ -906,7 +918,7 @@
   state.DidSwapBuffersComplete();
 
   // Now will be able to start main frame.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
   EXPECT_FALSE(state.needs_redraw());
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -931,23 +943,22 @@
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   EXPECT_FALSE(state.NeedsCommit());
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
   // Tell the scheduler the frame finished.
   state.NotifyBeginMainFrameStarted();
   state.NotifyReadyToCommit();
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
 
   // Commit.
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
 
   // Now commit should wait for activation.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION);
 
   // No activation yet, so this commit is not drawn yet. Force to draw this
   // frame, and still block BeginMainFrame.
@@ -961,8 +972,8 @@
 
   // Cannot BeginMainFrame yet since last commit is not yet activated and drawn.
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
   // Now activate sync tree.
@@ -971,8 +982,7 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   EXPECT_TRUE(state.active_tree_needs_first_draw());
   EXPECT_TRUE(state.needs_redraw());
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_DRAW);
 
   // Swap throttled. Do not draw.
   state.DidSwapBuffers();
@@ -995,7 +1005,7 @@
   state.DidSwapBuffersComplete();
 
   // Now will be able to start main frame.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
   EXPECT_FALSE(state.needs_redraw());
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1017,8 +1027,8 @@
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   EXPECT_FALSE(state.NeedsCommit());
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
@@ -1029,8 +1039,7 @@
   // Tell the scheduler the frame finished.
   state.NotifyBeginMainFrameStarted();
   state.NotifyReadyToCommit();
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT);
 
   // First commit.
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
@@ -1051,7 +1060,7 @@
 
   // Should be synchronized, no draw needed, no action needed.
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
   EXPECT_FALSE(state.needs_redraw());
 
   // Next BeginImplFrame should initiate second commit.
@@ -1086,8 +1095,8 @@
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   EXPECT_FALSE(state.NeedsCommit());
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
@@ -1096,7 +1105,7 @@
   state.BeginMainFrameAborted(false);
 
   // We should now be back in the idle state as if we never started the frame.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 
   // We shouldn't do anything on the BeginImplFrame deadline.
@@ -1108,8 +1117,8 @@
 
   // Although we have aborted on this frame and haven't cancelled the commit
   // (i.e. need another), don't send another BeginMainFrame yet.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
   EXPECT_TRUE(state.NeedsCommit());
 
   // Start a new frame.
@@ -1118,8 +1127,8 @@
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
 
   // We should be starting the commit now.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
 }
 
@@ -1137,17 +1146,17 @@
 
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   EXPECT_FALSE(state.NeedsCommit());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 
   // Abort the commit, cancelling future commits.
   state.BeginMainFrameAborted(true);
 
   // Verify that another commit doesn't start on the same frame.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
   EXPECT_FALSE(state.NeedsCommit());
 
   // Start a new frame; draw because this is the first frame since output
@@ -1162,15 +1171,14 @@
   state.DidSwapBuffersComplete();
 
   // Verify another commit doesn't start on another frame either.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
   EXPECT_FALSE(state.NeedsCommit());
 
   // Verify another commit can start if requested, though.
   state.SetNeedsCommit();
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
-            state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
 }
 
 TEST(SchedulerStateMachineTest,
@@ -1188,18 +1196,18 @@
 
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   EXPECT_FALSE(state.NeedsCommit());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 
   // Become invisible and abort BeginMainFrame.
   state.SetVisible(false);
   state.BeginMainFrameAborted(true);
 
   // Verify that another commit doesn't start on the same frame.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
   EXPECT_FALSE(state.NeedsCommit());
 
   // Become visible and start a new frame.
@@ -1216,15 +1224,14 @@
   state.DidSwapBuffersComplete();
 
   // Verify another commit doesn't start on another frame either.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
   EXPECT_FALSE(state.NeedsCommit());
 
   // Verify another commit can start if requested, though.
   state.SetNeedsCommit();
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
-            state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
 }
 
 TEST(SchedulerStateMachineTest,
@@ -1242,30 +1249,30 @@
 
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   EXPECT_FALSE(state.NeedsCommit());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 
   // Become invisible and abort BeginMainFrame.
   state.SetVisible(false);
   state.BeginMainFrameAborted(true);
 
   // Verify that another commit doesn't start on the same frame.
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
   EXPECT_FALSE(state.NeedsCommit());
 
   // Asking for a commit while not visible won't make it happen.
   state.SetNeedsCommit();
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
   EXPECT_TRUE(state.NeedsCommit());
 
   // Become visible but nothing happens until the next frame.
   state.SetVisible(true);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
   EXPECT_TRUE(state.NeedsCommit());
 
   // We should get that commit when we begin the next frame.
@@ -1290,10 +1297,10 @@
 
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   EXPECT_FALSE(state.NeedsCommit());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 
   // Become invisible and abort BeginMainFrame.
   state.SetVisible(false);
@@ -1301,20 +1308,20 @@
 
   // Asking for a commit while not visible won't make it happen.
   state.SetNeedsCommit();
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
   EXPECT_TRUE(state.NeedsCommit());
 
   // Begin a frame when not visible, the scheduler animates but does not commit.
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
   EXPECT_TRUE(state.NeedsCommit());
 
   // Become visible and the requested commit happens immediately.
   state.SetVisible(true);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+  EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
 }
@@ -1358,8 +1365,7 @@
             state.NextAction());
   state.DidLoseOutputSurface();
 
-  EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
-            state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
   state.UpdateState(state.NextAction());
 
   // Once context recreation begins, nothing should happen.
@@ -1413,8 +1419,8 @@
   EXPECT_ACTION_UPDATE_STATE(
       SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-  EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
-            state.CommitState());
+  EXPECT_COMMIT_STATE(
+      SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
 
   state.NotifyBeginMainFrameStarted();
   state.NotifyReadyToCommit();
@@ -1430,14 +1436,11 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
   state.OnBeginImplFrameDeadline();
-  EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
-            state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
   state.SetCanDraw(false);
-  EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT,
-            state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
   state.SetCanDraw(true);
-  EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
-            state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
 }
 
 TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
@@ -1471,7 +1474,7 @@
 
   // Ask for another draw. Expect nothing happens.
   state.SetNeedsRedraw(true);
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 
   // Finish the frame, and commit.
   state.NotifyBeginMainFrameStarted();
@@ -1484,25 +1487,23 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
 
   // Expect to begin context recreation only in BEGIN_IMPL_FRAME_STATE_IDLE
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
-            state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
 
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 
   state.OnBeginImplFrameDeadlinePending();
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 
   state.OnBeginImplFrameDeadline();
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 }
 
 TEST(SchedulerStateMachineTest,
@@ -1551,25 +1552,23 @@
   EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
 
   // Expect to begin context recreation only in BEGIN_IMPL_FRAME_STATE_IDLE
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
-            state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
 
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 
   state.OnBeginImplFrameDeadlinePending();
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 
   state.OnBeginImplFrameDeadline();
-  EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
-            state.begin_impl_frame_state());
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_IMPL_FRAME_STATE(
+      SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 
   state.OnBeginImplFrameIdle();
   EXPECT_ACTION_UPDATE_STATE(
@@ -1607,15 +1606,13 @@
 
   // Cause a lost output surface, and restore it.
   state.DidLoseOutputSurface();
-  EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
-            state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
   state.UpdateState(state.NextAction());
   state.DidCreateAndInitializeOutputSurface();
 
   EXPECT_FALSE(state.RedrawPending());
   state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
-  EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
-            state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
 }
 
 TEST(SchedulerStateMachineTest,
@@ -1654,7 +1651,7 @@
   state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
   state.SetVisible(false);
   state.SetNeedsCommit();
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 }
 
 TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
@@ -1670,7 +1667,7 @@
 
   state.NotifyBeginMainFrameStarted();
   state.NotifyReadyToCommit();
-  EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
   state.UpdateState(state.NextAction());
 
   EXPECT_TRUE(state.active_tree_needs_first_draw());
@@ -1701,8 +1698,7 @@
   // lost the output surface and are trying to get the first commit, since the
   // main thread will just abort anyway.
   state.SetVisible(false);
-  EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction())
-      << state.AsValue()->ToString();
+  EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
 }
 
 TEST(SchedulerStateMachineTest, ReportIfNotDrawing) {
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index 9257446..8833037 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -118,6 +118,13 @@
 
   TRACE_EVENT0("cc", "Display::Draw");
   benchmark_instrumentation::IssueDisplayRenderingStatsEvent();
+
+  // Run callbacks early to allow pipelining.
+  for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
+    Surface* surface = manager_->GetSurfaceForId(id_entry.first);
+    if (surface)
+      surface->RunDrawCallbacks();
+  }
   DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
 
   gfx::Size surface_size =
@@ -134,23 +141,13 @@
                        device_clip_rect,
                        disable_picture_quad_image_filtering);
 
-  bool disable_swap = surface_size != current_surface_size_;
-  if (disable_swap) {
+  if (surface_size != current_surface_size_) {
     DidSwapBuffers();
+    DidSwapBuffersComplete();
   } else {
     renderer_->SwapBuffers(frame->metadata);
   }
 
-  for (SurfaceAggregator::SurfaceIndexMap::iterator it =
-           aggregator_->previous_contained_surfaces().begin();
-       it != aggregator_->previous_contained_surfaces().end();
-       ++it) {
-    Surface* surface = manager_->GetSurfaceForId(it->first);
-    if (surface)
-      surface->RunDrawCallbacks();
-  }
-  if (disable_swap)
-    DidSwapBuffersComplete();
   return true;
 }
 
@@ -172,8 +169,11 @@
 }
 
 void Display::OnSurfaceDamaged(SurfaceId surface) {
-  if (aggregator_ && aggregator_->previous_contained_surfaces().count(surface))
+  if (aggregator_ &&
+      aggregator_->previous_contained_surfaces().count(surface)) {
+    aggregator_->ReleaseResources(surface);
     client_->DisplayDamaged();
+  }
 }
 
 SurfaceId Display::CurrentSurfaceId() {
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index c7b1145..98ae58c 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -33,10 +33,12 @@
         &current_resources);
     factory_->UnrefResources(current_resources);
   }
+  if (!draw_callback_.is_null())
+    draw_callback_.Run(false);
 }
 
 void Surface::QueueFrame(scoped_ptr<CompositorFrame> frame,
-                         const base::Closure& callback) {
+                         const DrawCallback& callback) {
   DCHECK(factory_);
   ClearCopyRequests();
   TakeLatencyInfo(&frame->metadata.latency_info);
@@ -54,7 +56,7 @@
     factory_->UnrefResources(previous_resources);
   }
   if (!draw_callback_.is_null())
-    draw_callback_.Run();
+    draw_callback_.Run(false);
   draw_callback_ = callback;
   factory_->manager()->DidSatisfySequences(
       SurfaceIdAllocator::NamespaceForId(surface_id_),
@@ -106,9 +108,9 @@
 
 void Surface::RunDrawCallbacks() {
   if (!draw_callback_.is_null()) {
-    base::Closure callback = draw_callback_;
-    draw_callback_ = base::Closure();
-    callback.Run();
+    DrawCallback callback = draw_callback_;
+    draw_callback_ = DrawCallback();
+    callback.Run(true);
   }
 }
 
diff --git a/cc/surfaces/surface.h b/cc/surfaces/surface.h
index ed0061d..96152a0 100644
--- a/cc/surfaces/surface.h
+++ b/cc/surfaces/surface.h
@@ -34,13 +34,15 @@
 
 class CC_SURFACES_EXPORT Surface {
  public:
+  using DrawCallback = base::Callback<void(bool)>;
+
   Surface(SurfaceId id, SurfaceFactory* factory);
   ~Surface();
 
   SurfaceId surface_id() const { return surface_id_; }
 
   void QueueFrame(scoped_ptr<CompositorFrame> frame,
-                  const base::Closure& draw_callback);
+                  const DrawCallback& draw_callback);
   void RequestCopyOfOutput(scoped_ptr<CopyOutputRequest> copy_request);
   // Adds each CopyOutputRequest in the current frame to copy_requests. The
   // caller takes ownership of them.
@@ -79,7 +81,7 @@
   int frame_index_;
   std::vector<SurfaceSequence> destruction_dependencies_;
 
-  base::Closure draw_callback_;
+  DrawCallback draw_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(Surface);
 };
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc
index 2334d14..4c44084 100644
--- a/cc/surfaces/surface_aggregator.cc
+++ b/cc/surfaces/surface_aggregator.cc
@@ -438,4 +438,13 @@
   return frame.Pass();
 }
 
+void SurfaceAggregator::ReleaseResources(SurfaceId surface_id) {
+  SurfaceToResourceChildIdMap::iterator it =
+      surface_id_to_resource_child_id_.find(surface_id);
+  if (it != surface_id_to_resource_child_id_.end()) {
+    provider_->DestroyChild(it->second);
+    surface_id_to_resource_child_id_.erase(it);
+  }
+}
+
 }  // namespace cc
diff --git a/cc/surfaces/surface_aggregator.h b/cc/surfaces/surface_aggregator.h
index 1e68643..9cb0578 100644
--- a/cc/surfaces/surface_aggregator.h
+++ b/cc/surfaces/surface_aggregator.h
@@ -32,6 +32,7 @@
   ~SurfaceAggregator();
 
   scoped_ptr<CompositorFrame> Aggregate(SurfaceId surface_id);
+  void ReleaseResources(SurfaceId surface_id);
   SurfaceIndexMap& previous_contained_surfaces() {
     return previous_contained_surfaces_;
   }
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index 3e48311..7f6943c 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -123,7 +123,8 @@
     scoped_ptr<CompositorFrame> frame(new CompositorFrame);
     frame->delegated_frame_data = frame_data.Pass();
 
-    factory_.SubmitFrame(surface_id, frame.Pass(), base::Closure());
+    factory_.SubmitFrame(surface_id, frame.Pass(),
+                         SurfaceFactory::DrawCallback());
   }
 
   void QueuePassAsFrame(scoped_ptr<RenderPass> pass, SurfaceId surface_id) {
@@ -133,7 +134,8 @@
     scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
     child_frame->delegated_frame_data = delegated_frame_data.Pass();
 
-    factory_.SubmitFrame(surface_id, child_frame.Pass(), base::Closure());
+    factory_.SubmitFrame(surface_id, child_frame.Pass(),
+                         SurfaceFactory::DrawCallback());
   }
 
  protected:
@@ -380,7 +382,8 @@
     scoped_ptr<CompositorFrame> frame(new CompositorFrame);
     frame->delegated_frame_data = frame_data.Pass();
 
-    factory_.SubmitFrame(root_surface_id_, frame.Pass(), base::Closure());
+    factory_.SubmitFrame(root_surface_id_, frame.Pass(),
+                         SurfaceFactory::DrawCallback());
   }
 
   scoped_ptr<CompositorFrame> aggregated_frame =
@@ -937,7 +940,8 @@
   scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
   child_frame->delegated_frame_data = child_frame_data.Pass();
 
-  factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
+  factory_.SubmitFrame(child_surface_id, child_frame.Pass(),
+                       SurfaceFactory::DrawCallback());
 
   test::Quad root_quads[] = {test::Quad::SolidColorQuad(1),
                              test::Quad::SurfaceQuad(child_surface_id, 1.f)};
@@ -962,7 +966,8 @@
   scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
   root_frame->delegated_frame_data = root_frame_data.Pass();
 
-  factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
+  factory_.SubmitFrame(root_surface_id_, root_frame.Pass(),
+                       SurfaceFactory::DrawCallback());
 
   scoped_ptr<CompositorFrame> aggregated_frame =
       aggregator_.Aggregate(root_surface_id_);
@@ -1061,7 +1066,8 @@
   scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
   child_frame->delegated_frame_data = child_frame_data.Pass();
 
-  factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
+  factory_.SubmitFrame(child_surface_id, child_frame.Pass(),
+                       SurfaceFactory::DrawCallback());
 
   test::Quad root_quads[] = {test::Quad::SurfaceQuad(child_surface_id, 1.f)};
   test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
@@ -1083,7 +1089,8 @@
   scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
   root_frame->delegated_frame_data = root_frame_data.Pass();
 
-  factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
+  factory_.SubmitFrame(root_surface_id_, root_frame.Pass(),
+                       SurfaceFactory::DrawCallback());
 
   scoped_ptr<CompositorFrame> aggregated_frame =
       aggregator_.Aggregate(root_surface_id_);
@@ -1119,7 +1126,8 @@
     scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
     child_frame->delegated_frame_data = child_frame_data.Pass();
 
-    factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
+    factory_.SubmitFrame(child_surface_id, child_frame.Pass(),
+                         SurfaceFactory::DrawCallback());
 
     scoped_ptr<CompositorFrame> aggregated_frame =
         aggregator_.Aggregate(root_surface_id_);
@@ -1158,7 +1166,8 @@
     scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
     root_frame->delegated_frame_data = root_frame_data.Pass();
 
-    factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
+    factory_.SubmitFrame(root_surface_id_, root_frame.Pass(),
+                         SurfaceFactory::DrawCallback());
   }
 
   {
@@ -1179,7 +1188,8 @@
     scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
     root_frame->delegated_frame_data = root_frame_data.Pass();
 
-    factory_.SubmitFrame(root_surface_id_, root_frame.Pass(), base::Closure());
+    factory_.SubmitFrame(root_surface_id_, root_frame.Pass(),
+                         SurfaceFactory::DrawCallback());
 
     scoped_ptr<CompositorFrame> aggregated_frame =
         aggregator_.Aggregate(root_surface_id_);
@@ -1295,7 +1305,8 @@
   frame_data->render_pass_list.push_back(pass.Pass());
   scoped_ptr<CompositorFrame> frame(new CompositorFrame);
   frame->delegated_frame_data = frame_data.Pass();
-  factory->SubmitFrame(surface_id, frame.Pass(), base::Closure());
+  factory->SubmitFrame(surface_id, frame.Pass(),
+                       SurfaceFactory::DrawCallback());
 }
 
 TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) {
diff --git a/cc/surfaces/surface_factory.cc b/cc/surfaces/surface_factory.cc
index fd5a6d4..7af7cb7 100644
--- a/cc/surfaces/surface_factory.cc
+++ b/cc/surfaces/surface_factory.cc
@@ -46,7 +46,7 @@
 
 void SurfaceFactory::SubmitFrame(SurfaceId surface_id,
                                  scoped_ptr<CompositorFrame> frame,
-                                 const base::Closure& callback) {
+                                 const DrawCallback& callback) {
   OwningSurfaceMap::iterator it = surface_map_.find(surface_id);
   DCHECK(it != surface_map_.end());
   DCHECK(it->second->factory().get() == this);
diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h
index eba32d2..7abd929 100644
--- a/cc/surfaces/surface_factory.h
+++ b/cc/surfaces/surface_factory.h
@@ -35,6 +35,10 @@
 class CC_SURFACES_EXPORT SurfaceFactory
     : public base::SupportsWeakPtr<SurfaceFactory> {
  public:
+  // This callback is called with true if the frame was drawn, or false if it
+  // was discarded.
+  using DrawCallback = base::Callback<void(bool)>;
+
   SurfaceFactory(SurfaceManager* manager, SurfaceFactoryClient* client);
   ~SurfaceFactory();
 
@@ -43,10 +47,11 @@
   void DestroyAll();
   // A frame can only be submitted to a surface created by this factory,
   // although the frame may reference surfaces created by other factories.
-  // The callback is called the first time this frame is used to draw.
+  // The callback is called the first time this frame is used to draw, or if
+  // the frame is discarded.
   void SubmitFrame(SurfaceId surface_id,
                    scoped_ptr<CompositorFrame> frame,
-                   const base::Closure& callback);
+                   const DrawCallback& callback);
   void RequestCopyOfSurface(SurfaceId surface_id,
                             scoped_ptr<CopyOutputRequest> copy_request);
 
diff --git a/cc/surfaces/surface_factory_unittest.cc b/cc/surfaces/surface_factory_unittest.cc
index 84dcc5e..1a87c0f 100644
--- a/cc/surfaces/surface_factory_unittest.cc
+++ b/cc/surfaces/surface_factory_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/bind.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/output/delegated_frame_data.h"
 #include "cc/surfaces/surface.h"
@@ -58,7 +59,8 @@
     }
     scoped_ptr<CompositorFrame> frame(new CompositorFrame);
     frame->delegated_frame_data = frame_data.Pass();
-    factory_.SubmitFrame(surface_id_, frame.Pass(), base::Closure());
+    factory_.SubmitFrame(surface_id_, frame.Pass(),
+                         SurfaceFactory::DrawCallback());
   }
 
   void UnrefResources(ResourceProvider::ResourceId* ids_to_unref,
@@ -358,6 +360,11 @@
   }
 }
 
+void DrawCallback(bool* executed, bool* result, bool drawn) {
+  *executed = true;
+  *result = drawn;
+}
+
 // Tests doing a DestroyAll before shutting down the factory;
 TEST_F(SurfaceFactoryTest, DestroyAll) {
   SurfaceId id(7);
@@ -370,10 +377,17 @@
   frame_data->resource_list.push_back(resource);
   scoped_ptr<CompositorFrame> frame(new CompositorFrame);
   frame->delegated_frame_data = frame_data.Pass();
-  factory_.SubmitFrame(id, frame.Pass(), base::Closure());
+  bool executed = false;
+  bool drawn = false;
+
+  factory_.SubmitFrame(id, frame.Pass(),
+                       base::Bind(&DrawCallback, &executed, &drawn));
 
   surface_id_ = SurfaceId();
+  EXPECT_FALSE(executed);
   factory_.DestroyAll();
+  EXPECT_TRUE(executed);
+  EXPECT_FALSE(drawn);
 }
 
 TEST_F(SurfaceFactoryTest, DestroySequence) {
@@ -391,7 +405,8 @@
   frame->metadata.satisfies_sequences.push_back(4);
   frame->delegated_frame_data = frame_data.Pass();
   DCHECK(manager_.GetSurfaceForId(id2));
-  factory_.SubmitFrame(surface_id_, frame.Pass(), base::Closure());
+  factory_.SubmitFrame(surface_id_, frame.Pass(),
+                       SurfaceFactory::DrawCallback());
   DCHECK(!manager_.GetSurfaceForId(id2));
 
   // Check that waiting after the sequence is satisfied works.
diff --git a/cc/surfaces/surfaces_pixeltest.cc b/cc/surfaces/surfaces_pixeltest.cc
index bf9d483..528684b 100644
--- a/cc/surfaces/surfaces_pixeltest.cc
+++ b/cc/surfaces/surfaces_pixeltest.cc
@@ -86,7 +86,8 @@
 
   SurfaceId root_surface_id = allocator_.GenerateId();
   factory_.Create(root_surface_id);
-  factory_.SubmitFrame(root_surface_id, root_frame.Pass(), base::Closure());
+  factory_.SubmitFrame(root_surface_id, root_frame.Pass(),
+                       SurfaceFactory::DrawCallback());
 
   SurfaceAggregator aggregator(&manager_, resource_provider_.get());
   scoped_ptr<CompositorFrame> aggregated_frame =
@@ -140,7 +141,8 @@
     scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
     root_frame->delegated_frame_data = delegated_frame_data.Pass();
 
-    factory_.SubmitFrame(root_surface_id, root_frame.Pass(), base::Closure());
+    factory_.SubmitFrame(root_surface_id, root_frame.Pass(),
+                         SurfaceFactory::DrawCallback());
   }
 
   {
@@ -167,7 +169,8 @@
     scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
     child_frame->delegated_frame_data = delegated_frame_data.Pass();
 
-    factory_.SubmitFrame(child_surface_id, child_frame.Pass(), base::Closure());
+    factory_.SubmitFrame(child_surface_id, child_frame.Pass(),
+                         SurfaceFactory::DrawCallback());
   }
 
   SurfaceAggregator aggregator(&manager_, resource_provider_.get());
@@ -237,7 +240,8 @@
     scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
     root_frame->delegated_frame_data = delegated_frame_data.Pass();
 
-    factory_.SubmitFrame(root_surface_id, root_frame.Pass(), base::Closure());
+    factory_.SubmitFrame(root_surface_id, root_frame.Pass(),
+                         SurfaceFactory::DrawCallback());
   }
 
   {
@@ -272,7 +276,8 @@
     scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
     child_frame->delegated_frame_data = delegated_frame_data.Pass();
 
-    factory_.SubmitFrame(left_child_id, child_frame.Pass(), base::Closure());
+    factory_.SubmitFrame(left_child_id, child_frame.Pass(),
+                         SurfaceFactory::DrawCallback());
   }
 
   {
@@ -307,7 +312,8 @@
     scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
     child_frame->delegated_frame_data = delegated_frame_data.Pass();
 
-    factory_.SubmitFrame(right_child_id, child_frame.Pass(), base::Closure());
+    factory_.SubmitFrame(right_child_id, child_frame.Pass(),
+                         SurfaceFactory::DrawCallback());
   }
 
   SurfaceAggregator aggregator(&manager_, resource_provider_.get());
diff --git a/cc/test/failure_output_surface.cc b/cc/test/failure_output_surface.cc
new file mode 100644
index 0000000..2c87853
--- /dev/null
+++ b/cc/test/failure_output_surface.cc
@@ -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.
+
+#include "cc/test/failure_output_surface.h"
+
+namespace cc {
+
+FailureOutputSurface::FailureOutputSurface(bool is_delegating)
+    : FakeOutputSurface(nullptr, nullptr, is_delegating) {
+}
+
+bool FailureOutputSurface::BindToClient(OutputSurfaceClient* client) {
+  // This will force this output surface to not initialize in LTHI
+  // and eventually get back to LTH::DidFailToInitializeOutputSurface;
+  return false;
+}
+
+}  // namespace cc
diff --git a/cc/test/failure_output_surface.h b/cc/test/failure_output_surface.h
new file mode 100644
index 0000000..4878ea5
--- /dev/null
+++ b/cc/test/failure_output_surface.h
@@ -0,0 +1,24 @@
+// 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_FAILURE_OUTPUT_SURFACE_H_
+#define CC_TEST_FAILURE_OUTPUT_SURFACE_H_
+
+#include "cc/test/fake_output_surface.h"
+
+namespace cc {
+
+class FailureOutputSurface : public FakeOutputSurface {
+ public:
+  explicit FailureOutputSurface(bool is_delegating);
+
+  bool BindToClient(OutputSurfaceClient* client) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FailureOutputSurface);
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_FAILURE_OUTPUT_SURFACE_H_
diff --git a/cc/test/fake_layer_tree_host_client.cc b/cc/test/fake_layer_tree_host_client.cc
index 17ed10c..a4a5d7e 100644
--- a/cc/test/fake_layer_tree_host_client.cc
+++ b/cc/test/fake_layer_tree_host_client.cc
@@ -21,7 +21,7 @@
 
 FakeLayerTreeHostClient::~FakeLayerTreeHostClient() {}
 
-void FakeLayerTreeHostClient::RequestNewOutputSurface(bool fallback) {
+void FakeLayerTreeHostClient::RequestNewOutputSurface() {
   DCHECK(host_);
   scoped_ptr<OutputSurface> surface;
   if (use_software_rendering_) {
@@ -40,4 +40,8 @@
   host_->SetOutputSurface(surface.Pass());
 }
 
+void FakeLayerTreeHostClient::DidFailToInitializeOutputSurface() {
+  RequestNewOutputSurface();
+}
+
 }  // namespace cc
diff --git a/cc/test/fake_layer_tree_host_client.h b/cc/test/fake_layer_tree_host_client.h
index 6f24116..f256ab1 100644
--- a/cc/test/fake_layer_tree_host_client.h
+++ b/cc/test/fake_layer_tree_host_client.h
@@ -43,8 +43,9 @@
                            float page_scale,
                            float top_controls_delta) override {}
 
-  void RequestNewOutputSurface(bool fallback) override;
+  void RequestNewOutputSurface() override;
   void DidInitializeOutputSurface() override {}
+  void DidFailToInitializeOutputSurface() override;
   void WillCommit() override {}
   void DidCommit() override {}
   void DidCommitAndDrawFrame() override {}
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index 13b20ad..8153442 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -13,36 +13,40 @@
 FakePictureLayerImpl::FakePictureLayerImpl(
     LayerTreeImpl* tree_impl,
     int id,
-    scoped_refptr<RasterSource> raster_source)
-    : PictureLayerImpl(tree_impl, id),
+    scoped_refptr<RasterSource> raster_source,
+    bool is_mask)
+    : PictureLayerImpl(tree_impl, id, is_mask),
       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) {
-  raster_source_ = raster_source;
-  SetBounds(raster_source_->GetSize());
-  SetContentBounds(raster_source_->GetSize());
+  SetBounds(raster_source->GetSize());
+  SetContentBounds(raster_source->GetSize());
+  SetRasterSourceOnPending(raster_source, Region());
 }
 
 FakePictureLayerImpl::FakePictureLayerImpl(
     LayerTreeImpl* tree_impl,
     int id,
     scoped_refptr<RasterSource> raster_source,
+    bool is_mask,
     const gfx::Size& layer_bounds)
-    : PictureLayerImpl(tree_impl, id),
+    : PictureLayerImpl(tree_impl, id, is_mask),
       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) {
-  raster_source_ = raster_source;
   SetBounds(layer_bounds);
   SetContentBounds(layer_bounds);
+  SetRasterSourceOnPending(raster_source, Region());
 }
 
-FakePictureLayerImpl::FakePictureLayerImpl(LayerTreeImpl* tree_impl, int id)
-    : PictureLayerImpl(tree_impl, id),
+FakePictureLayerImpl::FakePictureLayerImpl(LayerTreeImpl* tree_impl,
+                                           int id,
+                                           bool is_mask)
+    : PictureLayerImpl(tree_impl, id, is_mask),
       append_quads_count_(0),
       did_become_active_call_count_(0),
       has_valid_tile_priorities_(false),
@@ -52,7 +56,14 @@
 
 scoped_ptr<LayerImpl> FakePictureLayerImpl::CreateLayerImpl(
     LayerTreeImpl* tree_impl) {
-  return make_scoped_ptr(new FakePictureLayerImpl(tree_impl, id()));
+  return make_scoped_ptr(new FakePictureLayerImpl(tree_impl, id(), is_mask_));
+}
+
+void FakePictureLayerImpl::PushPropertiesTo(LayerImpl* layer_impl) {
+  FakePictureLayerImpl* picture_layer_impl =
+      static_cast<FakePictureLayerImpl*>(layer_impl);
+  picture_layer_impl->fixed_tile_size_ = fixed_tile_size_;
+  PictureLayerImpl::PushPropertiesTo(layer_impl);
 }
 
 void FakePictureLayerImpl::AppendQuads(
@@ -99,15 +110,13 @@
   return result;
 }
 
-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)->UpdateTilesToCurrentRasterSource(
-          raster_source_.get(), Region(), raster_source_->GetSize());
-    }
-  }
+void FakePictureLayerImpl::SetRasterSourceOnPending(
+    scoped_refptr<RasterSource> raster_source,
+    const Region& invalidation) {
+  DCHECK(layer_tree_impl()->IsPendingTree());
+  Region invalidation_temp = invalidation;
+  const PictureLayerTilingSet* pending_set = nullptr;
+  UpdateRasterSource(raster_source, &invalidation_temp, pending_set);
 }
 
 void FakePictureLayerImpl::SetAllTilesVisible() {
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index b10b357..d633051 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -14,7 +14,8 @@
  public:
   static scoped_ptr<FakePictureLayerImpl> Create(
       LayerTreeImpl* tree_impl, int id) {
-    return make_scoped_ptr(new FakePictureLayerImpl(tree_impl, id));
+    bool is_mask = false;
+    return make_scoped_ptr(new FakePictureLayerImpl(tree_impl, id, is_mask));
   }
 
   // Create layer from a raster source that covers the entire layer.
@@ -22,8 +23,9 @@
       LayerTreeImpl* tree_impl,
       int id,
       scoped_refptr<RasterSource> raster_source) {
+    bool is_mask = false;
     return make_scoped_ptr(
-        new FakePictureLayerImpl(tree_impl, id, raster_source));
+        new FakePictureLayerImpl(tree_impl, id, raster_source, is_mask));
   }
 
   // Create layer from a raster source that only covers part of the layer.
@@ -32,11 +34,24 @@
       int id,
       scoped_refptr<RasterSource> raster_source,
       const gfx::Size& layer_bounds) {
+    bool is_mask = false;
+    return make_scoped_ptr(new FakePictureLayerImpl(
+        tree_impl, id, raster_source, is_mask, layer_bounds));
+  }
+
+  // Create layer from a raster source that covers the entire layer and is a
+  // mask.
+  static scoped_ptr<FakePictureLayerImpl> CreateMaskWithRasterSource(
+      LayerTreeImpl* tree_impl,
+      int id,
+      scoped_refptr<RasterSource> raster_source) {
+    bool is_mask = true;
     return make_scoped_ptr(
-        new FakePictureLayerImpl(tree_impl, id, raster_source, layer_bounds));
+        new FakePictureLayerImpl(tree_impl, id, raster_source, is_mask));
   }
 
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
+  void PushPropertiesTo(LayerImpl* layer_impl) override;
   void AppendQuads(RenderPass* render_pass,
                    const Occlusion& occlusion_in_content_space,
                    AppendQuadsData* append_quads_data) override;
@@ -91,7 +106,8 @@
 
   PictureLayerTilingSet* tilings() { return tilings_.get(); }
   RasterSource* raster_source() { return raster_source_.get(); }
-  void SetRasterSource(scoped_refptr<RasterSource> raster_source);
+  void SetRasterSourceOnPending(scoped_refptr<RasterSource> raster_source,
+                                const Region& invalidation);
   size_t append_quads_count() { return append_quads_count_; }
 
   const Region& invalidation() const { return invalidation_; }
@@ -103,7 +119,9 @@
 
   void set_fixed_tile_size(const gfx::Size& size) { fixed_tile_size_ = size; }
 
+  // TODO(danakj): Remove this darn thing.
   void CreateDefaultTilingsAndTiles();
+
   void SetAllTilesVisible();
   void SetAllTilesReady();
   void SetAllTilesReadyInTiling(PictureLayerTiling* tiling);
@@ -123,12 +141,14 @@
  protected:
   FakePictureLayerImpl(LayerTreeImpl* tree_impl,
                        int id,
-                       scoped_refptr<RasterSource> raster_source);
+                       scoped_refptr<RasterSource> raster_source,
+                       bool is_mask);
   FakePictureLayerImpl(LayerTreeImpl* tree_impl,
                        int id,
                        scoped_refptr<RasterSource> raster_source,
+                       bool is_mask,
                        const gfx::Size& layer_bounds);
-  FakePictureLayerImpl(LayerTreeImpl* tree_impl, int id);
+  FakePictureLayerImpl(LayerTreeImpl* tree_impl, int id, bool is_mask);
 
  private:
   gfx::Size fixed_tile_size_;
diff --git a/cc/test/fake_picture_layer_tiling_client.cc b/cc/test/fake_picture_layer_tiling_client.cc
index b21e011..6c1dc98 100644
--- a/cc/test/fake_picture_layer_tiling_client.cc
+++ b/cc/test/fake_picture_layer_tiling_client.cc
@@ -17,10 +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) {
+      max_tile_priority_bin_(TilePriority::NOW) {
 }
 
 FakePictureLayerTilingClient::FakePictureLayerTilingClient(
@@ -33,9 +30,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) {
+      max_tile_priority_bin_(TilePriority::NOW) {
 }
 
 FakePictureLayerTilingClient::~FakePictureLayerTilingClient() {
@@ -63,19 +58,6 @@
   return max_tile_priority_bin_;
 }
 
-size_t FakePictureLayerTilingClient::GetMaxTilesForInterestArea() const {
-  return max_tiles_for_interest_area_;
-}
-
-float FakePictureLayerTilingClient::GetSkewportTargetTimeInSeconds() const {
-  return skewport_target_time_in_seconds_;
-}
-
-int FakePictureLayerTilingClient::GetSkewportExtrapolationLimitInContentPixels()
-    const {
-  return skewport_extrapolation_limit_in_content_pixels_;
-}
-
 const Region* FakePictureLayerTilingClient::GetPendingInvalidation() {
   return &invalidation_;
 }
diff --git a/cc/test/fake_picture_layer_tiling_client.h b/cc/test/fake_picture_layer_tiling_client.h
index acf26d0..935765b 100644
--- a/cc/test/fake_picture_layer_tiling_client.h
+++ b/cc/test/fake_picture_layer_tiling_client.h
@@ -25,10 +25,6 @@
                                  const gfx::Rect& rect) 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;
-  bool RequiresHighResToDraw() const override;
 
   void SetTileSize(const gfx::Size& tile_size);
   gfx::Size TileSize() const { return tile_size_; }
@@ -38,6 +34,7 @@
       const PictureLayerTiling* tiling) const override;
   PictureLayerTiling* GetRecycledTwinTiling(
       const PictureLayerTiling* tiling) override;
+  bool RequiresHighResToDraw() const override;
   WhichTree GetTree() const override;
 
   void set_twin_tiling(PictureLayerTiling* tiling) { twin_tiling_ = tiling; }
@@ -50,15 +47,6 @@
   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;
-  }
-  void set_skewport_target_time_in_seconds(float time) {
-    skewport_target_time_in_seconds_ = time;
-  }
-  void set_skewport_extrapolation_limit_in_content_pixels(int limit) {
-    skewport_extrapolation_limit_in_content_pixels_ = limit;
-  }
   void set_tree(WhichTree tree) { tree_ = tree; }
   RasterSource* raster_source() { return pile_.get(); }
 
@@ -78,9 +66,6 @@
   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_;
   WhichTree tree_;
 };
 
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc
index f85946a..bb23aa8 100644
--- a/cc/test/fake_tile_manager.cc
+++ b/cc/test/fake_tile_manager.cc
@@ -67,7 +67,6 @@
                   base::MessageLoopProxy::current(),
                   NULL,
                   g_fake_tile_task_runner.Pointer(),
-                  NULL,
                   std::numeric_limits<size_t>::max()) {
 }
 
@@ -77,7 +76,6 @@
                   base::MessageLoopProxy::current(),
                   resource_pool,
                   g_fake_tile_task_runner.Pointer(),
-                  NULL,
                   std::numeric_limits<size_t>::max()) {
 }
 
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index e2b768a..83a338e 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -217,6 +217,9 @@
   if (!IsTestCaseSupported(test_case_))
     return;
   RunPixelTest(test_type_, content_root, file_name);
+
+  if (layer_tree_host())
+    EXPECT_TRUE(layer_tree_host()->settings().impl_side_painting);
 }
 
 ParameterizedPixelResourceTest::ParameterizedPixelResourceTest()
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index 23bfcf2..8a053fa 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -35,8 +35,7 @@
 
 LayerTreePixelTest::~LayerTreePixelTest() {}
 
-scoped_ptr<OutputSurface> LayerTreePixelTest::CreateOutputSurface(
-    bool fallback) {
+scoped_ptr<OutputSurface> LayerTreePixelTest::CreateOutputSurface() {
   gfx::Size surface_expansion_size(40, 60);
   scoped_ptr<PixelTestOutputSurface> output_surface;
 
diff --git a/cc/test/layer_tree_pixel_test.h b/cc/test/layer_tree_pixel_test.h
index c3c324a..60ea727 100644
--- a/cc/test/layer_tree_pixel_test.h
+++ b/cc/test/layer_tree_pixel_test.h
@@ -40,7 +40,7 @@
   LayerTreePixelTest();
   virtual ~LayerTreePixelTest();
 
-  scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) override;
+  scoped_ptr<OutputSurface> CreateOutputSurface() override;
   void CommitCompleteOnThread(LayerTreeHostImpl* impl) override;
 
   virtual scoped_ptr<CopyOutputRequest> CreateCopyOutputRequest();
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index d6411ec..e5a5687 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -377,8 +377,8 @@
                                      top_controls_delta);
   }
 
-  void RequestNewOutputSurface(bool fallback) override {
-    test_hooks_->RequestNewOutputSurface(fallback);
+  void RequestNewOutputSurface() override {
+    test_hooks_->RequestNewOutputSurface();
   }
 
   void DidInitializeOutputSurface() override {
@@ -391,6 +391,7 @@
 
   void DidFailToInitializeOutputSurface() override {
     test_hooks_->DidFailToInitializeOutputSurface();
+    RequestNewOutputSurface();
   }
 
   void WillCommit() override { test_hooks_->WillCommit(); }
@@ -785,17 +786,14 @@
   RunTest(true, false, true);
 }
 
-void LayerTreeTest::RequestNewOutputSurface(bool fallback) {
-  layer_tree_host_->SetOutputSurface(CreateOutputSurface(fallback));
+void LayerTreeTest::RequestNewOutputSurface() {
+  layer_tree_host_->SetOutputSurface(CreateOutputSurface());
 }
 
-scoped_ptr<OutputSurface> LayerTreeTest::CreateOutputSurface(bool fallback) {
-  scoped_ptr<FakeOutputSurface> output_surface =
-      CreateFakeOutputSurface(fallback);
-  if (output_surface) {
-    DCHECK_EQ(delegating_renderer_,
-              output_surface->capabilities().delegated_rendering);
-  }
+scoped_ptr<OutputSurface> LayerTreeTest::CreateOutputSurface() {
+  scoped_ptr<FakeOutputSurface> output_surface = CreateFakeOutputSurface();
+  DCHECK_EQ(delegating_renderer_,
+            output_surface->capabilities().delegated_rendering);
   output_surface_ = output_surface.get();
 
   if (settings_.use_external_begin_frame_source &&
@@ -806,8 +804,7 @@
   return output_surface.Pass();
 }
 
-scoped_ptr<FakeOutputSurface> LayerTreeTest::CreateFakeOutputSurface(
-    bool fallback) {
+scoped_ptr<FakeOutputSurface> LayerTreeTest::CreateFakeOutputSurface() {
   if (delegating_renderer_)
     return FakeOutputSurface::CreateDelegating3d();
   else
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 4176265..02f18b7 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -110,7 +110,7 @@
                                Animation::TargetProperty target_property,
                                int group) override {}
 
-  virtual void RequestNewOutputSurface(bool fallback) = 0;
+  virtual void RequestNewOutputSurface() = 0;
 };
 
 class BeginTask;
@@ -202,11 +202,11 @@
   void DestroyLayerTreeHost();
 
   // By default, output surface recreation is synchronous.
-  void RequestNewOutputSurface(bool fallback) override;
+  void RequestNewOutputSurface() override;
   // Override this for pixel tests, where you need a real output surface.
-  virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback);
+  virtual scoped_ptr<OutputSurface> CreateOutputSurface();
   // Override this for unit tests, which should not produce pixel output.
-  virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback);
+  virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface();
 
   TestWebGraphicsContext3D* TestContext();
 
diff --git a/cc/test/render_pass_test_common.cc b/cc/test/render_pass_test_common.cc
index b79fc1f..7237ce1 100644
--- a/cc/test/render_pass_test_common.cc
+++ b/cc/test/render_pass_test_common.cc
@@ -198,6 +198,7 @@
                            resource2,
                            gfx::RectF(0, 0, 50, 50),
                            gfx::Size(50, 50),
+                           false,
                            false);
 
   SharedQuadState* transformed_state = this->CreateAndAppendSharedQuadState();
@@ -215,6 +216,7 @@
                                 resource3,
                                 gfx::RectF(0, 0, 100, 100),
                                 gfx::Size(100, 100),
+                                false,
                                 false);
 
   SharedQuadState* shared_state2 = this->CreateAndAppendSharedQuadState();
@@ -235,6 +237,7 @@
                     resource4,
                     gfx::RectF(0, 0, 100, 100),
                     gfx::Size(100, 100),
+                    false,
                     false);
 
   ResourceProvider::ResourceId plane_resources[4];
diff --git a/cc/test/test_context_provider.cc b/cc/test/test_context_provider.cc
index e7697f1..2a2b6f6 100644
--- a/cc/test/test_context_provider.cc
+++ b/cc/test/test_context_provider.cc
@@ -12,6 +12,8 @@
 #include "base/logging.h"
 #include "cc/test/test_gles2_interface.h"
 #include "cc/test/test_web_graphics_context_3d.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
 
 namespace cc {
 
@@ -90,8 +92,14 @@
   DCHECK(bound_);
   DCHECK(context_thread_checker_.CalledOnValidThread());
 
-  // TODO(danakj): Make a test GrContext that works with a test Context3d.
-  return NULL;
+  if (gr_context_)
+    return gr_context_.get();
+
+  auto null_interface = skia::AdoptRef(GrGLCreateNullInterface());
+  gr_context_ = skia::AdoptRef(GrContext::Create(
+      kOpenGL_GrBackend,
+      reinterpret_cast<GrBackendContext>(null_interface.get())));
+  return gr_context_.get();
 }
 
 bool TestContextProvider::IsContextLost() {
diff --git a/cc/test/test_context_provider.h b/cc/test/test_context_provider.h
index 66ae998..3be8b43 100644
--- a/cc/test/test_context_provider.h
+++ b/cc/test/test_context_provider.h
@@ -13,6 +13,7 @@
 #include "cc/output/context_provider.h"
 #include "cc/test/test_context_support.h"
 #include "gpu/command_buffer/client/gles2_interface_stub.h"
+#include "skia/ext/refptr.h"
 
 namespace cc {
 class TestWebGraphicsContext3D;
@@ -75,6 +76,7 @@
 
   LostContextCallback lost_context_callback_;
   MemoryPolicyChangedCallback memory_policy_changed_callback_;
+  skia::RefPtr<class GrContext> gr_context_;
 
   base::WeakPtrFactory<TestContextProvider> weak_ptr_factory_;
 
diff --git a/cc/test/test_shared_bitmap_manager.cc b/cc/test/test_shared_bitmap_manager.cc
index 933dcd2..7e14b2f 100644
--- a/cc/test/test_shared_bitmap_manager.cc
+++ b/cc/test/test_shared_bitmap_manager.cc
@@ -18,26 +18,10 @@
 
   ~OwnedSharedBitmap() override {}
 
-  base::SharedMemory* memory() override { return shared_memory_.get(); }
-
  private:
   scoped_ptr<base::SharedMemory> shared_memory_;
 };
 
-class UnownedSharedBitmap : public SharedBitmap {
- public:
-  UnownedSharedBitmap(base::SharedMemory* shared_memory,
-                      const SharedBitmapId& id)
-      : SharedBitmap(static_cast<uint8*>(shared_memory->memory()), id),
-        shared_memory_(shared_memory) {}
-
-  ~UnownedSharedBitmap() override {}
-
-  base::SharedMemory* memory() override { return shared_memory_; }
-
- private:
-  base::SharedMemory* shared_memory_;
-};
 }  // namespace
 
 TestSharedBitmapManager::TestSharedBitmapManager() {}
@@ -60,15 +44,8 @@
   base::AutoLock lock(lock_);
   if (bitmap_map_.find(id) == bitmap_map_.end())
     return nullptr;
-  return make_scoped_ptr(new UnownedSharedBitmap(bitmap_map_[id], id));
-}
-
-scoped_ptr<SharedBitmap> TestSharedBitmapManager::GetBitmapForSharedMemory(
-    base::SharedMemory* memory) {
-  base::AutoLock lock(lock_);
-  SharedBitmapId id = SharedBitmap::GenerateId();
-  bitmap_map_[id] = memory;
-  return make_scoped_ptr(new UnownedSharedBitmap(memory, id));
+  uint8* pixels = static_cast<uint8*>(bitmap_map_[id]->memory());
+  return make_scoped_ptr(new SharedBitmap(pixels, id));
 }
 
 }  // namespace cc
diff --git a/cc/test/test_shared_bitmap_manager.h b/cc/test/test_shared_bitmap_manager.h
index 9163c79..acba096 100644
--- a/cc/test/test_shared_bitmap_manager.h
+++ b/cc/test/test_shared_bitmap_manager.h
@@ -10,6 +10,10 @@
 #include "base/synchronization/lock.h"
 #include "cc/resources/shared_bitmap_manager.h"
 
+namespace base {
+class SharedMemory;
+}  // namespace base
+
 namespace cc {
 
 class TestSharedBitmapManager : public SharedBitmapManager {
@@ -23,9 +27,6 @@
       const gfx::Size&,
       const SharedBitmapId& id) override;
 
-  scoped_ptr<SharedBitmap> GetBitmapForSharedMemory(
-      base::SharedMemory* memory) override;
-
  private:
   base::Lock lock_;
   std::map<SharedBitmapId, base::SharedMemory*> bitmap_map_;
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 4d03449..d192a9a 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -114,7 +114,6 @@
       source_frame_number_(0),
       rendering_stats_instrumentation_(RenderingStatsInstrumentation::Create()),
       output_surface_lost_(true),
-      num_failed_recreate_attempts_(0),
       settings_(settings),
       debug_state_(settings.initial_debug_state),
       top_controls_shrink_blink_size_(false),
@@ -217,40 +216,6 @@
   layer->OnOutputSurfaceCreated();
 }
 
-void LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted(bool success) {
-  DCHECK(output_surface_lost_);
-  TRACE_EVENT1("cc",
-               "LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted",
-               "success",
-               success);
-
-  if (!success) {
-    // Tolerate a certain number of recreation failures to work around races
-    // in the output-surface-lost machinery.
-    ++num_failed_recreate_attempts_;
-    if (num_failed_recreate_attempts_ >= 5)
-      LOG(FATAL) << "Failed to create a fallback OutputSurface.";
-    client_->DidFailToInitializeOutputSurface();
-    return;
-  }
-
-  output_surface_lost_ = false;
-
-  if (!contents_texture_manager_ && !settings_.impl_side_painting) {
-    contents_texture_manager_ =
-        PrioritizedResourceManager::Create(proxy_.get());
-    surface_memory_placeholder_ =
-        contents_texture_manager_->CreateTexture(gfx::Size(), RGBA_8888);
-  }
-
-  if (root_layer()) {
-    LayerTreeHostCommon::CallFunctionForSubtree(
-        root_layer(), base::Bind(&LayerTreeHostOnOutputSurfaceCreatedCallback));
-  }
-
-  client_->DidInitializeOutputSurface();
-}
-
 void LayerTreeHost::DeleteContentsTexturesOnImplThread(
     ResourceProvider* resource_provider) {
   DCHECK(proxy_->IsImplThread());
@@ -328,12 +293,6 @@
     sync_tree->SetRootLayer(TreeSynchronizer::SynchronizeTrees(
         root_layer(), sync_tree->DetachLayerTree(), sync_tree));
   }
-
-  {
-    TRACE_EVENT0("cc", "LayerTreeHost::PushProperties");
-    TreeSynchronizer::PushProperties(root_layer(), sync_tree->root_layer());
-  }
-
   sync_tree->set_needs_full_tree_sync(needs_full_tree_sync_);
   needs_full_tree_sync_ = false;
 
@@ -355,6 +314,7 @@
         page_scale_layer_->id(), inner_viewport_scroll_layer_->id(),
         outer_viewport_scroll_layer_.get() ? outer_viewport_scroll_layer_->id()
                                            : Layer::INVALID_ID);
+    DCHECK(inner_viewport_scroll_layer_->IsContainerForFixedPositionLayers());
   } else {
     sync_tree->ClearViewportLayers();
   }
@@ -415,6 +375,11 @@
 
   sync_tree->set_has_ever_been_drawn(false);
 
+  {
+    TRACE_EVENT0("cc", "LayerTreeHost::PushProperties");
+    TreeSynchronizer::PushProperties(root_layer(), sync_tree->root_layer());
+  }
+
   micro_benchmark_controller_.ScheduleImplBenchmarks(host_impl);
 }
 
@@ -441,11 +406,38 @@
 }
 
 void LayerTreeHost::SetOutputSurface(scoped_ptr<OutputSurface> surface) {
+  TRACE_EVENT0("cc", "LayerTreeHost::SetOutputSurface");
+  DCHECK(output_surface_lost_);
+  DCHECK(surface);
+
   proxy_->SetOutputSurface(surface.Pass());
 }
 
 void LayerTreeHost::RequestNewOutputSurface() {
-  client_->RequestNewOutputSurface(num_failed_recreate_attempts_ >= 4);
+  client_->RequestNewOutputSurface();
+}
+
+void LayerTreeHost::DidInitializeOutputSurface() {
+  output_surface_lost_ = false;
+
+  if (!contents_texture_manager_ && !settings_.impl_side_painting) {
+    contents_texture_manager_ =
+        PrioritizedResourceManager::Create(proxy_.get());
+    surface_memory_placeholder_ =
+        contents_texture_manager_->CreateTexture(gfx::Size(), RGBA_8888);
+  }
+
+  if (root_layer()) {
+    LayerTreeHostCommon::CallFunctionForSubtree(
+        root_layer(), base::Bind(&LayerTreeHostOnOutputSurfaceCreatedCallback));
+  }
+
+  client_->DidInitializeOutputSurface();
+}
+
+void LayerTreeHost::DidFailToInitializeOutputSurface() {
+  DCHECK(output_surface_lost_);
+  client_->DidFailToInitializeOutputSurface();
 }
 
 scoped_ptr<LayerTreeHostImpl> LayerTreeHost::CreateLayerTreeHostImpl(
@@ -478,7 +470,6 @@
   if (output_surface_lost_)
     return;
 
-  num_failed_recreate_attempts_ = 0;
   output_surface_lost_ = true;
   SetNeedsCommit();
 }
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 75165ad..e60f96e 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -125,11 +125,12 @@
   void CommitComplete();
   void SetOutputSurface(scoped_ptr<OutputSurface> output_surface);
   void RequestNewOutputSurface();
+  void DidInitializeOutputSurface();
+  void DidFailToInitializeOutputSurface();
   virtual scoped_ptr<LayerTreeHostImpl> CreateLayerTreeHostImpl(
       LayerTreeHostImplClient* client);
   void DidLoseOutputSurface();
   bool output_surface_lost() const { return output_surface_lost_; }
-  virtual void OnCreateAndInitializeOutputSurfaceAttempted(bool success);
   void DidCommitAndDrawFrame() { client_->DidCommitAndDrawFrame(); }
   void DidCompleteSwapBuffers() { client_->DidCompleteSwapBuffers(); }
   void DeleteContentsTexturesOnImplThread(ResourceProvider* resource_provider);
@@ -402,7 +403,6 @@
   scoped_ptr<RenderingStatsInstrumentation> rendering_stats_instrumentation_;
 
   bool output_surface_lost_;
-  int num_failed_recreate_attempts_;
 
   scoped_refptr<Layer> root_layer_;
   scoped_refptr<HeadsUpDisplayLayer> hud_layer_;
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h
index 5846343..a09693f 100644
--- a/cc/trees/layer_tree_host_client.h
+++ b/cc/trees/layer_tree_host_client.h
@@ -38,11 +38,12 @@
                                    float page_scale,
                                    float top_controls_delta) = 0;
   // Request an OutputSurface from the client. When the client has one it should
-  // call LayerTreeHost::SetOutputSurface.  If fallback is true, it should
-  // attempt to create an OutputSurface that is guaranteed to initialize
-  // correctly.
-  virtual void RequestNewOutputSurface(bool fallback) = 0;
+  // call LayerTreeHost::SetOutputSurface.  This will result in either
+  // DidFailToInitializeOutputSurface or DidInitializeOutputSurface being
+  // called.
+  virtual void RequestNewOutputSurface() = 0;
   virtual void DidInitializeOutputSurface() = 0;
+  virtual void DidFailToInitializeOutputSurface() = 0;
   virtual void WillCommit() = 0;
   virtual void DidCommit() = 0;
   virtual void DidCommitAndDrawFrame() = 0;
@@ -58,9 +59,6 @@
   // a TextureLayer that calls SetRateLimitContext(true).
   virtual void RateLimitSharedMainThreadContext() {}
 
-  // This hook is for testing.
-  virtual void DidFailToInitializeOutputSurface() {}
-
  protected:
   virtual ~LayerTreeHostClient() {}
 };
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index dd485ba..ea8a29f 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1589,11 +1589,13 @@
   if (use_gpu == use_gpu_rasterization_)
     return;
 
+  // Note that this must happen first, in case the rest of the calls want to
+  // query the new state of |use_gpu_rasterization_|.
   use_gpu_rasterization_ = use_gpu;
-  ReleaseTreeResources();
 
-  // Replace existing tile manager with another one that uses appropriate
-  // rasterizer.
+  // Clean up and replace existing tile manager with another one that uses
+  // appropriate rasterizer.
+  ReleaseTreeResources();
   if (tile_manager_) {
     DestroyTileManager();
     CreateAndSetTileManager();
@@ -1964,8 +1966,7 @@
                                     : settings_.scheduled_raster_task_limit;
   tile_manager_ = TileManager::Create(
       this, task_runner, resource_pool_.get(),
-      tile_task_worker_pool_->AsTileTaskRunner(),
-      rendering_stats_instrumentation_, scheduled_raster_task_limit);
+      tile_task_worker_pool_->AsTileTaskRunner(), scheduled_raster_task_limit);
 
   UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy());
 }
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 9049a84..61bda89 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -4181,6 +4181,7 @@
                                     resource_id_,
                                     gfx::RectF(0.f, 0.f, 1.f, 1.f),
                                     gfx::Size(1, 1),
+                                    false,
                                     false);
     test_blending_draw_quad->visible_rect = quad_visible_rect_;
     EXPECT_EQ(blend_, test_blending_draw_quad->ShouldDrawWithBlending());
@@ -7768,7 +7769,7 @@
 TEST_F(LayerTreeHostImplTest, GetPictureLayerImplPairs) {
   host_impl_->CreatePendingTree();
   host_impl_->pending_tree()->SetRootLayer(
-      PictureLayerImpl::Create(host_impl_->pending_tree(), 10));
+      PictureLayerImpl::Create(host_impl_->pending_tree(), 10, false));
 
   LayerTreeImpl* pending_tree = host_impl_->pending_tree();
   LayerImpl* pending_layer = pending_tree->root_layer();
@@ -7809,7 +7810,7 @@
   // should get two pairs.
   host_impl_->CreatePendingTree();
   host_impl_->pending_tree()->root_layer()->AddChild(
-      PictureLayerImpl::Create(host_impl_->pending_tree(), 11));
+      PictureLayerImpl::Create(host_impl_->pending_tree(), 11, false));
 
   LayerImpl* new_pending_layer = pending_tree->root_layer()->children()[0];
 
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
index 6b6b2af..b31d3e8 100644
--- a/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/layers/image_layer.h"
+#include "cc/layers/picture_image_layer.h"
 #include "cc/layers/solid_color_layer.h"
 #include "cc/test/layer_tree_pixel_resource_test.h"
 #include "cc/test/pixel_comparator.h"
@@ -137,7 +137,7 @@
       canvas.drawRect(
           SkRect::MakeXYWH(0, i * kLaneHeight, kLaneWidth, kLaneHeight), paint);
     }
-    scoped_refptr<ImageLayer> layer = ImageLayer::Create();
+    scoped_refptr<PictureImageLayer> layer = PictureImageLayer::Create();
     layer->SetIsDrawable(true);
     layer->SetBounds(gfx::Size(width, height));
     layer->SetBitmap(backing_store);
@@ -147,7 +147,7 @@
   void SetupMaskLayer(scoped_refptr<Layer> layer) {
     const int kMaskOffset = 2;
     gfx::Size bounds = layer->bounds();
-    scoped_refptr<ImageLayer> mask = ImageLayer::Create();
+    scoped_refptr<PictureImageLayer> mask = PictureImageLayer::Create();
     mask->SetIsDrawable(true);
     mask->SetIsMask(true);
     mask->SetBounds(bounds);
@@ -237,7 +237,6 @@
 
     CreateBlendingColorLayers(kLaneWidth, kLaneHeight, background.get(), flags);
 
-    this->impl_side_painting_ = false;
     this->force_antialiasing_ = (flags & kUseAntialiasing);
     this->force_blending_with_shaders_ = (flags & kForceShaders);
 
@@ -437,6 +436,13 @@
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest,
+       BlendingWithRenderPassShadersWithMask_GL_TextureRect) {
+  RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW,
+                            FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+                            kUseMasks | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
        BlendingWithRenderPassShadersWithMaskAA_GL) {
   RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
                             FILE_PATH_LITERAL("blending_render_pass_mask.png"),
@@ -444,6 +450,13 @@
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest,
+       BlendingWithRenderPassShadersWithMaskAA_GL_TextureRect) {
+  RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW,
+                            FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+                            kUseMasks | kUseAntialiasing | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
        BlendingWithRenderPassShadersColorMatrix_GL) {
   RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW,
                             FILE_PATH_LITERAL("blending_render_pass.png"),
@@ -465,6 +478,13 @@
 }
 
 TEST_F(LayerTreeHostBlendingPixelTest,
+       BlendingWithRenderPassShadersWithMaskColorMatrix_GL_TextureRect) {
+  RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW,
+                            FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+                            kUseMasks | kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
        BlendingWithRenderPassShadersWithMaskColorMatrixAA_GL) {
   RunBlendingWithRenderPass(
       GL_ASYNC_UPLOAD_2D_DRAW,
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 06c522a..eee6275 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -2090,7 +2090,6 @@
     settings.max_partial_texture_updates = 10;
 
     LayerTreeHostWithProxy host(&client, settings, proxy.Pass());
-    host.OnCreateAndInitializeOutputSurfaceAttempted(true);
 
     EXPECT_EQ(0u, host.MaxPartialTextureUpdates());
   }
@@ -2108,7 +2107,6 @@
     settings.max_partial_texture_updates = 10;
 
     LayerTreeHostWithProxy host(&client, settings, proxy.Pass());
-    host.OnCreateAndInitializeOutputSurfaceAttempted(true);
 
     EXPECT_EQ(5u, host.MaxPartialTextureUpdates());
   }
@@ -2126,7 +2124,6 @@
     settings.max_partial_texture_updates = 10;
 
     LayerTreeHostWithProxy host(&client, settings, proxy.Pass());
-    host.OnCreateAndInitializeOutputSurfaceAttempted(true);
 
     EXPECT_EQ(10u, host.MaxPartialTextureUpdates());
   }
@@ -2688,8 +2685,7 @@
 
 class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest {
  protected:
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
     scoped_ptr<MockIOSurfaceWebGraphicsContext3D> mock_context_owned(
         new MockIOSurfaceWebGraphicsContext3D);
     mock_context_ = mock_context_owned.get();
@@ -2883,8 +2879,7 @@
     PostSetNeedsCommitToMainThread();
   }
 
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
     scoped_ptr<TestWebGraphicsContext3D> context3d(
         TestWebGraphicsContext3D::Create());
 
@@ -4380,8 +4375,7 @@
     settings->use_one_copy = false;
   }
 
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
     scoped_refptr<TestContextProvider> context_provider =
         TestContextProvider::Create();
     context_provider->SetMaxTransferBufferUsageBytes(512 * 512);
@@ -4522,8 +4516,7 @@
       : first_output_surface_memory_limit_(4321234),
         second_output_surface_memory_limit_(1234321) {}
 
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
     if (!first_context_provider_.get()) {
       first_context_provider_ = TestContextProvider::Create();
     } else {
@@ -5108,7 +5101,7 @@
 class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest {
  protected:
   void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->impl_side_painting = true;
+    ASSERT_TRUE(settings->impl_side_painting);
 
     EXPECT_FALSE(settings->gpu_rasterization_forced);
     settings->gpu_rasterization_forced = true;
@@ -5169,7 +5162,7 @@
   FakeContentLayerClient layer_client_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationForced);
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestGpuRasterizationForced);
 
 class LayerTreeHostTestContinuousPainting : public LayerTreeHostTest {
  public:
@@ -5714,8 +5707,7 @@
     settings->use_one_copy = true;
   }
 
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
     scoped_ptr<TestWebGraphicsContext3D> context3d =
         TestWebGraphicsContext3D::Create();
     context3d->set_support_image(true);
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index b646e6a..cc4f28f 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -17,6 +17,7 @@
 #include "cc/layers/texture_layer_impl.h"
 #include "cc/output/filter_operations.h"
 #include "cc/resources/single_release_callback.h"
+#include "cc/test/failure_output_surface.h"
 #include "cc/test/fake_content_layer.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_content_layer_impl.h"
@@ -74,12 +75,11 @@
     return TestWebGraphicsContext3D::Create();
   }
 
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
     if (times_to_fail_create_) {
       --times_to_fail_create_;
       ExpectCreateToFail();
-      return nullptr;
+      return make_scoped_ptr(new FailureOutputSurface(delegating_renderer()));
     }
 
     scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
@@ -167,22 +167,22 @@
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
-  void RequestNewOutputSurface(bool fallback) override {
+  void RequestNewOutputSurface() override {
     if (async_output_surface_creation_) {
       MainThreadTaskRunner()->PostTask(
-          FROM_HERE,
-          base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
-                         CreateAndSetOutputSurface,
-                     base::Unretained(this),
-                     fallback));
+          FROM_HERE, base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
+                                    CreateAndSetOutputSurface,
+                                base::Unretained(this)));
     } else {
-      CreateAndSetOutputSurface(fallback);
+      CreateAndSetOutputSurface();
     }
   }
 
-  void CreateAndSetOutputSurface(bool fallback) {
-    layer_tree_host()->SetOutputSurface(
-        LayerTreeHostContextTest::CreateOutputSurface(fallback));
+  void CreateAndSetOutputSurface() {
+    scoped_ptr<OutputSurface> surface(
+        LayerTreeHostContextTest::CreateOutputSurface());
+    CHECK(surface);
+    layer_tree_host()->SetOutputSurface(surface.Pass());
   }
 
   void DidInitializeOutputSurface() override {
@@ -357,7 +357,7 @@
     EndTest();
   }
 
-  scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) override {
+  scoped_ptr<OutputSurface> CreateOutputSurface() override {
     EXPECT_TRUE(false);
     return nullptr;
   }
@@ -380,7 +380,7 @@
     settings->single_thread_proxy_scheduler = false;
   }
 
-  void RequestNewOutputSurface(bool fallback) override {
+  void RequestNewOutputSurface() override {
     EXPECT_GE(1, ++request_count_);
     EndTest();
   }
@@ -390,7 +390,7 @@
     layer_tree_host()->Composite(base::TimeTicks());
   }
 
-  scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) override {
+  scoped_ptr<OutputSurface> CreateOutputSurface() override {
     EXPECT_TRUE(false);
     return nullptr;
   }
@@ -414,13 +414,12 @@
     settings->single_thread_proxy_scheduler = false;
   }
 
-  void RequestNewOutputSurface(bool fallback) override {
+  void RequestNewOutputSurface() override {
     if (request_count_ == 0) {
       ExpectCreateToFail();
-      layer_tree_host()->SetOutputSurface(nullptr);
+      layer_tree_host()->SetOutputSurface(
+          make_scoped_ptr(new FailureOutputSurface(false)));
     }
-    EXPECT_GE(2, ++request_count_);
-    EndTest();
   }
 
   void BeginTest() override {
@@ -428,13 +427,14 @@
     layer_tree_host()->Composite(base::TimeTicks());
   }
 
-  scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) override {
-    EXPECT_TRUE(false);
-    return nullptr;
-  }
-
   void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
 
+  void DidFailToInitializeOutputSurface() override {
+    LayerTreeHostContextTest::DidFailToInitializeOutputSurface();
+    EXPECT_GE(2, ++request_count_);
+    EndTest();
+  }
+
   void AfterTest() override {}
 
   int request_count_;
@@ -452,19 +452,18 @@
     settings->single_thread_proxy_scheduler = false;
   }
 
-  void RequestNewOutputSurface(bool fallback) override {
+  void RequestNewOutputSurface() override {
     MainThreadTaskRunner()->PostTask(
         FROM_HERE,
         base::Bind(&LayerTreeHostContextTestCommitAfterDelayedOutputSurface::
                        CreateAndSetOutputSurface,
-                   base::Unretained(this),
-                   fallback));
+                   base::Unretained(this)));
   }
 
-  void CreateAndSetOutputSurface(bool fallback) {
+  void CreateAndSetOutputSurface() {
     creating_output_ = true;
     layer_tree_host()->SetOutputSurface(
-        LayerTreeHostContextTest::CreateOutputSurface(fallback));
+        LayerTreeHostContextTest::CreateOutputSurface());
   }
 
   void BeginTest() override { layer_tree_host()->Composite(base::TimeTicks()); }
@@ -492,9 +491,9 @@
     settings->single_thread_proxy_scheduler = false;
   }
 
-  void RequestNewOutputSurface(bool fallback) override {
+  void RequestNewOutputSurface() override {
     layer_tree_host()->SetOutputSurface(
-        LayerTreeHostContextTest::CreateOutputSurface(fallback));
+        LayerTreeHostContextTest::CreateOutputSurface());
     EndTest();
   }
 
@@ -572,35 +571,16 @@
 SINGLE_AND_MULTI_THREAD_TEST_F(
     LayerTreeHostContextTestLostContextSucceedsWithContent);
 
-class LayerTreeHostContextTestCreateOutputSurfaceFails
+class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
     : public LayerTreeHostContextTest {
  public:
-  // Run a test that initially fails OutputSurface creation |times_to_fail|
-  // times. If |expect_fallback_attempt| is |true|, an attempt to create a
-  // fallback/software OutputSurface is expected to occur.
-  LayerTreeHostContextTestCreateOutputSurfaceFails(int times_to_fail,
-                                                   bool expect_fallback_attempt)
-      : times_to_fail_(times_to_fail),
-        expect_fallback_attempt_(expect_fallback_attempt),
-        did_attempt_fallback_(false),
-        times_initialized_(0) {
+  LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
+      : times_to_fail_(1), times_initialized_(0) {
     times_to_fail_create_ = times_to_fail_;
   }
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
-    scoped_ptr<FakeOutputSurface> surface =
-        LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
-
-    if (surface)
-      EXPECT_EQ(times_to_fail_, times_create_failed_);
-
-    did_attempt_fallback_ = fallback;
-    return surface.Pass();
-  }
-
   void DidInitializeOutputSurface() override { times_initialized_++; }
 
   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override { EndTest(); }
@@ -608,38 +588,16 @@
   void AfterTest() override {
     EXPECT_EQ(times_to_fail_, times_create_failed_);
     EXPECT_NE(0, times_initialized_);
-    EXPECT_EQ(expect_fallback_attempt_, did_attempt_fallback_);
   }
 
  private:
   int times_to_fail_;
-  bool expect_fallback_attempt_;
-  bool did_attempt_fallback_;
   int times_initialized_;
 };
 
-class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
-    : public LayerTreeHostContextTestCreateOutputSurfaceFails {
- public:
-  LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
-      : LayerTreeHostContextTestCreateOutputSurfaceFails(1, false) {}
-};
-
 SINGLE_AND_MULTI_THREAD_TEST_F(
     LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
 
-// After 4 failures we expect an attempt to create a fallback/software
-// OutputSurface.
-class LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback
-    : public LayerTreeHostContextTestCreateOutputSurfaceFails {
- public:
-  LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback()
-      : LayerTreeHostContextTestCreateOutputSurfaceFails(4, true) {}
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback);
-
 class LayerTreeHostContextTestLostContextAndEvictTextures
     : public LayerTreeHostContextTest {
  public:
@@ -1118,15 +1076,14 @@
     return draw_result;
   }
 
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
     // This will get called twice:
     // First when we create the initial output surface...
     if (layer_tree_host()->source_frame_number() > 0) {
       // ... and then again after we forced the context to be lost.
       lost_context_ = true;
     }
-    return LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
+    return LayerTreeHostContextTest::CreateFakeOutputSurface();
   }
 
   void DidCommitAndDrawFrame() override {
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 1b68cca..de20b6c 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -103,8 +103,7 @@
 
   void AfterTest() override { EXPECT_EQ(4u, callbacks_.size()); }
 
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
     if (use_gl_renderer_)
       return FakeOutputSurface::Create3d();
     return FakeOutputSurface::CreateSoftware(
@@ -534,8 +533,7 @@
 class LayerTreeHostCopyRequestTestLostOutputSurface
     : public LayerTreeHostCopyRequestTest {
  protected:
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
     if (!first_context_provider_.get()) {
       first_context_provider_ = TestContextProvider::Create();
       return FakeOutputSurface::Create3d(first_context_provider_);
@@ -663,8 +661,7 @@
 class LayerTreeHostCopyRequestTestCountTextures
     : public LayerTreeHostCopyRequestTest {
  protected:
-  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
-      bool fallback) override {
+  scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface() override {
     context_provider_ = TestContextProvider::Create();
     return FakeOutputSurface::Create3d(context_provider_);
   }
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 1e04ad9..9e6611a 100644
--- a/cc/trees/layer_tree_host_unittest_no_message_loop.cc
+++ b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -66,13 +66,14 @@
   void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta,
                            float page_scale,
                            float top_controls_delta) override {}
-  void RequestNewOutputSurface(bool fallback) override {
+  void RequestNewOutputSurface() override {
     layer_tree_host_->SetOutputSurface(
         make_scoped_ptr<OutputSurface>(new NoMessageLoopOutputSurface));
   }
   void DidInitializeOutputSurface() override {
     did_initialize_output_surface_ = true;
   }
+  void DidFailToInitializeOutputSurface() override {}
   void WillCommit() override {}
   void DidCommit() override { did_commit_ = true; }
   void DidCommitAndDrawFrame() override { did_commit_and_draw_frame_ = true; }
diff --git a/cc/trees/layer_tree_host_unittest_picture.cc b/cc/trees/layer_tree_host_unittest_picture.cc
index 2d485b4..773798a 100644
--- a/cc/trees/layer_tree_host_unittest_picture.cc
+++ b/cc/trees/layer_tree_host_unittest_picture.cc
@@ -16,20 +16,25 @@
 // These tests deal with picture layers.
 class LayerTreeHostPictureTest : public LayerTreeTest {
  protected:
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    // PictureLayer can only be used with impl side painting enabled.
-    settings->impl_side_painting = true;
+  void SetupTreeWithSinglePictureLayer(const gfx::Size& size) {
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(size);
+
+    root_picture_layer_ = FakePictureLayer::Create(&client_);
+    root_picture_layer_->SetBounds(size);
+    root->AddChild(root_picture_layer_);
+
+    layer_tree_host()->SetRootLayer(root);
   }
+
+  scoped_refptr<FakePictureLayer> root_picture_layer_;
+  FakeContentLayerClient client_;
 };
 
 class LayerTreeHostPictureTestTwinLayer
     : public LayerTreeHostPictureTest {
   void SetupTree() override {
-    LayerTreeHostPictureTest::SetupTree();
-
-    scoped_refptr<FakePictureLayer> picture =
-        FakePictureLayer::Create(&client_);
-    layer_tree_host()->root_layer()->AddChild(picture);
+    SetupTreeWithSinglePictureLayer(gfx::Size(1, 1));
   }
 
   void BeginTest() override {
@@ -117,11 +122,200 @@
 
   void AfterTest() override {}
 
-  FakeContentLayerClient client_;
   int activates_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostPictureTestTwinLayer);
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestTwinLayer);
+
+class LayerTreeHostPictureTestResizeViewportWithGpuRaster
+    : public LayerTreeHostPictureTest {
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->gpu_rasterization_forced = true;
+  }
+
+  void SetupTree() override {
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(768, 960));
+
+    client_.set_fill_with_nonsolid_color(true);
+    picture_ = FakePictureLayer::Create(&client_);
+    picture_->SetBounds(gfx::Size(768, 960));
+    root->AddChild(picture_);
+
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeHostPictureTest::SetupTree();
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* child = impl->sync_tree()->root_layer()->children()[0];
+    FakePictureLayerImpl* picture_impl =
+        static_cast<FakePictureLayerImpl*>(child);
+    gfx::Size tile_size =
+        picture_impl->HighResTiling()->TileAt(0, 0)->content_rect().size();
+
+    switch (impl->sync_tree()->source_frame_number()) {
+      case 0:
+        tile_size_ = tile_size;
+        // GPU Raster picks a tile size based on the viewport size.
+        EXPECT_EQ(gfx::Size(768, 256), tile_size);
+        break;
+      case 1:
+        // When the viewport changed size, the new frame's tiles should change
+        // along with it.
+        EXPECT_NE(gfx::Size(768, 256), tile_size);
+    }
+  }
+
+  void DidCommit() override {
+    switch (layer_tree_host()->source_frame_number()) {
+      case 1:
+        // Change the picture layer's size along with the viewport, so it will
+        // consider picking a new tile size.
+        picture_->SetBounds(gfx::Size(768, 1056));
+        layer_tree_host()->SetViewportSize(gfx::Size(768, 1056));
+        break;
+      case 2:
+        EndTest();
+    }
+  }
+
+  void AfterTest() override {}
+
+  gfx::Size tile_size_;
+  FakeContentLayerClient client_;
+  scoped_refptr<FakePictureLayer> picture_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(
+    LayerTreeHostPictureTestResizeViewportWithGpuRaster);
+
+class LayerTreeHostPictureTestChangeLiveTilesRectWithRecycleTree
+    : public LayerTreeHostPictureTest {
+  void SetupTree() override {
+    frame_ = 0;
+    did_post_commit_ = false;
+
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(100, 100));
+
+    // The layer is big enough that the live tiles rect won't cover the full
+    // layer.
+    client_.set_fill_with_nonsolid_color(true);
+    picture_ = FakePictureLayer::Create(&client_);
+    picture_->SetBounds(gfx::Size(100, 100000));
+    root->AddChild(picture_);
+
+    layer_tree_host()->SetRootLayer(root);
+    LayerTreeHostPictureTest::SetupTree();
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* child = impl->active_tree()->root_layer()->children()[0];
+    FakePictureLayerImpl* picture_impl =
+        static_cast<FakePictureLayerImpl*>(child);
+    FakePictureLayerImpl* recycled_impl = static_cast<FakePictureLayerImpl*>(
+        picture_impl->GetRecycledTwinLayer());
+
+    switch (++frame_) {
+      case 1: {
+        PictureLayerTiling* tiling = picture_impl->HighResTiling();
+        PictureLayerTiling* recycled_tiling = recycled_impl->HighResTiling();
+        int num_tiles_y = tiling->TilingDataForTesting().num_tiles_y();
+
+        // There should be tiles at the top of the picture layer but not at the
+        // bottom.
+        EXPECT_TRUE(tiling->TileAt(0, 0));
+        EXPECT_FALSE(tiling->TileAt(0, num_tiles_y));
+
+        // The recycled tiling matches it.
+        EXPECT_TRUE(recycled_tiling->TileAt(0, 0));
+        EXPECT_FALSE(recycled_tiling->TileAt(0, num_tiles_y));
+
+        // The live tiles rect matches on the recycled tree.
+        EXPECT_EQ(tiling->live_tiles_rect(),
+                  recycled_tiling->live_tiles_rect());
+
+        // Make the bottom of the layer visible.
+        picture_impl->SetPosition(gfx::PointF(0.f, -100000.f + 100.f));
+        impl->SetNeedsRedraw();
+        break;
+      }
+      case 2: {
+        PictureLayerTiling* tiling = picture_impl->HighResTiling();
+        PictureLayerTiling* recycled_tiling = recycled_impl->HighResTiling();
+
+        // There not be tiles at the top of the layer now.
+        EXPECT_FALSE(tiling->TileAt(0, 0));
+
+        // The recycled twin tiling should not have unshared tiles at the top
+        // either.
+        EXPECT_FALSE(recycled_tiling->TileAt(0, 0));
+
+        // The live tiles rect matches on the recycled tree.
+        EXPECT_EQ(tiling->live_tiles_rect(),
+                  recycled_tiling->live_tiles_rect());
+
+        // Make the top of the layer visible again.
+        picture_impl->SetPosition(gfx::PointF());
+        impl->SetNeedsRedraw();
+        break;
+      }
+      case 3: {
+        PictureLayerTiling* tiling = picture_impl->HighResTiling();
+        PictureLayerTiling* recycled_tiling = recycled_impl->HighResTiling();
+        int num_tiles_y = tiling->TilingDataForTesting().num_tiles_y();
+
+        // There should be tiles at the top of the picture layer again.
+        EXPECT_TRUE(tiling->TileAt(0, 0));
+        EXPECT_FALSE(tiling->TileAt(0, num_tiles_y));
+
+        // The recycled tiling should also have tiles at the top.
+        EXPECT_TRUE(recycled_tiling->TileAt(0, 0));
+        EXPECT_FALSE(recycled_tiling->TileAt(0, num_tiles_y));
+
+        // The live tiles rect matches on the recycled tree.
+        EXPECT_EQ(tiling->live_tiles_rect(),
+                  recycled_tiling->live_tiles_rect());
+
+        // Make a new main frame without changing the picture layer at all, so
+        // it won't need to update or push properties.
+        did_post_commit_ = true;
+        PostSetNeedsCommitToMainThread();
+        break;
+      }
+    }
+  }
+
+  void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override {
+    LayerImpl* child = impl->sync_tree()->root_layer()->children()[0];
+    FakePictureLayerImpl* picture_impl =
+        static_cast<FakePictureLayerImpl*>(child);
+    PictureLayerTiling* tiling = picture_impl->HighResTiling();
+    int num_tiles_y = tiling->TilingDataForTesting().num_tiles_y();
+
+    // The pending layer should always have tiles at the top of it each commit.
+    // The tile is part of the required for activation set so it should exist.
+    EXPECT_TRUE(tiling->TileAt(0, 0));
+    EXPECT_FALSE(tiling->TileAt(0, num_tiles_y));
+
+    if (did_post_commit_)
+      EndTest();
+  }
+
+  void AfterTest() override {}
+
+  int frame_;
+  bool did_post_commit_;
+  FakeContentLayerClient client_;
+  scoped_refptr<FakePictureLayer> picture_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(
+    LayerTreeHostPictureTestChangeLiveTilesRectWithRecycleTree);
 
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index b1248e0..6498f0e 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -129,8 +129,8 @@
   output_surface_creation_requested_ = false;
   renderer_capabilities_for_main_thread_ = RendererCapabilities();
 
-  bool success = !!output_surface;
-  if (success) {
+  bool success;
+  {
     DebugScopedSetMainThreadBlocked main_thread_blocked(this);
     DebugScopedSetImplThread impl(this);
     layer_tree_host_->DeleteContentsTexturesOnImplThread(
@@ -138,15 +138,14 @@
     success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass());
   }
 
-  layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success);
-
   if (success) {
+    layer_tree_host_->DidInitializeOutputSurface();
     if (scheduler_on_impl_thread_)
       scheduler_on_impl_thread_->DidCreateAndInitializeOutputSurface();
     else if (!inside_synchronous_composite_)
       SetNeedsCommit();
-  } else if (Proxy::MainThreadTaskRunner()) {
-    ScheduleRequestNewOutputSurface();
+  } else {
+    layer_tree_host_->DidFailToInitializeOutputSurface();
   }
 }
 
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index e6ab017..73bf79e 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -215,16 +215,10 @@
 }
 
 void ThreadProxy::SetOutputSurface(scoped_ptr<OutputSurface> output_surface) {
-  if (output_surface) {
-    Proxy::ImplThreadTaskRunner()->PostTask(
-        FROM_HERE,
-        base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread,
-                   impl_thread_weak_ptr_,
-                   base::Passed(&output_surface)));
-    return;
-  }
-
-  DidInitializeOutputSurface(false, RendererCapabilities());
+  Proxy::ImplThreadTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread,
+                 impl_thread_weak_ptr_, base::Passed(&output_surface)));
 }
 
 void ThreadProxy::DidInitializeOutputSurface(
@@ -232,15 +226,13 @@
     const RendererCapabilities& capabilities) {
   TRACE_EVENT0("cc", "ThreadProxy::DidInitializeOutputSurface");
   DCHECK(IsMainThread());
-  main().renderer_capabilities_main_thread_copy = capabilities;
-  layer_tree_host()->OnCreateAndInitializeOutputSurfaceAttempted(success);
 
   if (!success) {
-    Proxy::MainThreadTaskRunner()->PostTask(
-        FROM_HERE,
-        base::Bind(&ThreadProxy::RequestNewOutputSurface,
-                   main_thread_weak_ptr_));
+    layer_tree_host()->DidFailToInitializeOutputSurface();
+    return;
   }
+  main().renderer_capabilities_main_thread_copy = capabilities;
+  layer_tree_host()->DidInitializeOutputSurface();
 }
 
 void ThreadProxy::SetRendererCapabilitiesMainThreadCopy(
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index d35de42..5a506df 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -19,7 +19,9 @@
 #define glBindBuffer GLES2_GET_FUN(BindBuffer)
 #define glBindFramebuffer GLES2_GET_FUN(BindFramebuffer)
 #define glBindRenderbuffer GLES2_GET_FUN(BindRenderbuffer)
+#define glBindSampler GLES2_GET_FUN(BindSampler)
 #define glBindTexture GLES2_GET_FUN(BindTexture)
+#define glBindTransformFeedback GLES2_GET_FUN(BindTransformFeedback)
 #define glBlendColor GLES2_GET_FUN(BlendColor)
 #define glBlendEquation GLES2_GET_FUN(BlendEquation)
 #define glBlendEquationSeparate GLES2_GET_FUN(BlendEquationSeparate)
@@ -46,8 +48,10 @@
 #define glDeleteFramebuffers GLES2_GET_FUN(DeleteFramebuffers)
 #define glDeleteProgram GLES2_GET_FUN(DeleteProgram)
 #define glDeleteRenderbuffers GLES2_GET_FUN(DeleteRenderbuffers)
+#define glDeleteSamplers GLES2_GET_FUN(DeleteSamplers)
 #define glDeleteShader GLES2_GET_FUN(DeleteShader)
 #define glDeleteTextures GLES2_GET_FUN(DeleteTextures)
+#define glDeleteTransformFeedbacks GLES2_GET_FUN(DeleteTransformFeedbacks)
 #define glDepthFunc GLES2_GET_FUN(DepthFunc)
 #define glDepthMask GLES2_GET_FUN(DepthMask)
 #define glDepthRangef GLES2_GET_FUN(DepthRangef)
@@ -68,7 +72,9 @@
 #define glGenerateMipmap GLES2_GET_FUN(GenerateMipmap)
 #define glGenFramebuffers GLES2_GET_FUN(GenFramebuffers)
 #define glGenRenderbuffers GLES2_GET_FUN(GenRenderbuffers)
+#define glGenSamplers GLES2_GET_FUN(GenSamplers)
 #define glGenTextures GLES2_GET_FUN(GenTextures)
+#define glGenTransformFeedbacks GLES2_GET_FUN(GenTransformFeedbacks)
 #define glGetActiveAttrib GLES2_GET_FUN(GetActiveAttrib)
 #define glGetActiveUniform GLES2_GET_FUN(GetActiveUniform)
 #define glGetAttachedShaders GLES2_GET_FUN(GetAttachedShaders)
@@ -84,6 +90,8 @@
 #define glGetProgramiv GLES2_GET_FUN(GetProgramiv)
 #define glGetProgramInfoLog GLES2_GET_FUN(GetProgramInfoLog)
 #define glGetRenderbufferParameteriv GLES2_GET_FUN(GetRenderbufferParameteriv)
+#define glGetSamplerParameterfv GLES2_GET_FUN(GetSamplerParameterfv)
+#define glGetSamplerParameteriv GLES2_GET_FUN(GetSamplerParameteriv)
 #define glGetShaderiv GLES2_GET_FUN(GetShaderiv)
 #define glGetShaderInfoLog GLES2_GET_FUN(GetShaderInfoLog)
 #define glGetShaderPrecisionFormat GLES2_GET_FUN(GetShaderPrecisionFormat)
@@ -105,17 +113,25 @@
 #define glIsFramebuffer GLES2_GET_FUN(IsFramebuffer)
 #define glIsProgram GLES2_GET_FUN(IsProgram)
 #define glIsRenderbuffer GLES2_GET_FUN(IsRenderbuffer)
+#define glIsSampler GLES2_GET_FUN(IsSampler)
 #define glIsShader GLES2_GET_FUN(IsShader)
 #define glIsTexture GLES2_GET_FUN(IsTexture)
+#define glIsTransformFeedback GLES2_GET_FUN(IsTransformFeedback)
 #define glLineWidth GLES2_GET_FUN(LineWidth)
 #define glLinkProgram GLES2_GET_FUN(LinkProgram)
+#define glPauseTransformFeedback GLES2_GET_FUN(PauseTransformFeedback)
 #define glPixelStorei GLES2_GET_FUN(PixelStorei)
 #define glPolygonOffset GLES2_GET_FUN(PolygonOffset)
 #define glReadBuffer GLES2_GET_FUN(ReadBuffer)
 #define glReadPixels GLES2_GET_FUN(ReadPixels)
 #define glReleaseShaderCompiler GLES2_GET_FUN(ReleaseShaderCompiler)
 #define glRenderbufferStorage GLES2_GET_FUN(RenderbufferStorage)
+#define glResumeTransformFeedback GLES2_GET_FUN(ResumeTransformFeedback)
 #define glSampleCoverage GLES2_GET_FUN(SampleCoverage)
+#define glSamplerParameterf GLES2_GET_FUN(SamplerParameterf)
+#define glSamplerParameterfv GLES2_GET_FUN(SamplerParameterfv)
+#define glSamplerParameteri GLES2_GET_FUN(SamplerParameteri)
+#define glSamplerParameteriv GLES2_GET_FUN(SamplerParameteriv)
 #define glScissor GLES2_GET_FUN(Scissor)
 #define glShaderBinary GLES2_GET_FUN(ShaderBinary)
 #define glShaderSource GLES2_GET_FUN(ShaderSource)
@@ -196,7 +212,9 @@
 #define glDeleteQueriesEXT GLES2_GET_FUN(DeleteQueriesEXT)
 #define glIsQueryEXT GLES2_GET_FUN(IsQueryEXT)
 #define glBeginQueryEXT GLES2_GET_FUN(BeginQueryEXT)
+#define glBeginTransformFeedback GLES2_GET_FUN(BeginTransformFeedback)
 #define glEndQueryEXT GLES2_GET_FUN(EndQueryEXT)
+#define glEndTransformFeedback GLES2_GET_FUN(EndTransformFeedback)
 #define glGetQueryivEXT GLES2_GET_FUN(GetQueryivEXT)
 #define glGetQueryObjectuivEXT GLES2_GET_FUN(GetQueryObjectuivEXT)
 #define glInsertEventMarkerEXT GLES2_GET_FUN(InsertEventMarkerEXT)
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 0b86db6..418612a 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -10,6 +10,7 @@
 import os.path
 import sys
 import re
+import platform
 from optparse import OptionParser
 from subprocess import call
 
@@ -709,6 +710,26 @@
       'GL_TEXTURE_3D',
     ],
   },
+  'TransformFeedbackBindTarget': {
+    'type': 'GLenum',
+    'valid': [
+      'GL_TRANSFORM_FEEDBACK',
+    ],
+    'invalid': [
+      'GL_TEXTURE_2D',
+    ],
+  },
+  'TransformFeedbackPrimitiveMode': {
+    'type': 'GLenum',
+    'valid': [
+      'GL_POINTS',
+      'GL_LINES',
+      'GL_TRIANGLES',
+    ],
+    'invalid': [
+      'GL_LINE_LOOP',
+    ],
+  },
   'ShaderType': {
     'type': 'GLenum',
     'valid': [
@@ -939,6 +960,23 @@
       'GL_RENDERBUFFER_INTERNAL_FORMAT',
     ],
   },
+  'SamplerParameter': {
+    'type': 'GLenum',
+    'valid': [
+      'GL_TEXTURE_MAG_FILTER',
+      'GL_TEXTURE_MIN_FILTER',
+      'GL_TEXTURE_MIN_LOD',
+      'GL_TEXTURE_MAX_LOD',
+      'GL_TEXTURE_WRAP_S',
+      'GL_TEXTURE_WRAP_T',
+      'GL_TEXTURE_WRAP_R',
+      'GL_TEXTURE_COMPARE_MODE',
+      'GL_TEXTURE_COMPARE_FUNC',
+    ],
+    'invalid': [
+      'GL_GENERATE_MIPMAP',
+    ],
+  },
   'ShaderParameter': {
     'type': 'GLenum',
     'valid': [
@@ -1327,7 +1365,7 @@
 #               command.
 # impl_decl:    Whether or not to generate the GLES2Implementation declaration
 #               for this command.
-# needs_size:   If true a data_size field is added to the command.
+# needs_size:   If True a data_size field is added to the command.
 # count:        The number of units per element. For PUTn or PUT types.
 # unit_test:    If False no service side unit test will be generated.
 # client_test:  If False no client side unit test will be generated.
@@ -1359,6 +1397,8 @@
 # not_shared:   For GENn types, True if objects can't be shared between contexts
 # unsafe:       True = no validation is implemented on the service side and the
 #               command is only available with --enable-unsafe-es3-apis.
+# id_mapping:   A list of resource type names whose client side IDs need to be
+#               mapped to service side IDs.  This is only used for unsafe APIs.
 
 _FUNCTION_INFO = {
   'ActiveTexture': {
@@ -1391,6 +1431,11 @@
     'gl_test_func': 'glBindRenderbufferEXT',
     'gen_func': 'GenRenderbuffersEXT',
   },
+  'BindSampler': {
+    'type': 'Bind',
+    'id_mapping': [ 'Sampler' ],
+    'unsafe': True,
+  },
   'BindTexture': {
     'type': 'Bind',
     'decoder_func': 'DoBindTexture',
@@ -1399,6 +1444,11 @@
     'client_test': False,
     'trace_level': 1,
   },
+  'BindTransformFeedback': {
+    'type': 'Bind',
+    'id_mapping': [ 'TransformFeedback' ],
+    'unsafe': True,
+  },
   'BlitFramebufferCHROMIUM': {
     'decoder_func': 'DoBlitFramebufferCHROMIUM',
     'unit_test': False,
@@ -1690,12 +1740,24 @@
     'resource_type': 'Renderbuffer',
     'resource_types': 'Renderbuffers',
   },
+  'DeleteSamplers': {
+    'type': 'DELn',
+    'resource_type': 'Sampler',
+    'resource_types': 'Samplers',
+    'unsafe': True,
+  },
   'DeleteShader': {'type': 'Delete', 'decoder_func': 'DoDeleteShader'},
   'DeleteTextures': {
     'type': 'DELn',
     'resource_type': 'Texture',
     'resource_types': 'Textures',
   },
+  'DeleteTransformFeedbacks': {
+    'type': 'DELn',
+    'resource_type': 'TransformFeedback',
+    'resource_types': 'TransformFeedbacks',
+    'unsafe': True,
+  },
   'DepthRangef': {
     'decoder_func': 'DoDepthRangef',
     'gl_test_func': 'glDepthRange',
@@ -1797,12 +1859,26 @@
     'resource_type': 'Renderbuffer',
     'resource_types': 'Renderbuffers',
   },
+  'GenSamplers': {
+    'type': 'GENn',
+    'gl_test_func': 'glGenSamplers',
+    'resource_type': 'Sampler',
+    'resource_types': 'Samplers',
+    'unsafe': True,
+  },
   'GenTextures': {
     'type': 'GENn',
     'gl_test_func': 'glGenTextures',
     'resource_type': 'Texture',
     'resource_types': 'Textures',
   },
+  'GenTransformFeedbacks': {
+    'type': 'GENn',
+    'gl_test_func': 'glGenTransformFeedbacks',
+    'resource_type': 'TransformFeedback',
+    'resource_types': 'TransformFeedbacks',
+    'unsafe': True,
+  },
   'GetActiveAttrib': {
     'type': 'Custom',
     'data_transfer_methods': ['shm'],
@@ -1924,6 +2000,18 @@
     'gl_test_func': 'glGetRenderbufferParameterivEXT',
     'result': ['SizedResult<GLint>'],
   },
+  'GetSamplerParameterfv': {
+    'type': 'GETn',
+    'result': ['SizedResult<GLfloat>'],
+    'id_mapping': [ 'Sampler' ],
+    'unsafe': True,
+  },
+  'GetSamplerParameteriv': {
+    'type': 'GETn',
+    'result': ['SizedResult<GLint>'],
+    'id_mapping': [ 'Sampler' ],
+    'unsafe': True,
+  },
   'GetShaderiv': {
     'type': 'GETn',
     'decoder_func': 'DoGetShaderiv',
@@ -2062,11 +2150,21 @@
     'decoder_func': 'DoIsShader',
     'expectation': False,
   },
+  'IsSampler': {
+    'type': 'Is',
+    'id_mapping': [ 'Sampler' ],
+    'unsafe': True,
+  },
   'IsTexture': {
     'type': 'Is',
     'decoder_func': 'DoIsTexture',
     'expectation': False,
   },
+  'IsTransformFeedback': {
+    'type': 'Is',
+    'id_mapping': [ 'TransformFeedback' ],
+    'unsafe': True,
+  },
   'LinkProgram': {
     'decoder_func': 'DoLinkProgram',
     'impl_func':  False,
@@ -2091,6 +2189,9 @@
     'client_test': False,
     'pepper_interface': 'ChromiumMapSub',
   },
+  'PauseTransformFeedback': {
+    'unsafe': True,
+  },
   'PixelStorei': {'type': 'Manual'},
   'PostSubBufferCHROMIUM': {
       'type': 'Custom',
@@ -2172,6 +2273,42 @@
     'decoder_func': 'DoReleaseShaderCompiler',
     'unit_test': False,
   },
+  'ResumeTransformFeedback': {
+    'unsafe': True,
+  },
+  'SamplerParameterf': {
+    'valid_args': {
+      '2': 'GL_NEAREST'
+    },
+    'id_mapping': [ 'Sampler' ],
+    'unsafe': True,
+  },
+  'SamplerParameterfv': {
+    'type': 'PUT',
+    'data_value': 'GL_NEAREST',
+    'count': 1,
+    'gl_test_func': 'glSamplerParameterf',
+    'decoder_func': 'DoSamplerParameterfv',
+    'first_element_only': True,
+    'id_mapping': [ 'Sampler' ],
+    'unsafe': True,
+  },
+  'SamplerParameteri': {
+    'valid_args': {
+      '2': 'GL_NEAREST'
+    },
+    'id_mapping': [ 'Sampler' ],
+    'unsafe': True,
+  },
+  'SamplerParameteriv': {
+    'type': 'PUT',
+    'data_value': 'GL_NEAREST',
+    'count': 1,
+    'gl_test_func': 'glSamplerParameteri',
+    'decoder_func': 'DoSamplerParameteriv',
+    'first_element_only': True,
+    'unsafe': True,
+  },
   'ShaderBinary': {
     'type': 'Custom',
     'client_test': False,
@@ -2599,6 +2736,9 @@
     'gl_test_func': 'glBeginQuery',
     'pepper_interface': 'Query',
   },
+  'BeginTransformFeedback': {
+    'unsafe': True,
+  },
   'EndQueryEXT': {
     'type': 'Manual',
     'cmd_args': 'GLenumQueryTarget target, GLuint submit_count',
@@ -2606,6 +2746,9 @@
     'client_test': False,
     'pepper_interface': 'Query',
   },
+  'EndTransformFeedback': {
+    'unsafe': True,
+  },
   'GetQueryivEXT': {
     'gen_cmd': False,
     'client_test': False,
@@ -3061,6 +3204,10 @@
 
   def WriteHandlerImplementation(self, func, file):
     """Writes the handler implementation for this command."""
+    if func.IsUnsafe() and func.GetInfo('id_mapping'):
+      for id_type in func.GetInfo('id_mapping'):
+        file.Write("  group_->Get%sServiceId(%s, &%s);\n" %
+                   (id_type, id_type.lower(), id_type.lower()))
     file.Write("  %s(%s);\n" %
                (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
 
@@ -3110,6 +3257,10 @@
 
   def WriteImmediateHandlerImplementation (self, func, file):
     """Writes the handler impl for the immediate version of a command."""
+    if func.IsUnsafe() and func.GetInfo('id_mapping'):
+      for id_type in func.GetInfo('id_mapping'):
+        file.Write("  group_->Get%sServiceId(%s, &%s);\n" %
+                   (id_type, id_type.lower(), id_type.lower()))
     file.Write("  %s(%s);\n" %
                (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
 
@@ -3233,6 +3384,8 @@
 
   def WriteInvalidUnitTest(self, func, file, test, *extras):
     """Writes an invalid unit test for the service implementation."""
+    if func.IsUnsafe():
+      return
     for invalid_arg_index, invalid_arg in enumerate(func.GetOriginalArgs()):
       # Service implementation does not test constants, as they are not part of
       # the call in the service side.
@@ -3270,7 +3423,7 @@
           'all_but_last_args': ", ".join(arg_strings[:-1]),
           'gl_args': ", ".join(gl_arg_strings),
           'parse_result': parse_result,
-            'gl_error_test': gl_error_test,
+          'gl_error_test': gl_error_test,
         }
         for extra in extras:
           vars.update(extra)
@@ -4154,7 +4307,18 @@
   EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s));
   SpecializedSetup<cmds::%(name)s, 0>(true);
   cmds::%(name)s cmd;
-  cmd.Init(%(args)s);
+  cmd.Init(%(args)s);"""
+      if func.IsUnsafe():
+        valid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+"""
+      else:
+        valid_test += """
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
 }
@@ -4183,7 +4347,18 @@
   EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s));
   SpecializedSetup<cmds::%(name)s, 0>(true);
   cmds::%(name)s cmd;
-  cmd.Init(%(args)s);
+  cmd.Init(%(args)s);"""
+      if func.IsUnsafe():
+        valid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+"""
+      else:
+        valid_test += """
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
 }
@@ -4239,7 +4414,14 @@
       for arg in func.GetOriginalArgs():
         arg.WriteClientSideValidationCode(file, func)
 
-      code = """  if (Is%(type)sReservedId(%(id)s)) {
+      if func.IsUnsafe():
+        code = """  helper_->%(name)s(%(arg_string)s);
+  CheckGLError();
+}
+
+"""
+      else:
+        code = """  if (Is%(type)sReservedId(%(id)s)) {
     SetGLError(GL_INVALID_OPERATION, "%(name)s\", \"%(id)s reserved id");
     return;
   }
@@ -4278,10 +4460,13 @@
   expected.cmd.Init(%(cmd_args)s);
 
   gl_->%(name)s(%(args)s);
-  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));"""
+    if not func.IsUnsafe():
+      code += """
   ClearCommands();
   gl_->%(name)s(%(args)s);
-  EXPECT_TRUE(NoCommandsWritten());
+  EXPECT_TRUE(NoCommandsWritten());"""
+    code += """
 }
 """
     cmd_arg_strings = [
@@ -4326,10 +4511,25 @@
 
   def WriteImmediateHandlerImplementation(self, func, file):
     """Overrriden from TypeHandler."""
-    file.Write("  if (!%sHelper(n, %s)) {\n"
-               "    return error::kInvalidArguments;\n"
-               "  }\n" %
-               (func.original_name, func.GetLastOriginalArg().name))
+    if func.IsUnsafe():
+      file.Write("""  for (GLsizei ii = 0; ii < n; ++ii) {
+    if (group_->Get%(resource_name)sServiceId(%(last_arg_name)s[ii], NULL)) {
+      return error::kInvalidArguments;
+    }
+  }
+  scoped_ptr<GLuint[]> service_ids(new GLuint[n]);
+  gl%(func_name)s(n, service_ids.get());
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    group_->Add%(resource_name)sId(%(last_arg_name)s[ii], service_ids[ii]);
+  }
+""" % { 'func_name': func.original_name,
+        'last_arg_name': func.GetLastOriginalArg().name,
+        'resource_name': func.GetInfo('resource_type') })
+    else:
+      file.Write("  if (!%sHelper(n, %s)) {\n"
+                 "    return error::kInvalidArguments;\n"
+                 "  }\n" %
+                 (func.original_name, func.GetLastOriginalArg().name))
 
   def WriteGLES2Implementation(self, func, file):
     """Overrriden from TypeHandler."""
@@ -4415,8 +4615,17 @@
   cmds::%(name)s cmd;
   cmd.Init(%(args)s);
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  EXPECT_TRUE(Get%(resource_name)s(kNewClientId) != NULL);
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());"""
+    if func.IsUnsafe():
+      valid_test += """
+  GLuint service_id;
+  EXPECT_TRUE(Get%(resource_name)sServiceId(kNewClientId, &service_id));
+  EXPECT_EQ(kNewServiceId, service_id)
+}
+"""
+    else:
+      valid_test += """
+  EXPECT_TRUE(Get%(resource_name)s(kNewClientId, &service_id) != NULL);
 }
 """
     self.WriteValidUnitTest(func, file, valid_test, {
@@ -4444,11 +4653,27 @@
       .WillOnce(SetArgumentPointee<1>(kNewServiceId));
   cmds::%(name)s* cmd = GetImmediateAs<cmds::%(name)s>();
   GLuint temp = kNewClientId;
-  SpecializedSetup<cmds::%(name)s, 0>(true);
+  SpecializedSetup<cmds::%(name)s, 0>(true);"""
+    if func.IsUnsafe():
+      valid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(true);"""
+    valid_test += """
   cmd->Init(1, &temp);
   EXPECT_EQ(error::kNoError,
             ExecuteImmediateCmd(*cmd, sizeof(temp)));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());"""
+    if func.IsUnsafe():
+      valid_test += """
+  GLuint service_id;
+  EXPECT_TRUE(Get%(resource_name)sServiceId(kNewClientId, &service_id));
+  EXPECT_EQ(kNewServiceId, service_id);
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand,
+            ExecuteImmediateCmd(*cmd, sizeof(temp)));
+}
+"""
+    else:
+      valid_test += """
   EXPECT_TRUE(Get%(resource_name)s(kNewClientId) != NULL);
 }
 """
@@ -4460,7 +4685,17 @@
   EXPECT_CALL(*gl_, %(gl_func_name)s(_, _)).Times(0);
   cmds::%(name)s* cmd = GetImmediateAs<cmds::%(name)s>();
   SpecializedSetup<cmds::%(name)s, 0>(false);
-  cmd->Init(1, &client_%(resource_name)s_id_);
+  cmd->Init(1, &client_%(resource_name)s_id_);"""
+    if func.IsUnsafe():
+      invalid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kInvalidArguments,
+            ExecuteImmediateCmd(*cmd, sizeof(&client_%(resource_name)s_id_)));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+}
+"""
+    else:
+      invalid_test += """
   EXPECT_EQ(error::kInvalidArguments,
             ExecuteImmediateCmd(*cmd, sizeof(&client_%(resource_name)s_id_)));
 }
@@ -4744,10 +4979,25 @@
       .Times(1);
   cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>();
   SpecializedSetup<cmds::%(name)s, 0>(true);
-  cmd.Init(1, &client_%(resource_name)s_id_);
+  cmd.Init(1, &client_%(resource_name)s_id_);"""
+    if func.IsUnsafe():
+      valid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(true);"""
+    valid_test += """
   EXPECT_EQ(error::kNoError,
             ExecuteImmediateCmd(cmd, sizeof(client_%(resource_name)s_id_)));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());"""
+    if func.IsUnsafe():
+      valid_test += """
+  EXPECT_FALSE(Get%(upper_resource_name)sServiceId(
+      client_%(resource_name)s_id_, NULL));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand,
+            ExecuteImmediateCmd(cmd, sizeof(client_%(resource_name)s_id_)));
+}
+"""
+    else:
+      valid_test += """
   EXPECT_TRUE(
       Get%(upper_resource_name)s(client_%(resource_name)s_id_) == NULL);
 }
@@ -4761,7 +5011,19 @@
   cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>();
   SpecializedSetup<cmds::%(name)s, 0>(false);
   GLuint temp = kInvalidClientId;
-  cmd.Init(1, &temp);
+  cmd.Init(1, &temp);"""
+    if func.IsUnsafe():
+      invalid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError,
+            ExecuteImmediateCmd(cmd, sizeof(temp)));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand,
+            ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+"""
+    else:
+      invalid_test += """
   EXPECT_EQ(error::kNoError,
             ExecuteImmediateCmd(cmd, sizeof(temp)));
 }
@@ -4775,8 +5037,20 @@
 
   def WriteImmediateHandlerImplementation (self, func, file):
     """Overrriden from TypeHandler."""
-    file.Write("  %sHelper(n, %s);\n" %
-               (func.original_name, func.GetLastOriginalArg().name))
+    if func.IsUnsafe():
+      file.Write("""  for (GLsizei ii = 0; ii < n; ++ii) {
+    GLuint service_id = 0;
+    if (group_->Get%(resource_type)sServiceId(
+            %(last_arg_name)s[ii], &service_id)) {
+      glDelete%(resource_type)ss(1, &service_id);
+      group_->Remove%(resource_type)sId(%(last_arg_name)s[ii]);
+    }
+  }
+""" % { 'resource_type': func.GetInfo('resource_type'),
+        'last_arg_name': func.GetLastOriginalArg().name })
+    else:
+      file.Write("  %sHelper(n, %s);\n" %
+                 (func.original_name, func.GetLastOriginalArg().name))
 
   def WriteGLES2Implementation(self, func, file):
     """Overrriden from TypeHandler."""
@@ -5230,13 +5504,32 @@
 
     invalid_test = """
 TEST_P(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) {
-  cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>();
+  cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>();"""
+    if func.IsUnsafe():
+      invalid_test += """
+  EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_any_args)s, _)).Times(1);
+"""
+    else:
+      invalid_test += """
   EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_any_args)s, _)).Times(0);
+"""
+    invalid_test += """
   SpecializedSetup<cmds::%(name)s, 0>(false);
   %(data_type)s temp[%(data_count)s] = { %(data_value)s, };
-  cmd.Init(%(all_but_last_args)s, &temp[0]);
+  cmd.Init(%(all_but_last_args)s, &temp[0]);"""
+    if func.IsUnsafe():
+      invalid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(true);
   EXPECT_EQ(error::%(parse_result)s,
-            ExecuteImmediateCmd(cmd, sizeof(temp)));%(gl_error_test)s
+            ExecuteImmediateCmd(cmd, sizeof(temp)));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+}
+"""
+    else:
+      invalid_test += """
+  EXPECT_EQ(error::%(parse_result)s,
+            ExecuteImmediateCmd(cmd, sizeof(temp)));
+  %(gl_error_test)s
 }
 """
     self.WriteInvalidUnitTest(func, file, invalid_test, extra, *extras)
@@ -6026,9 +6319,18 @@
   EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s));
   SpecializedSetup<cmds::%(name)s, 0>(true);
   cmds::%(name)s cmd;
-  cmd.Init(%(args)s%(comma)sshared_memory_id_, shared_memory_offset_);
+  cmd.Init(%(args)s%(comma)sshared_memory_id_, shared_memory_offset_);"""
+    if func.IsUnsafe():
+      valid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(true);"""
+    valid_test += """
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());"""
+    if func.IsUnsafe():
+      valid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));"""
+    valid_test += """
 }
 """
     comma = ""
@@ -6054,12 +6356,20 @@
     invalid_test = """
 TEST_P(%(test_name)s, %(name)sInvalidArgsBadSharedMemoryId) {
   EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0);
-  SpecializedSetup<cmds::%(name)s, 0>(false);
+  SpecializedSetup<cmds::%(name)s, 0>(false);"""
+    if func.IsUnsafe():
+      invalid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(true);"""
+    invalid_test += """
   cmds::%(name)s cmd;
   cmd.Init(%(args)s%(comma)skInvalidSharedMemoryId, shared_memory_offset_);
   EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
   cmd.Init(%(args)s%(comma)sshared_memory_id_, kInvalidSharedMemoryOffset);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));"""
+    if func.IsUnsafe():
+      invalid_test += """
+  decoder_->set_unsafe_es3_apis_enabled(true);"""
+    invalid_test += """
 }
 """
     self.WriteValidUnitTest(func, file, invalid_test, {
@@ -6082,6 +6392,10 @@
 """
     file.Write(code % {'func_name': func.name})
     func.WriteHandlerValidation(file)
+    if func.IsUnsafe() and func.GetInfo('id_mapping'):
+      for id_type in func.GetInfo('id_mapping'):
+        file.Write("  group_->Get%sServiceId(%s, &%s);\n" %
+                   (id_type, id_type.lower(), id_type.lower()))
     file.Write("  *result_dst = %s(%s);\n" %
                (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
     file.Write("  return error::kNoError;\n")
@@ -8803,8 +9117,11 @@
     self.generated_cpp_filenames.append(file.filename)
 
 def Format(generated_files):
+  formatter = "clang-format"
+  if platform.system() == "Windows":
+    formatter += ".bat"
   for filename in generated_files:
-    call(["clang-format", "-i", "-style=chromium", filename])
+    call([formatter, "-i", "-style=chromium", filename])
 
 def main(argv):
   """This is the main function."""
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 766ce56..bd41c8f 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -30,9 +30,15 @@
 void GLES2BindRenderbuffer(GLenum target, GLuint renderbuffer) {
   gles2::GetGLContext()->BindRenderbuffer(target, renderbuffer);
 }
+void GLES2BindSampler(GLuint unit, GLuint sampler) {
+  gles2::GetGLContext()->BindSampler(unit, sampler);
+}
 void GLES2BindTexture(GLenum target, GLuint texture) {
   gles2::GetGLContext()->BindTexture(target, texture);
 }
+void GLES2BindTransformFeedback(GLenum target, GLuint transformfeedback) {
+  gles2::GetGLContext()->BindTransformFeedback(target, transformfeedback);
+}
 void GLES2BlendColor(GLclampf red,
                      GLclampf green,
                      GLclampf blue,
@@ -167,12 +173,18 @@
 void GLES2DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
   gles2::GetGLContext()->DeleteRenderbuffers(n, renderbuffers);
 }
+void GLES2DeleteSamplers(GLsizei n, const GLuint* samplers) {
+  gles2::GetGLContext()->DeleteSamplers(n, samplers);
+}
 void GLES2DeleteShader(GLuint shader) {
   gles2::GetGLContext()->DeleteShader(shader);
 }
 void GLES2DeleteTextures(GLsizei n, const GLuint* textures) {
   gles2::GetGLContext()->DeleteTextures(n, textures);
 }
+void GLES2DeleteTransformFeedbacks(GLsizei n, const GLuint* ids) {
+  gles2::GetGLContext()->DeleteTransformFeedbacks(n, ids);
+}
 void GLES2DepthFunc(GLenum func) {
   gles2::GetGLContext()->DepthFunc(func);
 }
@@ -250,9 +262,15 @@
 void GLES2GenRenderbuffers(GLsizei n, GLuint* renderbuffers) {
   gles2::GetGLContext()->GenRenderbuffers(n, renderbuffers);
 }
+void GLES2GenSamplers(GLsizei n, GLuint* samplers) {
+  gles2::GetGLContext()->GenSamplers(n, samplers);
+}
 void GLES2GenTextures(GLsizei n, GLuint* textures) {
   gles2::GetGLContext()->GenTextures(n, textures);
 }
+void GLES2GenTransformFeedbacks(GLsizei n, GLuint* ids) {
+  gles2::GetGLContext()->GenTransformFeedbacks(n, ids);
+}
 void GLES2GetActiveAttrib(GLuint program,
                           GLuint index,
                           GLsizei bufsize,
@@ -326,6 +344,12 @@
                                      GLint* params) {
   gles2::GetGLContext()->GetRenderbufferParameteriv(target, pname, params);
 }
+void GLES2GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params) {
+  gles2::GetGLContext()->GetSamplerParameterfv(sampler, pname, params);
+}
+void GLES2GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params) {
+  gles2::GetGLContext()->GetSamplerParameteriv(sampler, pname, params);
+}
 void GLES2GetShaderiv(GLuint shader, GLenum pname, GLint* params) {
   gles2::GetGLContext()->GetShaderiv(shader, pname, params);
 }
@@ -408,18 +432,27 @@
 GLboolean GLES2IsRenderbuffer(GLuint renderbuffer) {
   return gles2::GetGLContext()->IsRenderbuffer(renderbuffer);
 }
+GLboolean GLES2IsSampler(GLuint sampler) {
+  return gles2::GetGLContext()->IsSampler(sampler);
+}
 GLboolean GLES2IsShader(GLuint shader) {
   return gles2::GetGLContext()->IsShader(shader);
 }
 GLboolean GLES2IsTexture(GLuint texture) {
   return gles2::GetGLContext()->IsTexture(texture);
 }
+GLboolean GLES2IsTransformFeedback(GLuint transformfeedback) {
+  return gles2::GetGLContext()->IsTransformFeedback(transformfeedback);
+}
 void GLES2LineWidth(GLfloat width) {
   gles2::GetGLContext()->LineWidth(width);
 }
 void GLES2LinkProgram(GLuint program) {
   gles2::GetGLContext()->LinkProgram(program);
 }
+void GLES2PauseTransformFeedback() {
+  gles2::GetGLContext()->PauseTransformFeedback();
+}
 void GLES2PixelStorei(GLenum pname, GLint param) {
   gles2::GetGLContext()->PixelStorei(pname, param);
 }
@@ -448,9 +481,28 @@
   gles2::GetGLContext()->RenderbufferStorage(target, internalformat, width,
                                              height);
 }
+void GLES2ResumeTransformFeedback() {
+  gles2::GetGLContext()->ResumeTransformFeedback();
+}
 void GLES2SampleCoverage(GLclampf value, GLboolean invert) {
   gles2::GetGLContext()->SampleCoverage(value, invert);
 }
+void GLES2SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) {
+  gles2::GetGLContext()->SamplerParameterf(sampler, pname, param);
+}
+void GLES2SamplerParameterfv(GLuint sampler,
+                             GLenum pname,
+                             const GLfloat* params) {
+  gles2::GetGLContext()->SamplerParameterfv(sampler, pname, params);
+}
+void GLES2SamplerParameteri(GLuint sampler, GLenum pname, GLint param) {
+  gles2::GetGLContext()->SamplerParameteri(sampler, pname, param);
+}
+void GLES2SamplerParameteriv(GLuint sampler,
+                             GLenum pname,
+                             const GLint* params) {
+  gles2::GetGLContext()->SamplerParameteriv(sampler, pname, params);
+}
 void GLES2Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
   gles2::GetGLContext()->Scissor(x, y, width, height);
 }
@@ -799,9 +851,15 @@
 void GLES2BeginQueryEXT(GLenum target, GLuint id) {
   gles2::GetGLContext()->BeginQueryEXT(target, id);
 }
+void GLES2BeginTransformFeedback(GLenum primitivemode) {
+  gles2::GetGLContext()->BeginTransformFeedback(primitivemode);
+}
 void GLES2EndQueryEXT(GLenum target) {
   gles2::GetGLContext()->EndQueryEXT(target);
 }
+void GLES2EndTransformFeedback() {
+  gles2::GetGLContext()->EndTransformFeedback();
+}
 void GLES2GetQueryivEXT(GLenum target, GLenum pname, GLint* params) {
   gles2::GetGLContext()->GetQueryivEXT(target, pname, params);
 }
@@ -1124,10 +1182,18 @@
      reinterpret_cast<GLES2FunctionPointer>(glBindRenderbuffer),
     },
     {
+     "glBindSampler",
+     reinterpret_cast<GLES2FunctionPointer>(glBindSampler),
+    },
+    {
      "glBindTexture",
      reinterpret_cast<GLES2FunctionPointer>(glBindTexture),
     },
     {
+     "glBindTransformFeedback",
+     reinterpret_cast<GLES2FunctionPointer>(glBindTransformFeedback),
+    },
+    {
      "glBlendColor",
      reinterpret_cast<GLES2FunctionPointer>(glBlendColor),
     },
@@ -1232,6 +1298,10 @@
      reinterpret_cast<GLES2FunctionPointer>(glDeleteRenderbuffers),
     },
     {
+     "glDeleteSamplers",
+     reinterpret_cast<GLES2FunctionPointer>(glDeleteSamplers),
+    },
+    {
      "glDeleteShader",
      reinterpret_cast<GLES2FunctionPointer>(glDeleteShader),
     },
@@ -1240,6 +1310,10 @@
      reinterpret_cast<GLES2FunctionPointer>(glDeleteTextures),
     },
     {
+     "glDeleteTransformFeedbacks",
+     reinterpret_cast<GLES2FunctionPointer>(glDeleteTransformFeedbacks),
+    },
+    {
      "glDepthFunc",
      reinterpret_cast<GLES2FunctionPointer>(glDepthFunc),
     },
@@ -1320,10 +1394,18 @@
      reinterpret_cast<GLES2FunctionPointer>(glGenRenderbuffers),
     },
     {
+     "glGenSamplers",
+     reinterpret_cast<GLES2FunctionPointer>(glGenSamplers),
+    },
+    {
      "glGenTextures",
      reinterpret_cast<GLES2FunctionPointer>(glGenTextures),
     },
     {
+     "glGenTransformFeedbacks",
+     reinterpret_cast<GLES2FunctionPointer>(glGenTransformFeedbacks),
+    },
+    {
      "glGetActiveAttrib",
      reinterpret_cast<GLES2FunctionPointer>(glGetActiveAttrib),
     },
@@ -1381,6 +1463,14 @@
      reinterpret_cast<GLES2FunctionPointer>(glGetRenderbufferParameteriv),
     },
     {
+     "glGetSamplerParameterfv",
+     reinterpret_cast<GLES2FunctionPointer>(glGetSamplerParameterfv),
+    },
+    {
+     "glGetSamplerParameteriv",
+     reinterpret_cast<GLES2FunctionPointer>(glGetSamplerParameteriv),
+    },
+    {
      "glGetShaderiv",
      reinterpret_cast<GLES2FunctionPointer>(glGetShaderiv),
     },
@@ -1465,6 +1555,10 @@
      reinterpret_cast<GLES2FunctionPointer>(glIsRenderbuffer),
     },
     {
+     "glIsSampler",
+     reinterpret_cast<GLES2FunctionPointer>(glIsSampler),
+    },
+    {
      "glIsShader",
      reinterpret_cast<GLES2FunctionPointer>(glIsShader),
     },
@@ -1473,6 +1567,10 @@
      reinterpret_cast<GLES2FunctionPointer>(glIsTexture),
     },
     {
+     "glIsTransformFeedback",
+     reinterpret_cast<GLES2FunctionPointer>(glIsTransformFeedback),
+    },
+    {
      "glLineWidth",
      reinterpret_cast<GLES2FunctionPointer>(glLineWidth),
     },
@@ -1481,6 +1579,10 @@
      reinterpret_cast<GLES2FunctionPointer>(glLinkProgram),
     },
     {
+     "glPauseTransformFeedback",
+     reinterpret_cast<GLES2FunctionPointer>(glPauseTransformFeedback),
+    },
+    {
      "glPixelStorei",
      reinterpret_cast<GLES2FunctionPointer>(glPixelStorei),
     },
@@ -1505,10 +1607,30 @@
      reinterpret_cast<GLES2FunctionPointer>(glRenderbufferStorage),
     },
     {
+     "glResumeTransformFeedback",
+     reinterpret_cast<GLES2FunctionPointer>(glResumeTransformFeedback),
+    },
+    {
      "glSampleCoverage",
      reinterpret_cast<GLES2FunctionPointer>(glSampleCoverage),
     },
     {
+     "glSamplerParameterf",
+     reinterpret_cast<GLES2FunctionPointer>(glSamplerParameterf),
+    },
+    {
+     "glSamplerParameterfv",
+     reinterpret_cast<GLES2FunctionPointer>(glSamplerParameterfv),
+    },
+    {
+     "glSamplerParameteri",
+     reinterpret_cast<GLES2FunctionPointer>(glSamplerParameteri),
+    },
+    {
+     "glSamplerParameteriv",
+     reinterpret_cast<GLES2FunctionPointer>(glSamplerParameteriv),
+    },
+    {
      "glScissor",
      reinterpret_cast<GLES2FunctionPointer>(glScissor),
     },
@@ -1820,10 +1942,18 @@
      reinterpret_cast<GLES2FunctionPointer>(glBeginQueryEXT),
     },
     {
+     "glBeginTransformFeedback",
+     reinterpret_cast<GLES2FunctionPointer>(glBeginTransformFeedback),
+    },
+    {
      "glEndQueryEXT",
      reinterpret_cast<GLES2FunctionPointer>(glEndQueryEXT),
     },
     {
+     "glEndTransformFeedback",
+     reinterpret_cast<GLES2FunctionPointer>(glEndTransformFeedback),
+    },
+    {
      "glGetQueryivEXT",
      reinterpret_cast<GLES2FunctionPointer>(glGetQueryivEXT),
     },
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index 7b2faae..8d4553a 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -57,6 +57,13 @@
   }
 }
 
+void BindSampler(GLuint unit, GLuint sampler) {
+  gles2::cmds::BindSampler* c = GetCmdSpace<gles2::cmds::BindSampler>();
+  if (c) {
+    c->Init(unit, sampler);
+  }
+}
+
 void BindTexture(GLenum target, GLuint texture) {
   gles2::cmds::BindTexture* c = GetCmdSpace<gles2::cmds::BindTexture>();
   if (c) {
@@ -64,6 +71,14 @@
   }
 }
 
+void BindTransformFeedback(GLenum target, GLuint transformfeedback) {
+  gles2::cmds::BindTransformFeedback* c =
+      GetCmdSpace<gles2::cmds::BindTransformFeedback>();
+  if (c) {
+    c->Init(target, transformfeedback);
+  }
+}
+
 void BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
   gles2::cmds::BlendColor* c = GetCmdSpace<gles2::cmds::BlendColor>();
   if (c) {
@@ -342,6 +357,15 @@
   }
 }
 
+void DeleteSamplersImmediate(GLsizei n, const GLuint* samplers) {
+  const uint32_t size = gles2::cmds::DeleteSamplersImmediate::ComputeSize(n);
+  gles2::cmds::DeleteSamplersImmediate* c =
+      GetImmediateCmdSpaceTotalSize<gles2::cmds::DeleteSamplersImmediate>(size);
+  if (c) {
+    c->Init(n, samplers);
+  }
+}
+
 void DeleteShader(GLuint shader) {
   gles2::cmds::DeleteShader* c = GetCmdSpace<gles2::cmds::DeleteShader>();
   if (c) {
@@ -358,6 +382,17 @@
   }
 }
 
+void DeleteTransformFeedbacksImmediate(GLsizei n, const GLuint* ids) {
+  const uint32_t size =
+      gles2::cmds::DeleteTransformFeedbacksImmediate::ComputeSize(n);
+  gles2::cmds::DeleteTransformFeedbacksImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          gles2::cmds::DeleteTransformFeedbacksImmediate>(size);
+  if (c) {
+    c->Init(n, ids);
+  }
+}
+
 void DepthFunc(GLenum func) {
   gles2::cmds::DepthFunc* c = GetCmdSpace<gles2::cmds::DepthFunc>();
   if (c) {
@@ -524,6 +559,15 @@
   }
 }
 
+void GenSamplersImmediate(GLsizei n, GLuint* samplers) {
+  const uint32_t size = gles2::cmds::GenSamplersImmediate::ComputeSize(n);
+  gles2::cmds::GenSamplersImmediate* c =
+      GetImmediateCmdSpaceTotalSize<gles2::cmds::GenSamplersImmediate>(size);
+  if (c) {
+    c->Init(n, samplers);
+  }
+}
+
 void GenTexturesImmediate(GLsizei n, GLuint* textures) {
   const uint32_t size = gles2::cmds::GenTexturesImmediate::ComputeSize(n);
   gles2::cmds::GenTexturesImmediate* c =
@@ -533,6 +577,17 @@
   }
 }
 
+void GenTransformFeedbacksImmediate(GLsizei n, GLuint* ids) {
+  const uint32_t size =
+      gles2::cmds::GenTransformFeedbacksImmediate::ComputeSize(n);
+  gles2::cmds::GenTransformFeedbacksImmediate* c =
+      GetImmediateCmdSpaceTotalSize<
+          gles2::cmds::GenTransformFeedbacksImmediate>(size);
+  if (c) {
+    c->Init(n, ids);
+  }
+}
+
 void GetActiveAttrib(GLuint program,
                      GLuint index,
                      uint32_t name_bucket_id,
@@ -677,6 +732,28 @@
   }
 }
 
+void GetSamplerParameterfv(GLuint sampler,
+                           GLenum pname,
+                           uint32_t params_shm_id,
+                           uint32_t params_shm_offset) {
+  gles2::cmds::GetSamplerParameterfv* c =
+      GetCmdSpace<gles2::cmds::GetSamplerParameterfv>();
+  if (c) {
+    c->Init(sampler, pname, params_shm_id, params_shm_offset);
+  }
+}
+
+void GetSamplerParameteriv(GLuint sampler,
+                           GLenum pname,
+                           uint32_t params_shm_id,
+                           uint32_t params_shm_offset) {
+  gles2::cmds::GetSamplerParameteriv* c =
+      GetCmdSpace<gles2::cmds::GetSamplerParameteriv>();
+  if (c) {
+    c->Init(sampler, pname, params_shm_id, params_shm_offset);
+  }
+}
+
 void GetShaderiv(GLuint shader,
                  GLenum pname,
                  uint32_t params_shm_id,
@@ -886,6 +963,15 @@
   }
 }
 
+void IsSampler(GLuint sampler,
+               uint32_t result_shm_id,
+               uint32_t result_shm_offset) {
+  gles2::cmds::IsSampler* c = GetCmdSpace<gles2::cmds::IsSampler>();
+  if (c) {
+    c->Init(sampler, result_shm_id, result_shm_offset);
+  }
+}
+
 void IsShader(GLuint shader,
               uint32_t result_shm_id,
               uint32_t result_shm_offset) {
@@ -904,6 +990,16 @@
   }
 }
 
+void IsTransformFeedback(GLuint transformfeedback,
+                         uint32_t result_shm_id,
+                         uint32_t result_shm_offset) {
+  gles2::cmds::IsTransformFeedback* c =
+      GetCmdSpace<gles2::cmds::IsTransformFeedback>();
+  if (c) {
+    c->Init(transformfeedback, result_shm_id, result_shm_offset);
+  }
+}
+
 void LineWidth(GLfloat width) {
   gles2::cmds::LineWidth* c = GetCmdSpace<gles2::cmds::LineWidth>();
   if (c) {
@@ -918,6 +1014,14 @@
   }
 }
 
+void PauseTransformFeedback() {
+  gles2::cmds::PauseTransformFeedback* c =
+      GetCmdSpace<gles2::cmds::PauseTransformFeedback>();
+  if (c) {
+    c->Init();
+  }
+}
+
 void PixelStorei(GLenum pname, GLint param) {
   gles2::cmds::PixelStorei* c = GetCmdSpace<gles2::cmds::PixelStorei>();
   if (c) {
@@ -976,6 +1080,14 @@
   }
 }
 
+void ResumeTransformFeedback() {
+  gles2::cmds::ResumeTransformFeedback* c =
+      GetCmdSpace<gles2::cmds::ResumeTransformFeedback>();
+  if (c) {
+    c->Init();
+  }
+}
+
 void SampleCoverage(GLclampf value, GLboolean invert) {
   gles2::cmds::SampleCoverage* c = GetCmdSpace<gles2::cmds::SampleCoverage>();
   if (c) {
@@ -983,6 +1095,46 @@
   }
 }
 
+void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) {
+  gles2::cmds::SamplerParameterf* c =
+      GetCmdSpace<gles2::cmds::SamplerParameterf>();
+  if (c) {
+    c->Init(sampler, pname, param);
+  }
+}
+
+void SamplerParameterfvImmediate(GLuint sampler,
+                                 GLenum pname,
+                                 const GLfloat* params) {
+  const uint32_t size = gles2::cmds::SamplerParameterfvImmediate::ComputeSize();
+  gles2::cmds::SamplerParameterfvImmediate* c =
+      GetImmediateCmdSpaceTotalSize<gles2::cmds::SamplerParameterfvImmediate>(
+          size);
+  if (c) {
+    c->Init(sampler, pname, params);
+  }
+}
+
+void SamplerParameteri(GLuint sampler, GLenum pname, GLint param) {
+  gles2::cmds::SamplerParameteri* c =
+      GetCmdSpace<gles2::cmds::SamplerParameteri>();
+  if (c) {
+    c->Init(sampler, pname, param);
+  }
+}
+
+void SamplerParameterivImmediate(GLuint sampler,
+                                 GLenum pname,
+                                 const GLint* params) {
+  const uint32_t size = gles2::cmds::SamplerParameterivImmediate::ComputeSize();
+  gles2::cmds::SamplerParameterivImmediate* c =
+      GetImmediateCmdSpaceTotalSize<gles2::cmds::SamplerParameterivImmediate>(
+          size);
+  if (c) {
+    c->Init(sampler, pname, params);
+  }
+}
+
 void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
   gles2::cmds::Scissor* c = GetCmdSpace<gles2::cmds::Scissor>();
   if (c) {
@@ -1689,6 +1841,14 @@
   }
 }
 
+void BeginTransformFeedback(GLenum primitivemode) {
+  gles2::cmds::BeginTransformFeedback* c =
+      GetCmdSpace<gles2::cmds::BeginTransformFeedback>();
+  if (c) {
+    c->Init(primitivemode);
+  }
+}
+
 void EndQueryEXT(GLenum target, GLuint submit_count) {
   gles2::cmds::EndQueryEXT* c = GetCmdSpace<gles2::cmds::EndQueryEXT>();
   if (c) {
@@ -1696,6 +1856,14 @@
   }
 }
 
+void EndTransformFeedback() {
+  gles2::cmds::EndTransformFeedback* c =
+      GetCmdSpace<gles2::cmds::EndTransformFeedback>();
+  if (c) {
+    c->Init();
+  }
+}
+
 void InsertEventMarkerEXT(GLuint bucket_id) {
   gles2::cmds::InsertEventMarkerEXT* c =
       GetCmdSpace<gles2::cmds::InsertEventMarkerEXT>();
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 19a005f..88b9c72 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -2314,6 +2314,14 @@
     const GLuint* /* valuebuffers */) {
 }
 
+void GLES2Implementation::GenSamplersHelper(
+    GLsizei /* n */, const GLuint* /* samplers */) {
+}
+
+void GLES2Implementation::GenTransformFeedbacksHelper(
+    GLsizei /* n */, const GLuint* /* transformfeedbacks */) {
+}
+
 // 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
@@ -2684,6 +2692,39 @@
   }
 }
 
+void GLES2Implementation::DeleteSamplersStub(
+    GLsizei n, const GLuint* samplers) {
+  helper_->DeleteSamplersImmediate(n, samplers);
+}
+
+void GLES2Implementation::DeleteSamplersHelper(
+    GLsizei n, const GLuint* samplers) {
+  if (!GetIdHandler(id_namespaces::kSamplers)->FreeIds(
+      this, n, samplers, &GLES2Implementation::DeleteSamplersStub)) {
+    SetGLError(
+        GL_INVALID_VALUE,
+        "glDeleteSamplers", "id not created by this context.");
+    return;
+  }
+}
+
+void GLES2Implementation::DeleteTransformFeedbacksStub(
+    GLsizei n, const GLuint* transformfeedbacks) {
+  helper_->DeleteTransformFeedbacksImmediate(n, transformfeedbacks);
+}
+
+void GLES2Implementation::DeleteTransformFeedbacksHelper(
+    GLsizei n, const GLuint* transformfeedbacks) {
+  if (!GetIdHandler(id_namespaces::kTransformFeedbacks)->FreeIds(
+      this, n, transformfeedbacks,
+      &GLES2Implementation::DeleteTransformFeedbacksStub)) {
+    SetGLError(
+        GL_INVALID_VALUE,
+        "glDeleteTransformFeedbacks", "id not created by this context.");
+    return;
+  }
+}
+
 void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
     GLsizei n,
     const GLuint* valuebuffers) {
@@ -3985,6 +4026,18 @@
   return true;
 }
 
+bool GLES2Implementation::GetSamplerParameterfvHelper(
+    GLuint /* sampler */, GLenum /* pname */, GLfloat* /* params */) {
+  // TODO(zmo): Implement client side caching.
+  return false;
+}
+
+bool GLES2Implementation::GetSamplerParameterivHelper(
+    GLuint /* sampler */, GLenum /* pname */, GLint* /* params */) {
+  // TODO(zmo): Implement client side caching.
+  return false;
+}
+
 // Include the auto-generated part of this file. We split this because it means
 // we can easily edit the non-auto generated parts right here in this file
 // instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index e473006..7d17d64 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -431,6 +431,8 @@
   bool IsVertexArrayReservedId(GLuint id) { return false; }
   bool IsProgramReservedId(GLuint id) { return false; }
   bool IsValuebufferReservedId(GLuint id) { return false; }
+  bool IsSamplerReservedId(GLuint id) { return false; }
+  bool IsTransformFeedbackReservedId(GLuint id) { return false; }
 
   void BindBufferHelper(GLenum target, GLuint buffer);
   void BindFramebufferHelper(GLenum target, GLuint framebuffer);
@@ -453,6 +455,8 @@
   void GenVertexArraysOESHelper(GLsizei n, const GLuint* arrays);
   void GenQueriesEXTHelper(GLsizei n, const GLuint* queries);
   void GenValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* valuebuffers);
+  void GenSamplersHelper(GLsizei n, const GLuint* samplers);
+  void GenTransformFeedbacksHelper(GLsizei n, const GLuint* transformfeedbacks);
 
   void DeleteBuffersHelper(GLsizei n, const GLuint* buffers);
   void DeleteFramebuffersHelper(GLsizei n, const GLuint* framebuffers);
@@ -463,6 +467,9 @@
   void DeleteQueriesEXTHelper(GLsizei n, const GLuint* queries);
   void DeleteVertexArraysOESHelper(GLsizei n, const GLuint* arrays);
   void DeleteValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* valuebuffers);
+  void DeleteSamplersHelper(GLsizei n, const GLuint* samplers);
+  void DeleteTransformFeedbacksHelper(
+      GLsizei n, const GLuint* transformfeedbacks);
 
   void DeleteBuffersStub(GLsizei n, const GLuint* buffers);
   void DeleteFramebuffersStub(GLsizei n, const GLuint* framebuffers);
@@ -472,6 +479,9 @@
   void DeleteShaderStub(GLsizei n, const GLuint* shaders);
   void DeleteVertexArraysOESStub(GLsizei n, const GLuint* arrays);
   void DeleteValuebuffersCHROMIUMStub(GLsizei n, const GLuint* valuebuffers);
+  void DeleteSamplersStub(GLsizei n, const GLuint* samplers);
+  void DeleteTransformFeedbacksStub(
+      GLsizei n, const GLuint* transformfeedbacks);
 
   void BufferDataHelper(
       GLenum target, GLsizeiptr size, const void* data, GLenum usage);
@@ -520,6 +530,10 @@
       GLenum target, GLenum format, GLenum pname, GLsizei bufSize,
       GLint* params);
   bool GetProgramivHelper(GLuint program, GLenum pname, GLint* params);
+  bool GetSamplerParameterfvHelper(
+      GLuint sampler, GLenum pname, GLfloat* params);
+  bool GetSamplerParameterivHelper(
+      GLuint sampler, GLenum pname, GLint* params);
   bool GetRenderbufferParameterivHelper(
       GLenum target, GLenum pname, GLint* params);
   bool GetShaderivHelper(GLuint shader, GLenum pname, GLint* params);
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 7d03d88..3a5253a 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -27,8 +27,12 @@
 
 void BindRenderbuffer(GLenum target, GLuint renderbuffer) override;
 
+void BindSampler(GLuint unit, GLuint sampler) override;
+
 void BindTexture(GLenum target, GLuint texture) override;
 
+void BindTransformFeedback(GLenum target, GLuint transformfeedback) override;
+
 void BlendColor(GLclampf red,
                 GLclampf green,
                 GLclampf blue,
@@ -132,10 +136,14 @@
 
 void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) override;
 
+void DeleteSamplers(GLsizei n, const GLuint* samplers) override;
+
 void DeleteShader(GLuint shader) override;
 
 void DeleteTextures(GLsizei n, const GLuint* textures) override;
 
+void DeleteTransformFeedbacks(GLsizei n, const GLuint* ids) override;
+
 void DepthFunc(GLenum func) override;
 
 void DepthMask(GLboolean flag) override;
@@ -186,8 +194,12 @@
 
 void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) override;
 
+void GenSamplers(GLsizei n, GLuint* samplers) override;
+
 void GenTextures(GLsizei n, GLuint* textures) override;
 
+void GenTransformFeedbacks(GLsizei n, GLuint* ids) override;
+
 void GetActiveAttrib(GLuint program,
                      GLuint index,
                      GLsizei bufsize,
@@ -243,6 +255,14 @@
                                 GLenum pname,
                                 GLint* params) override;
 
+void GetSamplerParameterfv(GLuint sampler,
+                           GLenum pname,
+                           GLfloat* params) override;
+
+void GetSamplerParameteriv(GLuint sampler,
+                           GLenum pname,
+                           GLint* params) override;
+
 void GetShaderiv(GLuint shader, GLenum pname, GLint* params) override;
 
 void GetShaderInfoLog(GLuint shader,
@@ -300,14 +320,20 @@
 
 GLboolean IsRenderbuffer(GLuint renderbuffer) override;
 
+GLboolean IsSampler(GLuint sampler) override;
+
 GLboolean IsShader(GLuint shader) override;
 
 GLboolean IsTexture(GLuint texture) override;
 
+GLboolean IsTransformFeedback(GLuint transformfeedback) override;
+
 void LineWidth(GLfloat width) override;
 
 void LinkProgram(GLuint program) override;
 
+void PauseTransformFeedback() override;
+
 void PixelStorei(GLenum pname, GLint param) override;
 
 void PolygonOffset(GLfloat factor, GLfloat units) override;
@@ -329,8 +355,22 @@
                          GLsizei width,
                          GLsizei height) override;
 
+void ResumeTransformFeedback() override;
+
 void SampleCoverage(GLclampf value, GLboolean invert) override;
 
+void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) override;
+
+void SamplerParameterfv(GLuint sampler,
+                        GLenum pname,
+                        const GLfloat* params) override;
+
+void SamplerParameteri(GLuint sampler, GLenum pname, GLint param) override;
+
+void SamplerParameteriv(GLuint sampler,
+                        GLenum pname,
+                        const GLint* params) override;
+
 void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) override;
 
 void ShaderBinary(GLsizei n,
@@ -599,8 +639,12 @@
 
 void BeginQueryEXT(GLenum target, GLuint id) override;
 
+void BeginTransformFeedback(GLenum primitivemode) override;
+
 void EndQueryEXT(GLenum target) override;
 
+void EndTransformFeedback() override;
+
 void GetQueryivEXT(GLenum target, GLenum pname, GLint* params) override;
 
 void GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* params) override;
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index d7a45ce..e7ef769 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -62,6 +62,14 @@
   CheckGLError();
 }
 
+void GLES2Implementation::BindSampler(GLuint unit, GLuint sampler) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindSampler(" << unit << ", "
+                     << sampler << ")");
+  helper_->BindSampler(unit, sampler);
+  CheckGLError();
+}
+
 void GLES2Implementation::BindTexture(GLenum target, GLuint texture) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindTexture("
@@ -75,6 +83,16 @@
   CheckGLError();
 }
 
+void GLES2Implementation::BindTransformFeedback(GLenum target,
+                                                GLuint transformfeedback) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindTransformFeedback("
+                     << GLES2Util::GetStringTransformFeedbackBindTarget(target)
+                     << ", " << transformfeedback << ")");
+  helper_->BindTransformFeedback(target, transformfeedback);
+  CheckGLError();
+}
+
 void GLES2Implementation::BlendColor(GLclampf red,
                                      GLclampf green,
                                      GLclampf blue,
@@ -397,6 +415,28 @@
   CheckGLError();
 }
 
+void GLES2Implementation::DeleteSamplers(GLsizei n, const GLuint* samplers) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteSamplers(" << n << ", "
+                     << static_cast<const void*>(samplers) << ")");
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (GLsizei i = 0; i < n; ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << samplers[i]);
+    }
+  });
+  GPU_CLIENT_DCHECK_CODE_BLOCK({
+    for (GLsizei i = 0; i < n; ++i) {
+      DCHECK(samplers[i] != 0);
+    }
+  });
+  if (n < 0) {
+    SetGLError(GL_INVALID_VALUE, "glDeleteSamplers", "n < 0");
+    return;
+  }
+  DeleteSamplersHelper(n, samplers);
+  CheckGLError();
+}
+
 void GLES2Implementation::DeleteShader(GLuint shader) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteShader(" << shader << ")");
@@ -427,6 +467,29 @@
   CheckGLError();
 }
 
+void GLES2Implementation::DeleteTransformFeedbacks(GLsizei n,
+                                                   const GLuint* ids) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteTransformFeedbacks(" << n
+                     << ", " << static_cast<const void*>(ids) << ")");
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (GLsizei i = 0; i < n; ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << ids[i]);
+    }
+  });
+  GPU_CLIENT_DCHECK_CODE_BLOCK({
+    for (GLsizei i = 0; i < n; ++i) {
+      DCHECK(ids[i] != 0);
+    }
+  });
+  if (n < 0) {
+    SetGLError(GL_INVALID_VALUE, "glDeleteTransformFeedbacks", "n < 0");
+    return;
+  }
+  DeleteTransformFeedbacksHelper(n, ids);
+  CheckGLError();
+}
+
 void GLES2Implementation::DepthFunc(GLenum func) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDepthFunc("
@@ -588,6 +651,27 @@
   CheckGLError();
 }
 
+void GLES2Implementation::GenSamplers(GLsizei n, GLuint* samplers) {
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenSamplers(" << n << ", "
+                     << static_cast<const void*>(samplers) << ")");
+  if (n < 0) {
+    SetGLError(GL_INVALID_VALUE, "glGenSamplers", "n < 0");
+    return;
+  }
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GetIdHandler(id_namespaces::kSamplers)->MakeIds(this, 0, n, samplers);
+  GenSamplersHelper(n, samplers);
+  helper_->GenSamplersImmediate(n, samplers);
+  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 << ": " << samplers[i]);
+    }
+  });
+  CheckGLError();
+}
+
 void GLES2Implementation::GenTextures(GLsizei n, GLuint* textures) {
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenTextures(" << n << ", "
                      << static_cast<const void*>(textures) << ")");
@@ -609,6 +693,27 @@
   CheckGLError();
 }
 
+void GLES2Implementation::GenTransformFeedbacks(GLsizei n, GLuint* ids) {
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenTransformFeedbacks(" << n
+                     << ", " << static_cast<const void*>(ids) << ")");
+  if (n < 0) {
+    SetGLError(GL_INVALID_VALUE, "glGenTransformFeedbacks", "n < 0");
+    return;
+  }
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GetIdHandler(id_namespaces::kTransformFeedbacks)->MakeIds(this, 0, n, ids);
+  GenTransformFeedbacksHelper(n, ids);
+  helper_->GenTransformFeedbacksImmediate(n, ids);
+  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 << ": " << ids[i]);
+    }
+  });
+  CheckGLError();
+}
+
 void GLES2Implementation::GetBooleanv(GLenum pname, GLboolean* params) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLboolean, params);
@@ -874,6 +979,65 @@
   });
   CheckGLError();
 }
+void GLES2Implementation::GetSamplerParameterfv(GLuint sampler,
+                                                GLenum pname,
+                                                GLfloat* params) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetSamplerParameterfv("
+                     << sampler << ", "
+                     << GLES2Util::GetStringSamplerParameter(pname) << ", "
+                     << static_cast<const void*>(params) << ")");
+  TRACE_EVENT0("gpu", "GLES2Implementation::GetSamplerParameterfv");
+  if (GetSamplerParameterfvHelper(sampler, pname, params)) {
+    return;
+  }
+  typedef cmds::GetSamplerParameterfv::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return;
+  }
+  result->SetNumResults(0);
+  helper_->GetSamplerParameterfv(sampler, pname, GetResultShmId(),
+                                 GetResultShmOffset());
+  WaitForCmd();
+  result->CopyResult(params);
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (int32_t i = 0; i < result->GetNumResults(); ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
+    }
+  });
+  CheckGLError();
+}
+void GLES2Implementation::GetSamplerParameteriv(GLuint sampler,
+                                                GLenum pname,
+                                                GLint* params) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetSamplerParameteriv("
+                     << sampler << ", "
+                     << GLES2Util::GetStringSamplerParameter(pname) << ", "
+                     << static_cast<const void*>(params) << ")");
+  TRACE_EVENT0("gpu", "GLES2Implementation::GetSamplerParameteriv");
+  if (GetSamplerParameterivHelper(sampler, pname, params)) {
+    return;
+  }
+  typedef cmds::GetSamplerParameteriv::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return;
+  }
+  result->SetNumResults(0);
+  helper_->GetSamplerParameteriv(sampler, pname, GetResultShmId(),
+                                 GetResultShmOffset());
+  WaitForCmd();
+  result->CopyResult(params);
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (int32_t i = 0; i < result->GetNumResults(); ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
+    }
+  });
+  CheckGLError();
+}
 void GLES2Implementation::GetShaderiv(GLuint shader,
                                       GLenum pname,
                                       GLint* params) {
@@ -1154,6 +1318,24 @@
   return result_value;
 }
 
+GLboolean GLES2Implementation::IsSampler(GLuint sampler) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  TRACE_EVENT0("gpu", "GLES2Implementation::IsSampler");
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsSampler(" << sampler << ")");
+  typedef cmds::IsSampler::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return GL_FALSE;
+  }
+  *result = 0;
+  helper_->IsSampler(sampler, GetResultShmId(), GetResultShmOffset());
+  WaitForCmd();
+  GLboolean result_value = *result != 0;
+  GPU_CLIENT_LOG("returned " << result_value);
+  CheckGLError();
+  return result_value;
+}
+
 GLboolean GLES2Implementation::IsShader(GLuint shader) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   TRACE_EVENT0("gpu", "GLES2Implementation::IsShader");
@@ -1190,6 +1372,26 @@
   return result_value;
 }
 
+GLboolean GLES2Implementation::IsTransformFeedback(GLuint transformfeedback) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  TRACE_EVENT0("gpu", "GLES2Implementation::IsTransformFeedback");
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsTransformFeedback("
+                     << transformfeedback << ")");
+  typedef cmds::IsTransformFeedback::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return GL_FALSE;
+  }
+  *result = 0;
+  helper_->IsTransformFeedback(transformfeedback, GetResultShmId(),
+                               GetResultShmOffset());
+  WaitForCmd();
+  GLboolean result_value = *result != 0;
+  GPU_CLIENT_LOG("returned " << result_value);
+  CheckGLError();
+  return result_value;
+}
+
 void GLES2Implementation::LineWidth(GLfloat width) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLineWidth(" << width << ")");
@@ -1197,6 +1399,14 @@
   CheckGLError();
 }
 
+void GLES2Implementation::PauseTransformFeedback() {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPauseTransformFeedback("
+                     << ")");
+  helper_->PauseTransformFeedback();
+  CheckGLError();
+}
+
 void GLES2Implementation::PolygonOffset(GLfloat factor, GLfloat units) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPolygonOffset(" << factor << ", "
@@ -1242,6 +1452,14 @@
   CheckGLError();
 }
 
+void GLES2Implementation::ResumeTransformFeedback() {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResumeTransformFeedback("
+                     << ")");
+  helper_->ResumeTransformFeedback();
+  CheckGLError();
+}
+
 void GLES2Implementation::SampleCoverage(GLclampf value, GLboolean invert) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSampleCoverage(" << value << ", "
@@ -1250,6 +1468,52 @@
   CheckGLError();
 }
 
+void GLES2Implementation::SamplerParameterf(GLuint sampler,
+                                            GLenum pname,
+                                            GLfloat param) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSamplerParameterf(" << sampler
+                     << ", " << GLES2Util::GetStringSamplerParameter(pname)
+                     << ", " << param << ")");
+  helper_->SamplerParameterf(sampler, pname, param);
+  CheckGLError();
+}
+
+void GLES2Implementation::SamplerParameterfv(GLuint sampler,
+                                             GLenum pname,
+                                             const GLfloat* params) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSamplerParameterfv(" << sampler
+                     << ", " << GLES2Util::GetStringSamplerParameter(pname)
+                     << ", " << static_cast<const void*>(params) << ")");
+  GPU_CLIENT_LOG("values: " << params[0]);
+  helper_->SamplerParameterfvImmediate(sampler, pname, params);
+  CheckGLError();
+}
+
+void GLES2Implementation::SamplerParameteri(GLuint sampler,
+                                            GLenum pname,
+                                            GLint param) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSamplerParameteri(" << sampler
+                     << ", " << GLES2Util::GetStringSamplerParameter(pname)
+                     << ", " << param << ")");
+  helper_->SamplerParameteri(sampler, pname, param);
+  CheckGLError();
+}
+
+void GLES2Implementation::SamplerParameteriv(GLuint sampler,
+                                             GLenum pname,
+                                             const GLint* params) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSamplerParameteriv(" << sampler
+                     << ", " << GLES2Util::GetStringSamplerParameter(pname)
+                     << ", " << static_cast<const void*>(params) << ")");
+  GPU_CLIENT_LOG("values: " << params[0]);
+  helper_->SamplerParameterivImmediate(sampler, pname, params);
+  CheckGLError();
+}
+
 void GLES2Implementation::Scissor(GLint x,
                                   GLint y,
                                   GLsizei width,
@@ -2391,6 +2655,23 @@
   CheckGLError();
 }
 
+void GLES2Implementation::BeginTransformFeedback(GLenum primitivemode) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBeginTransformFeedback("
+                     << GLES2Util::GetStringTransformFeedbackPrimitiveMode(
+                            primitivemode) << ")");
+  helper_->BeginTransformFeedback(primitivemode);
+  CheckGLError();
+}
+
+void GLES2Implementation::EndTransformFeedback() {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEndTransformFeedback("
+                     << ")");
+  helper_->EndTransformFeedback();
+  CheckGLError();
+}
+
 void GLES2Implementation::GenVertexArraysOES(GLsizei n, GLuint* arrays) {
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenVertexArraysOES(" << n << ", "
                      << static_cast<const void*>(arrays) << ")");
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index d772b8e..3d0f1b0 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -384,7 +384,9 @@
   static const GLuint kFramebuffersStartId = 1;
   static const GLuint kProgramsAndShadersStartId = 1;
   static const GLuint kRenderbuffersStartId = 1;
+  static const GLuint kSamplersStartId = 1;
   static const GLuint kTexturesStartId = 1;
+  static const GLuint kTransformFeedbacksStartId = 1;
   static const GLuint kQueriesStartId = 1;
   static const GLuint kVertexArraysStartId = 1;
   static const GLuint kValuebuffersStartId = 1;
@@ -754,7 +756,9 @@
 const GLuint GLES2ImplementationTest::kFramebuffersStartId;
 const GLuint GLES2ImplementationTest::kProgramsAndShadersStartId;
 const GLuint GLES2ImplementationTest::kRenderbuffersStartId;
+const GLuint GLES2ImplementationTest::kSamplersStartId;
 const GLuint GLES2ImplementationTest::kTexturesStartId;
+const GLuint GLES2ImplementationTest::kTransformFeedbacksStartId;
 const GLuint GLES2ImplementationTest::kQueriesStartId;
 const GLuint GLES2ImplementationTest::kVertexArraysStartId;
 const GLuint GLES2ImplementationTest::kValuebuffersStartId;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index 3d0eaa2..f501cd9 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -67,6 +67,28 @@
   EXPECT_TRUE(NoCommandsWritten());
 }
 
+TEST_F(GLES2ImplementationTest, BindSampler) {
+  struct Cmds {
+    cmds::BindSampler cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(1, 2);
+
+  gl_->BindSampler(1, 2);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, BindTransformFeedback) {
+  struct Cmds {
+    cmds::BindTransformFeedback cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(GL_TRANSFORM_FEEDBACK, 2);
+
+  gl_->BindTransformFeedback(GL_TRANSFORM_FEEDBACK, 2);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, BlendColor) {
   struct Cmds {
     cmds::BlendColor cmd;
@@ -312,6 +334,20 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
+TEST_F(GLES2ImplementationTest, DeleteSamplers) {
+  GLuint ids[2] = {kSamplersStartId, kSamplersStartId + 1};
+  struct Cmds {
+    cmds::DeleteSamplersImmediate del;
+    GLuint data[2];
+  };
+  Cmds expected;
+  expected.del.Init(arraysize(ids), &ids[0]);
+  expected.data[0] = kSamplersStartId;
+  expected.data[1] = kSamplersStartId + 1;
+  gl_->DeleteSamplers(arraysize(ids), &ids[0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, DeleteShader) {
   struct Cmds {
     cmds::DeleteShader cmd;
@@ -337,6 +373,20 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
+TEST_F(GLES2ImplementationTest, DeleteTransformFeedbacks) {
+  GLuint ids[2] = {kTransformFeedbacksStartId, kTransformFeedbacksStartId + 1};
+  struct Cmds {
+    cmds::DeleteTransformFeedbacksImmediate del;
+    GLuint data[2];
+  };
+  Cmds expected;
+  expected.del.Init(arraysize(ids), &ids[0]);
+  expected.data[0] = kTransformFeedbacksStartId;
+  expected.data[1] = kTransformFeedbacksStartId + 1;
+  gl_->DeleteTransformFeedbacks(arraysize(ids), &ids[0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, DepthFunc) {
   struct Cmds {
     cmds::DepthFunc cmd;
@@ -543,6 +593,24 @@
   EXPECT_EQ(kRenderbuffersStartId + 1, ids[1]);
 }
 
+TEST_F(GLES2ImplementationTest, GenSamplers) {
+  GLuint ids[2] = {
+      0,
+  };
+  struct Cmds {
+    cmds::GenSamplersImmediate gen;
+    GLuint data[2];
+  };
+  Cmds expected;
+  expected.gen.Init(arraysize(ids), &ids[0]);
+  expected.data[0] = kSamplersStartId;
+  expected.data[1] = kSamplersStartId + 1;
+  gl_->GenSamplers(arraysize(ids), &ids[0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_EQ(kSamplersStartId, ids[0]);
+  EXPECT_EQ(kSamplersStartId + 1, ids[1]);
+}
+
 TEST_F(GLES2ImplementationTest, GenTextures) {
   GLuint ids[2] = {
       0,
@@ -560,6 +628,24 @@
   EXPECT_EQ(kTexturesStartId, ids[0]);
   EXPECT_EQ(kTexturesStartId + 1, ids[1]);
 }
+
+TEST_F(GLES2ImplementationTest, GenTransformFeedbacks) {
+  GLuint ids[2] = {
+      0,
+  };
+  struct Cmds {
+    cmds::GenTransformFeedbacksImmediate gen;
+    GLuint data[2];
+  };
+  Cmds expected;
+  expected.gen.Init(arraysize(ids), &ids[0]);
+  expected.data[0] = kTransformFeedbacksStartId;
+  expected.data[1] = kTransformFeedbacksStartId + 1;
+  gl_->GenTransformFeedbacks(arraysize(ids), &ids[0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_EQ(kTransformFeedbacksStartId, ids[0]);
+  EXPECT_EQ(kTransformFeedbacksStartId + 1, ids[1]);
+}
 // TODO: Implement unit test for GetActiveAttrib
 // TODO: Implement unit test for GetActiveUniform
 // TODO: Implement unit test for GetAttachedShaders
@@ -707,6 +793,40 @@
   EXPECT_EQ(static_cast<Result::Type>(1), result);
 }
 
+TEST_F(GLES2ImplementationTest, GetSamplerParameterfv) {
+  struct Cmds {
+    cmds::GetSamplerParameterfv cmd;
+  };
+  typedef cmds::GetSamplerParameterfv::Result Result;
+  Result::Type result = 0;
+  Cmds expected;
+  ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+  expected.cmd.Init(123, GL_TEXTURE_MAG_FILTER, result1.id, result1.offset);
+  EXPECT_CALL(*command_buffer(), OnFlush())
+      .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+      .RetiresOnSaturation();
+  gl_->GetSamplerParameterfv(123, GL_TEXTURE_MAG_FILTER, &result);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
+TEST_F(GLES2ImplementationTest, GetSamplerParameteriv) {
+  struct Cmds {
+    cmds::GetSamplerParameteriv cmd;
+  };
+  typedef cmds::GetSamplerParameteriv::Result Result;
+  Result::Type result = 0;
+  Cmds expected;
+  ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+  expected.cmd.Init(123, GL_TEXTURE_MAG_FILTER, result1.id, result1.offset);
+  EXPECT_CALL(*command_buffer(), OnFlush())
+      .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+      .RetiresOnSaturation();
+  gl_->GetSamplerParameteriv(123, GL_TEXTURE_MAG_FILTER, &result);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
 TEST_F(GLES2ImplementationTest, GetShaderiv) {
   struct Cmds {
     cmds::GetShaderiv cmd;
@@ -941,6 +1061,25 @@
   EXPECT_TRUE(result);
 }
 
+TEST_F(GLES2ImplementationTest, IsSampler) {
+  struct Cmds {
+    cmds::IsSampler cmd;
+  };
+
+  Cmds expected;
+  ExpectedMemoryInfo result1 =
+      GetExpectedResultMemory(sizeof(cmds::IsSampler::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_->IsSampler(1);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_TRUE(result);
+}
+
 TEST_F(GLES2ImplementationTest, IsShader) {
   struct Cmds {
     cmds::IsShader cmd;
@@ -979,6 +1118,25 @@
   EXPECT_TRUE(result);
 }
 
+TEST_F(GLES2ImplementationTest, IsTransformFeedback) {
+  struct Cmds {
+    cmds::IsTransformFeedback cmd;
+  };
+
+  Cmds expected;
+  ExpectedMemoryInfo result1 =
+      GetExpectedResultMemory(sizeof(cmds::IsTransformFeedback::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_->IsTransformFeedback(1);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_TRUE(result);
+}
+
 TEST_F(GLES2ImplementationTest, LineWidth) {
   struct Cmds {
     cmds::LineWidth cmd;
@@ -1001,6 +1159,17 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
+TEST_F(GLES2ImplementationTest, PauseTransformFeedback) {
+  struct Cmds {
+    cmds::PauseTransformFeedback cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init();
+
+  gl_->PauseTransformFeedback();
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, PixelStorei) {
   struct Cmds {
     cmds::PixelStorei cmd;
@@ -1056,6 +1225,17 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
+TEST_F(GLES2ImplementationTest, ResumeTransformFeedback) {
+  struct Cmds {
+    cmds::ResumeTransformFeedback cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init();
+
+  gl_->ResumeTransformFeedback();
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, SampleCoverage) {
   struct Cmds {
     cmds::SampleCoverage cmd;
@@ -1067,6 +1247,60 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 
+TEST_F(GLES2ImplementationTest, SamplerParameterf) {
+  struct Cmds {
+    cmds::SamplerParameterf cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(1, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+  gl_->SamplerParameterf(1, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, SamplerParameterfv) {
+  GLfloat data[1] = {0};
+  struct Cmds {
+    cmds::SamplerParameterfvImmediate cmd;
+    GLfloat data[1];
+  };
+
+  for (int jj = 0; jj < 1; ++jj) {
+    data[jj] = static_cast<GLfloat>(jj);
+  }
+  Cmds expected;
+  expected.cmd.Init(1, GL_TEXTURE_MAG_FILTER, &data[0]);
+  gl_->SamplerParameterfv(1, GL_TEXTURE_MAG_FILTER, &data[0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, SamplerParameteri) {
+  struct Cmds {
+    cmds::SamplerParameteri cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(1, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+  gl_->SamplerParameteri(1, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, SamplerParameteriv) {
+  GLint data[1] = {0};
+  struct Cmds {
+    cmds::SamplerParameterivImmediate cmd;
+    GLint data[1];
+  };
+
+  for (int jj = 0; jj < 1; ++jj) {
+    data[jj] = static_cast<GLint>(jj);
+  }
+  Cmds expected;
+  expected.cmd.Init(1, GL_TEXTURE_MAG_FILTER, &data[0]);
+  gl_->SamplerParameteriv(1, GL_TEXTURE_MAG_FILTER, &data[0]);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
 TEST_F(GLES2ImplementationTest, Scissor) {
   struct Cmds {
     cmds::Scissor cmd;
@@ -2122,6 +2356,28 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
 // TODO: Implement unit test for BeginQueryEXT
+
+TEST_F(GLES2ImplementationTest, BeginTransformFeedback) {
+  struct Cmds {
+    cmds::BeginTransformFeedback cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(GL_POINTS);
+
+  gl_->BeginTransformFeedback(GL_POINTS);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, EndTransformFeedback) {
+  struct Cmds {
+    cmds::EndTransformFeedback cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init();
+
+  gl_->EndTransformFeedback();
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
 // TODO: Implement unit test for InsertEventMarkerEXT
 // TODO: Implement unit test for PushGroupMarkerEXT
 
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index f6317bb..5a5d289 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -21,7 +21,9 @@
 virtual void BindBuffer(GLenum target, GLuint buffer) = 0;
 virtual void BindFramebuffer(GLenum target, GLuint framebuffer) = 0;
 virtual void BindRenderbuffer(GLenum target, GLuint renderbuffer) = 0;
+virtual void BindSampler(GLuint unit, GLuint sampler) = 0;
 virtual void BindTexture(GLenum target, GLuint texture) = 0;
+virtual void BindTransformFeedback(GLenum target, GLuint transformfeedback) = 0;
 virtual void BlendColor(GLclampf red,
                         GLclampf green,
                         GLclampf blue,
@@ -99,8 +101,10 @@
 virtual void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) = 0;
 virtual void DeleteProgram(GLuint program) = 0;
 virtual void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) = 0;
+virtual void DeleteSamplers(GLsizei n, const GLuint* samplers) = 0;
 virtual void DeleteShader(GLuint shader) = 0;
 virtual void DeleteTextures(GLsizei n, const GLuint* textures) = 0;
+virtual void DeleteTransformFeedbacks(GLsizei n, const GLuint* ids) = 0;
 virtual void DepthFunc(GLenum func) = 0;
 virtual void DepthMask(GLboolean flag) = 0;
 virtual void DepthRangef(GLclampf zNear, GLclampf zFar) = 0;
@@ -135,7 +139,9 @@
 virtual void GenerateMipmap(GLenum target) = 0;
 virtual void GenFramebuffers(GLsizei n, GLuint* framebuffers) = 0;
 virtual void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) = 0;
+virtual void GenSamplers(GLsizei n, GLuint* samplers) = 0;
 virtual void GenTextures(GLsizei n, GLuint* textures) = 0;
+virtual void GenTransformFeedbacks(GLsizei n, GLuint* ids) = 0;
 virtual void GetActiveAttrib(GLuint program,
                              GLuint index,
                              GLsizei bufsize,
@@ -179,6 +185,12 @@
 virtual void GetRenderbufferParameteriv(GLenum target,
                                         GLenum pname,
                                         GLint* params) = 0;
+virtual void GetSamplerParameterfv(GLuint sampler,
+                                   GLenum pname,
+                                   GLfloat* params) = 0;
+virtual void GetSamplerParameteriv(GLuint sampler,
+                                   GLenum pname,
+                                   GLint* params) = 0;
 virtual void GetShaderiv(GLuint shader, GLenum pname, GLint* params) = 0;
 virtual void GetShaderInfoLog(GLuint shader,
                               GLsizei bufsize,
@@ -221,10 +233,13 @@
 virtual GLboolean IsFramebuffer(GLuint framebuffer) = 0;
 virtual GLboolean IsProgram(GLuint program) = 0;
 virtual GLboolean IsRenderbuffer(GLuint renderbuffer) = 0;
+virtual GLboolean IsSampler(GLuint sampler) = 0;
 virtual GLboolean IsShader(GLuint shader) = 0;
 virtual GLboolean IsTexture(GLuint texture) = 0;
+virtual GLboolean IsTransformFeedback(GLuint transformfeedback) = 0;
 virtual void LineWidth(GLfloat width) = 0;
 virtual void LinkProgram(GLuint program) = 0;
+virtual void PauseTransformFeedback() = 0;
 virtual void PixelStorei(GLenum pname, GLint param) = 0;
 virtual void PolygonOffset(GLfloat factor, GLfloat units) = 0;
 virtual void ReadBuffer(GLenum src) = 0;
@@ -240,7 +255,16 @@
                                  GLenum internalformat,
                                  GLsizei width,
                                  GLsizei height) = 0;
+virtual void ResumeTransformFeedback() = 0;
 virtual void SampleCoverage(GLclampf value, GLboolean invert) = 0;
+virtual void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) = 0;
+virtual void SamplerParameterfv(GLuint sampler,
+                                GLenum pname,
+                                const GLfloat* params) = 0;
+virtual void SamplerParameteri(GLuint sampler, GLenum pname, GLint param) = 0;
+virtual void SamplerParameteriv(GLuint sampler,
+                                GLenum pname,
+                                const GLint* params) = 0;
 virtual void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) = 0;
 virtual void ShaderBinary(GLsizei n,
                           const GLuint* shaders,
@@ -438,7 +462,9 @@
 virtual void DeleteQueriesEXT(GLsizei n, const GLuint* queries) = 0;
 virtual GLboolean IsQueryEXT(GLuint id) = 0;
 virtual void BeginQueryEXT(GLenum target, GLuint id) = 0;
+virtual void BeginTransformFeedback(GLenum primitivemode) = 0;
 virtual void EndQueryEXT(GLenum target) = 0;
+virtual void EndTransformFeedback() = 0;
 virtual void GetQueryivEXT(GLenum target, GLenum pname, GLint* params) = 0;
 virtual void GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* params) = 0;
 virtual void InsertEventMarkerEXT(GLsizei length, const GLchar* marker) = 0;
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index cbab14f..c2f4920 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -20,7 +20,9 @@
 void BindBuffer(GLenum target, GLuint buffer) override;
 void BindFramebuffer(GLenum target, GLuint framebuffer) override;
 void BindRenderbuffer(GLenum target, GLuint renderbuffer) override;
+void BindSampler(GLuint unit, GLuint sampler) override;
 void BindTexture(GLenum target, GLuint texture) override;
+void BindTransformFeedback(GLenum target, GLuint transformfeedback) override;
 void BlendColor(GLclampf red,
                 GLclampf green,
                 GLclampf blue,
@@ -98,8 +100,10 @@
 void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) override;
 void DeleteProgram(GLuint program) override;
 void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) override;
+void DeleteSamplers(GLsizei n, const GLuint* samplers) override;
 void DeleteShader(GLuint shader) override;
 void DeleteTextures(GLsizei n, const GLuint* textures) override;
+void DeleteTransformFeedbacks(GLsizei n, const GLuint* ids) override;
 void DepthFunc(GLenum func) override;
 void DepthMask(GLboolean flag) override;
 void DepthRangef(GLclampf zNear, GLclampf zFar) override;
@@ -134,7 +138,9 @@
 void GenerateMipmap(GLenum target) override;
 void GenFramebuffers(GLsizei n, GLuint* framebuffers) override;
 void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) override;
+void GenSamplers(GLsizei n, GLuint* samplers) override;
 void GenTextures(GLsizei n, GLuint* textures) override;
+void GenTransformFeedbacks(GLsizei n, GLuint* ids) override;
 void GetActiveAttrib(GLuint program,
                      GLuint index,
                      GLsizei bufsize,
@@ -176,6 +182,12 @@
 void GetRenderbufferParameteriv(GLenum target,
                                 GLenum pname,
                                 GLint* params) override;
+void GetSamplerParameterfv(GLuint sampler,
+                           GLenum pname,
+                           GLfloat* params) override;
+void GetSamplerParameteriv(GLuint sampler,
+                           GLenum pname,
+                           GLint* params) override;
 void GetShaderiv(GLuint shader, GLenum pname, GLint* params) override;
 void GetShaderInfoLog(GLuint shader,
                       GLsizei bufsize,
@@ -216,10 +228,13 @@
 GLboolean IsFramebuffer(GLuint framebuffer) override;
 GLboolean IsProgram(GLuint program) override;
 GLboolean IsRenderbuffer(GLuint renderbuffer) override;
+GLboolean IsSampler(GLuint sampler) override;
 GLboolean IsShader(GLuint shader) override;
 GLboolean IsTexture(GLuint texture) override;
+GLboolean IsTransformFeedback(GLuint transformfeedback) override;
 void LineWidth(GLfloat width) override;
 void LinkProgram(GLuint program) override;
+void PauseTransformFeedback() override;
 void PixelStorei(GLenum pname, GLint param) override;
 void PolygonOffset(GLfloat factor, GLfloat units) override;
 void ReadBuffer(GLenum src) override;
@@ -235,7 +250,16 @@
                          GLenum internalformat,
                          GLsizei width,
                          GLsizei height) override;
+void ResumeTransformFeedback() override;
 void SampleCoverage(GLclampf value, GLboolean invert) override;
+void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) override;
+void SamplerParameterfv(GLuint sampler,
+                        GLenum pname,
+                        const GLfloat* params) override;
+void SamplerParameteri(GLuint sampler, GLenum pname, GLint param) override;
+void SamplerParameteriv(GLuint sampler,
+                        GLenum pname,
+                        const GLint* params) override;
 void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) override;
 void ShaderBinary(GLsizei n,
                   const GLuint* shaders,
@@ -427,7 +451,9 @@
 void DeleteQueriesEXT(GLsizei n, const GLuint* queries) override;
 GLboolean IsQueryEXT(GLuint id) override;
 void BeginQueryEXT(GLenum target, GLuint id) override;
+void BeginTransformFeedback(GLenum primitivemode) override;
 void EndQueryEXT(GLenum target) override;
+void EndTransformFeedback() override;
 void GetQueryivEXT(GLenum target, GLenum pname, GLint* params) override;
 void GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* params) override;
 void InsertEventMarkerEXT(GLsizei length, const GLchar* marker) 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 c3d2803..fcd196d 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -29,9 +29,14 @@
 void GLES2InterfaceStub::BindRenderbuffer(GLenum /* target */,
                                           GLuint /* renderbuffer */) {
 }
+void GLES2InterfaceStub::BindSampler(GLuint /* unit */, GLuint /* sampler */) {
+}
 void GLES2InterfaceStub::BindTexture(GLenum /* target */,
                                      GLuint /* texture */) {
 }
+void GLES2InterfaceStub::BindTransformFeedback(GLenum /* target */,
+                                               GLuint /* transformfeedback */) {
+}
 void GLES2InterfaceStub::BlendColor(GLclampf /* red */,
                                     GLclampf /* green */,
                                     GLclampf /* blue */,
@@ -143,11 +148,17 @@
     GLsizei /* n */,
     const GLuint* /* renderbuffers */) {
 }
+void GLES2InterfaceStub::DeleteSamplers(GLsizei /* n */,
+                                        const GLuint* /* samplers */) {
+}
 void GLES2InterfaceStub::DeleteShader(GLuint /* shader */) {
 }
 void GLES2InterfaceStub::DeleteTextures(GLsizei /* n */,
                                         const GLuint* /* textures */) {
 }
+void GLES2InterfaceStub::DeleteTransformFeedbacks(GLsizei /* n */,
+                                                  const GLuint* /* ids */) {
+}
 void GLES2InterfaceStub::DepthFunc(GLenum /* func */) {
 }
 void GLES2InterfaceStub::DepthMask(GLboolean /* flag */) {
@@ -209,8 +220,13 @@
 void GLES2InterfaceStub::GenRenderbuffers(GLsizei /* n */,
                                           GLuint* /* renderbuffers */) {
 }
+void GLES2InterfaceStub::GenSamplers(GLsizei /* n */, GLuint* /* samplers */) {
+}
 void GLES2InterfaceStub::GenTextures(GLsizei /* n */, GLuint* /* textures */) {
 }
+void GLES2InterfaceStub::GenTransformFeedbacks(GLsizei /* n */,
+                                               GLuint* /* ids */) {
+}
 void GLES2InterfaceStub::GetActiveAttrib(GLuint /* program */,
                                          GLuint /* index */,
                                          GLsizei /* bufsize */,
@@ -275,6 +291,14 @@
                                                     GLenum /* pname */,
                                                     GLint* /* params */) {
 }
+void GLES2InterfaceStub::GetSamplerParameterfv(GLuint /* sampler */,
+                                               GLenum /* pname */,
+                                               GLfloat* /* params */) {
+}
+void GLES2InterfaceStub::GetSamplerParameteriv(GLuint /* sampler */,
+                                               GLenum /* pname */,
+                                               GLint* /* params */) {
+}
 void GLES2InterfaceStub::GetShaderiv(GLuint /* shader */,
                                      GLenum /* pname */,
                                      GLint* /* params */) {
@@ -360,16 +384,25 @@
 GLboolean GLES2InterfaceStub::IsRenderbuffer(GLuint /* renderbuffer */) {
   return 0;
 }
+GLboolean GLES2InterfaceStub::IsSampler(GLuint /* sampler */) {
+  return 0;
+}
 GLboolean GLES2InterfaceStub::IsShader(GLuint /* shader */) {
   return 0;
 }
 GLboolean GLES2InterfaceStub::IsTexture(GLuint /* texture */) {
   return 0;
 }
+GLboolean GLES2InterfaceStub::IsTransformFeedback(
+    GLuint /* transformfeedback */) {
+  return 0;
+}
 void GLES2InterfaceStub::LineWidth(GLfloat /* width */) {
 }
 void GLES2InterfaceStub::LinkProgram(GLuint /* program */) {
 }
+void GLES2InterfaceStub::PauseTransformFeedback() {
+}
 void GLES2InterfaceStub::PixelStorei(GLenum /* pname */, GLint /* param */) {
 }
 void GLES2InterfaceStub::PolygonOffset(GLfloat /* factor */,
@@ -392,9 +425,27 @@
                                              GLsizei /* width */,
                                              GLsizei /* height */) {
 }
+void GLES2InterfaceStub::ResumeTransformFeedback() {
+}
 void GLES2InterfaceStub::SampleCoverage(GLclampf /* value */,
                                         GLboolean /* invert */) {
 }
+void GLES2InterfaceStub::SamplerParameterf(GLuint /* sampler */,
+                                           GLenum /* pname */,
+                                           GLfloat /* param */) {
+}
+void GLES2InterfaceStub::SamplerParameterfv(GLuint /* sampler */,
+                                            GLenum /* pname */,
+                                            const GLfloat* /* params */) {
+}
+void GLES2InterfaceStub::SamplerParameteri(GLuint /* sampler */,
+                                           GLenum /* pname */,
+                                           GLint /* param */) {
+}
+void GLES2InterfaceStub::SamplerParameteriv(GLuint /* sampler */,
+                                            GLenum /* pname */,
+                                            const GLint* /* params */) {
+}
 void GLES2InterfaceStub::Scissor(GLint /* x */,
                                  GLint /* y */,
                                  GLsizei /* width */,
@@ -743,8 +794,12 @@
 }
 void GLES2InterfaceStub::BeginQueryEXT(GLenum /* target */, GLuint /* id */) {
 }
+void GLES2InterfaceStub::BeginTransformFeedback(GLenum /* primitivemode */) {
+}
 void GLES2InterfaceStub::EndQueryEXT(GLenum /* target */) {
 }
+void GLES2InterfaceStub::EndTransformFeedback() {
+}
 void GLES2InterfaceStub::GetQueryivEXT(GLenum /* target */,
                                        GLenum /* pname */,
                                        GLint* /* params */) {
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index f952d58..cd8ad7c 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -20,7 +20,9 @@
 void BindBuffer(GLenum target, GLuint buffer) override;
 void BindFramebuffer(GLenum target, GLuint framebuffer) override;
 void BindRenderbuffer(GLenum target, GLuint renderbuffer) override;
+void BindSampler(GLuint unit, GLuint sampler) override;
 void BindTexture(GLenum target, GLuint texture) override;
+void BindTransformFeedback(GLenum target, GLuint transformfeedback) override;
 void BlendColor(GLclampf red,
                 GLclampf green,
                 GLclampf blue,
@@ -98,8 +100,10 @@
 void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) override;
 void DeleteProgram(GLuint program) override;
 void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) override;
+void DeleteSamplers(GLsizei n, const GLuint* samplers) override;
 void DeleteShader(GLuint shader) override;
 void DeleteTextures(GLsizei n, const GLuint* textures) override;
+void DeleteTransformFeedbacks(GLsizei n, const GLuint* ids) override;
 void DepthFunc(GLenum func) override;
 void DepthMask(GLboolean flag) override;
 void DepthRangef(GLclampf zNear, GLclampf zFar) override;
@@ -134,7 +138,9 @@
 void GenerateMipmap(GLenum target) override;
 void GenFramebuffers(GLsizei n, GLuint* framebuffers) override;
 void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) override;
+void GenSamplers(GLsizei n, GLuint* samplers) override;
 void GenTextures(GLsizei n, GLuint* textures) override;
+void GenTransformFeedbacks(GLsizei n, GLuint* ids) override;
 void GetActiveAttrib(GLuint program,
                      GLuint index,
                      GLsizei bufsize,
@@ -176,6 +182,12 @@
 void GetRenderbufferParameteriv(GLenum target,
                                 GLenum pname,
                                 GLint* params) override;
+void GetSamplerParameterfv(GLuint sampler,
+                           GLenum pname,
+                           GLfloat* params) override;
+void GetSamplerParameteriv(GLuint sampler,
+                           GLenum pname,
+                           GLint* params) override;
 void GetShaderiv(GLuint shader, GLenum pname, GLint* params) override;
 void GetShaderInfoLog(GLuint shader,
                       GLsizei bufsize,
@@ -216,10 +228,13 @@
 GLboolean IsFramebuffer(GLuint framebuffer) override;
 GLboolean IsProgram(GLuint program) override;
 GLboolean IsRenderbuffer(GLuint renderbuffer) override;
+GLboolean IsSampler(GLuint sampler) override;
 GLboolean IsShader(GLuint shader) override;
 GLboolean IsTexture(GLuint texture) override;
+GLboolean IsTransformFeedback(GLuint transformfeedback) override;
 void LineWidth(GLfloat width) override;
 void LinkProgram(GLuint program) override;
+void PauseTransformFeedback() override;
 void PixelStorei(GLenum pname, GLint param) override;
 void PolygonOffset(GLfloat factor, GLfloat units) override;
 void ReadBuffer(GLenum src) override;
@@ -235,7 +250,16 @@
                          GLenum internalformat,
                          GLsizei width,
                          GLsizei height) override;
+void ResumeTransformFeedback() override;
 void SampleCoverage(GLclampf value, GLboolean invert) override;
+void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param) override;
+void SamplerParameterfv(GLuint sampler,
+                        GLenum pname,
+                        const GLfloat* params) override;
+void SamplerParameteri(GLuint sampler, GLenum pname, GLint param) override;
+void SamplerParameteriv(GLuint sampler,
+                        GLenum pname,
+                        const GLint* params) override;
 void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) override;
 void ShaderBinary(GLsizei n,
                   const GLuint* shaders,
@@ -427,7 +451,9 @@
 void DeleteQueriesEXT(GLsizei n, const GLuint* queries) override;
 GLboolean IsQueryEXT(GLuint id) override;
 void BeginQueryEXT(GLenum target, GLuint id) override;
+void BeginTransformFeedback(GLenum primitivemode) override;
 void EndQueryEXT(GLenum target) override;
+void EndTransformFeedback() override;
 void GetQueryivEXT(GLenum target, GLenum pname, GLint* params) override;
 void GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* params) override;
 void InsertEventMarkerEXT(GLsizei length, const GLchar* marker) 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 c9f8b93..567dace 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -46,11 +46,22 @@
   gl_->BindRenderbuffer(target, renderbuffer);
 }
 
+void GLES2TraceImplementation::BindSampler(GLuint unit, GLuint sampler) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindSampler");
+  gl_->BindSampler(unit, sampler);
+}
+
 void GLES2TraceImplementation::BindTexture(GLenum target, GLuint texture) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindTexture");
   gl_->BindTexture(target, texture);
 }
 
+void GLES2TraceImplementation::BindTransformFeedback(GLenum target,
+                                                     GLuint transformfeedback) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindTransformFeedback");
+  gl_->BindTransformFeedback(target, transformfeedback);
+}
+
 void GLES2TraceImplementation::BlendColor(GLclampf red,
                                           GLclampf green,
                                           GLclampf blue,
@@ -240,6 +251,12 @@
   gl_->DeleteRenderbuffers(n, renderbuffers);
 }
 
+void GLES2TraceImplementation::DeleteSamplers(GLsizei n,
+                                              const GLuint* samplers) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteSamplers");
+  gl_->DeleteSamplers(n, samplers);
+}
+
 void GLES2TraceImplementation::DeleteShader(GLuint shader) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteShader");
   gl_->DeleteShader(shader);
@@ -251,6 +268,12 @@
   gl_->DeleteTextures(n, textures);
 }
 
+void GLES2TraceImplementation::DeleteTransformFeedbacks(GLsizei n,
+                                                        const GLuint* ids) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteTransformFeedbacks");
+  gl_->DeleteTransformFeedbacks(n, ids);
+}
+
 void GLES2TraceImplementation::DepthFunc(GLenum func) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DepthFunc");
   gl_->DepthFunc(func);
@@ -371,11 +394,21 @@
   gl_->GenRenderbuffers(n, renderbuffers);
 }
 
+void GLES2TraceImplementation::GenSamplers(GLsizei n, GLuint* samplers) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenSamplers");
+  gl_->GenSamplers(n, samplers);
+}
+
 void GLES2TraceImplementation::GenTextures(GLsizei n, GLuint* textures) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenTextures");
   gl_->GenTextures(n, textures);
 }
 
+void GLES2TraceImplementation::GenTransformFeedbacks(GLsizei n, GLuint* ids) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenTransformFeedbacks");
+  gl_->GenTransformFeedbacks(n, ids);
+}
+
 void GLES2TraceImplementation::GetActiveAttrib(GLuint program,
                                                GLuint index,
                                                GLsizei bufsize,
@@ -481,6 +514,20 @@
   gl_->GetRenderbufferParameteriv(target, pname, params);
 }
 
+void GLES2TraceImplementation::GetSamplerParameterfv(GLuint sampler,
+                                                     GLenum pname,
+                                                     GLfloat* params) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetSamplerParameterfv");
+  gl_->GetSamplerParameterfv(sampler, pname, params);
+}
+
+void GLES2TraceImplementation::GetSamplerParameteriv(GLuint sampler,
+                                                     GLenum pname,
+                                                     GLint* params) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetSamplerParameteriv");
+  gl_->GetSamplerParameteriv(sampler, pname, params);
+}
+
 void GLES2TraceImplementation::GetShaderiv(GLuint shader,
                                            GLenum pname,
                                            GLint* params) {
@@ -623,6 +670,11 @@
   return gl_->IsRenderbuffer(renderbuffer);
 }
 
+GLboolean GLES2TraceImplementation::IsSampler(GLuint sampler) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsSampler");
+  return gl_->IsSampler(sampler);
+}
+
 GLboolean GLES2TraceImplementation::IsShader(GLuint shader) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsShader");
   return gl_->IsShader(shader);
@@ -633,6 +685,12 @@
   return gl_->IsTexture(texture);
 }
 
+GLboolean GLES2TraceImplementation::IsTransformFeedback(
+    GLuint transformfeedback) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsTransformFeedback");
+  return gl_->IsTransformFeedback(transformfeedback);
+}
+
 void GLES2TraceImplementation::LineWidth(GLfloat width) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::LineWidth");
   gl_->LineWidth(width);
@@ -643,6 +701,11 @@
   gl_->LinkProgram(program);
 }
 
+void GLES2TraceImplementation::PauseTransformFeedback() {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PauseTransformFeedback");
+  gl_->PauseTransformFeedback();
+}
+
 void GLES2TraceImplementation::PixelStorei(GLenum pname, GLint param) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PixelStorei");
   gl_->PixelStorei(pname, param);
@@ -682,12 +745,45 @@
   gl_->RenderbufferStorage(target, internalformat, width, height);
 }
 
+void GLES2TraceImplementation::ResumeTransformFeedback() {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ResumeTransformFeedback");
+  gl_->ResumeTransformFeedback();
+}
+
 void GLES2TraceImplementation::SampleCoverage(GLclampf value,
                                               GLboolean invert) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SampleCoverage");
   gl_->SampleCoverage(value, invert);
 }
 
+void GLES2TraceImplementation::SamplerParameterf(GLuint sampler,
+                                                 GLenum pname,
+                                                 GLfloat param) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SamplerParameterf");
+  gl_->SamplerParameterf(sampler, pname, param);
+}
+
+void GLES2TraceImplementation::SamplerParameterfv(GLuint sampler,
+                                                  GLenum pname,
+                                                  const GLfloat* params) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SamplerParameterfv");
+  gl_->SamplerParameterfv(sampler, pname, params);
+}
+
+void GLES2TraceImplementation::SamplerParameteri(GLuint sampler,
+                                                 GLenum pname,
+                                                 GLint param) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SamplerParameteri");
+  gl_->SamplerParameteri(sampler, pname, param);
+}
+
+void GLES2TraceImplementation::SamplerParameteriv(GLuint sampler,
+                                                  GLenum pname,
+                                                  const GLint* params) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SamplerParameteriv");
+  gl_->SamplerParameteriv(sampler, pname, params);
+}
+
 void GLES2TraceImplementation::Scissor(GLint x,
                                        GLint y,
                                        GLsizei width,
@@ -1268,11 +1364,21 @@
   gl_->BeginQueryEXT(target, id);
 }
 
+void GLES2TraceImplementation::BeginTransformFeedback(GLenum primitivemode) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BeginTransformFeedback");
+  gl_->BeginTransformFeedback(primitivemode);
+}
+
 void GLES2TraceImplementation::EndQueryEXT(GLenum target) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::EndQueryEXT");
   gl_->EndQueryEXT(target);
 }
 
+void GLES2TraceImplementation::EndTransformFeedback() {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::EndTransformFeedback");
+  gl_->EndTransformFeedback();
+}
+
 void GLES2TraceImplementation::GetQueryivEXT(GLenum target,
                                              GLenum pname,
                                              GLint* params) {
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index f0b1627..d046748e 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -10,7 +10,9 @@
 GL_APICALL void         GL_APIENTRY glBindBuffer (GLenumBufferTarget target, GLidBindBuffer buffer);
 GL_APICALL void         GL_APIENTRY glBindFramebuffer (GLenumFrameBufferTarget target, GLidBindFramebuffer framebuffer);
 GL_APICALL void         GL_APIENTRY glBindRenderbuffer (GLenumRenderBufferTarget target, GLidBindRenderbuffer renderbuffer);
+GL_APICALL void         GL_APIENTRY glBindSampler (GLuint unit, GLidBindSampler sampler);
 GL_APICALL void         GL_APIENTRY glBindTexture (GLenumTextureBindTarget target, GLidBindTexture texture);
+GL_APICALL void         GL_APIENTRY glBindTransformFeedback (GLenumTransformFeedbackBindTarget target, GLidBindTransformFeedback transformfeedback);
 GL_APICALL void         GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
 GL_APICALL void         GL_APIENTRY glBlendEquation ( GLenumEquation mode );
 GL_APICALL void         GL_APIENTRY glBlendEquationSeparate (GLenumEquation modeRGB, GLenumEquation modeAlpha);
@@ -37,8 +39,10 @@
 GL_APICALL void         GL_APIENTRY glDeleteFramebuffers (GLsizeiNotNegative n, const GLuint* framebuffers);
 GL_APICALL void         GL_APIENTRY glDeleteProgram (GLidProgram program);
 GL_APICALL void         GL_APIENTRY glDeleteRenderbuffers (GLsizeiNotNegative n, const GLuint* renderbuffers);
+GL_APICALL void         GL_APIENTRY glDeleteSamplers (GLsizeiNotNegative n, const GLuint* samplers);
 GL_APICALL void         GL_APIENTRY glDeleteShader (GLidShader shader);
 GL_APICALL void         GL_APIENTRY glDeleteTextures (GLsizeiNotNegative n, const GLuint* textures);
+GL_APICALL void         GL_APIENTRY glDeleteTransformFeedbacks (GLsizeiNotNegative n, const GLuint* ids);
 GL_APICALL void         GL_APIENTRY glDepthFunc (GLenumCmpFunction func);
 GL_APICALL void         GL_APIENTRY glDepthMask (GLboolean flag);
 GL_APICALL void         GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
@@ -59,7 +63,9 @@
 GL_APICALL void         GL_APIENTRY glGenerateMipmap (GLenumTextureBindTarget target);
 GL_APICALL void         GL_APIENTRY glGenFramebuffers (GLsizeiNotNegative n, GLuint* framebuffers);
 GL_APICALL void         GL_APIENTRY glGenRenderbuffers (GLsizeiNotNegative n, GLuint* renderbuffers);
+GL_APICALL void         GL_APIENTRY glGenSamplers (GLsizeiNotNegative n, GLuint* samplers);
 GL_APICALL void         GL_APIENTRY glGenTextures (GLsizeiNotNegative n, GLuint* textures);
+GL_APICALL void         GL_APIENTRY glGenTransformFeedbacks (GLsizeiNotNegative n, GLuint* ids);
 GL_APICALL void         GL_APIENTRY glGetActiveAttrib (GLidProgram program, GLuint index, GLsizeiNotNegative bufsize, GLsizeiOptional* length, GLint* size, GLenum* type, char* name);
 GL_APICALL void         GL_APIENTRY glGetActiveUniform (GLidProgram program, GLuint index, GLsizeiNotNegative bufsize, GLsizeiOptional* length, GLint* size, GLenum* type, char* name);
 GL_APICALL void         GL_APIENTRY glGetAttachedShaders (GLidProgram program, GLsizeiNotNegative maxcount, GLsizeiOptional* count, GLuint* shaders);
@@ -74,6 +80,8 @@
 GL_APICALL void         GL_APIENTRY glGetProgramiv (GLidProgram program, GLenumProgramParameter pname, GLint* params);
 GL_APICALL void         GL_APIENTRY glGetProgramInfoLog (GLidProgram program, GLsizeiNotNegative bufsize, GLsizeiOptional* length, char* infolog);
 GL_APICALL void         GL_APIENTRY glGetRenderbufferParameteriv (GLenumRenderBufferTarget target, GLenumRenderBufferParameter pname, GLint* params);
+GL_APICALL void         GL_APIENTRY glGetSamplerParameterfv (GLidSampler sampler, GLenumSamplerParameter pname, GLfloat* params);
+GL_APICALL void         GL_APIENTRY glGetSamplerParameteriv (GLidSampler sampler, GLenumSamplerParameter pname, GLint* params);
 GL_APICALL void         GL_APIENTRY glGetShaderiv (GLidShader shader, GLenumShaderParameter pname, GLint* params);
 GL_APICALL void         GL_APIENTRY glGetShaderInfoLog (GLidShader shader, GLsizeiNotNegative bufsize, GLsizeiOptional* length, char* infolog);
 GL_APICALL void         GL_APIENTRY glGetShaderPrecisionFormat (GLenumShaderType shadertype, GLenumShaderPrecision precisiontype, GLint* range, GLint* precision);
@@ -95,17 +103,25 @@
 GL_APICALL GLboolean    GL_APIENTRY glIsFramebuffer (GLidFramebuffer framebuffer);
 GL_APICALL GLboolean    GL_APIENTRY glIsProgram (GLidProgram program);
 GL_APICALL GLboolean    GL_APIENTRY glIsRenderbuffer (GLidRenderbuffer renderbuffer);
+GL_APICALL GLboolean    GL_APIENTRY glIsSampler (GLidSampler sampler);
 GL_APICALL GLboolean    GL_APIENTRY glIsShader (GLidShader shader);
 GL_APICALL GLboolean    GL_APIENTRY glIsTexture (GLidTexture texture);
+GL_APICALL GLboolean    GL_APIENTRY glIsTransformFeedback (GLidTransformFeedback transformfeedback);
 GL_APICALL void         GL_APIENTRY glLineWidth (GLfloat width);
 GL_APICALL void         GL_APIENTRY glLinkProgram (GLidProgram program);
+GL_APICALL void         GL_APIENTRY glPauseTransformFeedback (void);
 GL_APICALL void         GL_APIENTRY glPixelStorei (GLenumPixelStore pname, GLintPixelStoreAlignment param);
 GL_APICALL void         GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
 GL_APICALL void         GL_APIENTRY glReadBuffer (GLenum src);
 GL_APICALL void         GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenumReadPixelFormat format, GLenumPixelType type, void* pixels);
 GL_APICALL void         GL_APIENTRY glReleaseShaderCompiler (void);
 GL_APICALL void         GL_APIENTRY glRenderbufferStorage (GLenumRenderBufferTarget target, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
+GL_APICALL void         GL_APIENTRY glResumeTransformFeedback (void);
 GL_APICALL void         GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void         GL_APIENTRY glSamplerParameterf (GLidBindSampler sampler, GLenumSamplerParameter pname, GLfloat param);
+GL_APICALL void         GL_APIENTRY glSamplerParameterfv (GLidBindSampler sampler, GLenumSamplerParameter pname, const GLfloat* params);
+GL_APICALL void         GL_APIENTRY glSamplerParameteri (GLidBindSampler sampler, GLenumSamplerParameter pname, GLint param);
+GL_APICALL void         GL_APIENTRY glSamplerParameteriv (GLidBindSampler sampler, GLenumSamplerParameter pname, const GLint* params);
 GL_APICALL void         GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
 GL_APICALL void         GL_APIENTRY glShaderBinary (GLsizeiNotNegative n, const GLuint* shaders, GLenumShaderBinaryFormat binaryformat, const void* binary, GLsizeiNotNegative length);
 GL_APICALL void         GL_APIENTRY glShaderSource (GLidShader shader, GLsizeiNotNegative count, const GLchar* const* str, const GLint* length);
@@ -183,7 +199,9 @@
 GL_APICALL void         GL_APIENTRY glDeleteQueriesEXT (GLsizeiNotNegative n, const GLuint* queries);
 GL_APICALL GLboolean    GL_APIENTRY glIsQueryEXT (GLidQuery id);
 GL_APICALL void         GL_APIENTRY glBeginQueryEXT (GLenumQueryTarget target, GLidQuery id);
+GL_APICALL void         GL_APIENTRY glBeginTransformFeedback (GLenumTransformFeedbackPrimitiveMode primitivemode);
 GL_APICALL void         GL_APIENTRY glEndQueryEXT (GLenumQueryTarget target);
+GL_APICALL void         GL_APIENTRY glEndTransformFeedback (void);
 GL_APICALL void         GL_APIENTRY glGetQueryivEXT (GLenumQueryTarget target, GLenumQueryParameter pname, GLint* params);
 GL_APICALL void         GL_APIENTRY glGetQueryObjectuivEXT (GLidQuery id, GLenumQueryObjectParameter pname, GLuint* params);
 GL_APICALL void         GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar* marker);
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index c0bc663..8b22bc6 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -60,6 +60,8 @@
   kQueries,
   kVertexArrays,
   kValuebuffers,
+  kSamplers,
+  kTransformFeedbacks,
   kNumIdNamespaces
 };
 
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index bdee4e6..c94feaa 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -232,6 +232,42 @@
 COMPILE_ASSERT(offsetof(BindRenderbuffer, renderbuffer) == 8,
                OffsetOf_BindRenderbuffer_renderbuffer_not_8);
 
+struct BindSampler {
+  typedef BindSampler ValueType;
+  static const CommandId kCmdId = kBindSampler;
+  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(GLuint _unit, GLuint _sampler) {
+    SetHeader();
+    unit = _unit;
+    sampler = _sampler;
+  }
+
+  void* Set(void* cmd, GLuint _unit, GLuint _sampler) {
+    static_cast<ValueType*>(cmd)->Init(_unit, _sampler);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t unit;
+  uint32_t sampler;
+};
+
+COMPILE_ASSERT(sizeof(BindSampler) == 12, Sizeof_BindSampler_is_not_12);
+COMPILE_ASSERT(offsetof(BindSampler, header) == 0,
+               OffsetOf_BindSampler_header_not_0);
+COMPILE_ASSERT(offsetof(BindSampler, unit) == 4,
+               OffsetOf_BindSampler_unit_not_4);
+COMPILE_ASSERT(offsetof(BindSampler, sampler) == 8,
+               OffsetOf_BindSampler_sampler_not_8);
+
 struct BindTexture {
   typedef BindTexture ValueType;
   static const CommandId kCmdId = kBindTexture;
@@ -268,6 +304,43 @@
 COMPILE_ASSERT(offsetof(BindTexture, texture) == 8,
                OffsetOf_BindTexture_texture_not_8);
 
+struct BindTransformFeedback {
+  typedef BindTransformFeedback ValueType;
+  static const CommandId kCmdId = kBindTransformFeedback;
+  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 _transformfeedback) {
+    SetHeader();
+    target = _target;
+    transformfeedback = _transformfeedback;
+  }
+
+  void* Set(void* cmd, GLenum _target, GLuint _transformfeedback) {
+    static_cast<ValueType*>(cmd)->Init(_target, _transformfeedback);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t target;
+  uint32_t transformfeedback;
+};
+
+COMPILE_ASSERT(sizeof(BindTransformFeedback) == 12,
+               Sizeof_BindTransformFeedback_is_not_12);
+COMPILE_ASSERT(offsetof(BindTransformFeedback, header) == 0,
+               OffsetOf_BindTransformFeedback_header_not_0);
+COMPILE_ASSERT(offsetof(BindTransformFeedback, target) == 4,
+               OffsetOf_BindTransformFeedback_target_not_4);
+COMPILE_ASSERT(offsetof(BindTransformFeedback, transformfeedback) == 8,
+               OffsetOf_BindTransformFeedback_transformfeedback_not_8);
+
 struct BlendColor {
   typedef BlendColor ValueType;
   static const CommandId kCmdId = kBlendColor;
@@ -1631,6 +1704,48 @@
 COMPILE_ASSERT(offsetof(DeleteRenderbuffersImmediate, n) == 4,
                OffsetOf_DeleteRenderbuffersImmediate_n_not_4);
 
+struct DeleteSamplersImmediate {
+  typedef DeleteSamplersImmediate ValueType;
+  static const CommandId kCmdId = kDeleteSamplersImmediate;
+  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* _samplers) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _samplers, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, const GLuint* _samplers) {
+    static_cast<ValueType*>(cmd)->Init(_n, _samplers);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteSamplersImmediate) == 8,
+               Sizeof_DeleteSamplersImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteSamplersImmediate, header) == 0,
+               OffsetOf_DeleteSamplersImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteSamplersImmediate, n) == 4,
+               OffsetOf_DeleteSamplersImmediate_n_not_4);
+
 struct DeleteShader {
   typedef DeleteShader ValueType;
   static const CommandId kCmdId = kDeleteShader;
@@ -1705,6 +1820,48 @@
 COMPILE_ASSERT(offsetof(DeleteTexturesImmediate, n) == 4,
                OffsetOf_DeleteTexturesImmediate_n_not_4);
 
+struct DeleteTransformFeedbacksImmediate {
+  typedef DeleteTransformFeedbacksImmediate ValueType;
+  static const CommandId kCmdId = kDeleteTransformFeedbacksImmediate;
+  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* _ids) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _ids, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, const GLuint* _ids) {
+    static_cast<ValueType*>(cmd)->Init(_n, _ids);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteTransformFeedbacksImmediate) == 8,
+               Sizeof_DeleteTransformFeedbacksImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteTransformFeedbacksImmediate, header) == 0,
+               OffsetOf_DeleteTransformFeedbacksImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteTransformFeedbacksImmediate, n) == 4,
+               OffsetOf_DeleteTransformFeedbacksImmediate_n_not_4);
+
 struct DepthFunc {
   typedef DepthFunc ValueType;
   static const CommandId kCmdId = kDepthFunc;
@@ -2457,6 +2614,48 @@
 COMPILE_ASSERT(offsetof(GenRenderbuffersImmediate, n) == 4,
                OffsetOf_GenRenderbuffersImmediate_n_not_4);
 
+struct GenSamplersImmediate {
+  typedef GenSamplersImmediate ValueType;
+  static const CommandId kCmdId = kGenSamplersImmediate;
+  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* _samplers) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _samplers, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, GLuint* _samplers) {
+    static_cast<ValueType*>(cmd)->Init(_n, _samplers);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+COMPILE_ASSERT(sizeof(GenSamplersImmediate) == 8,
+               Sizeof_GenSamplersImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenSamplersImmediate, header) == 0,
+               OffsetOf_GenSamplersImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenSamplersImmediate, n) == 4,
+               OffsetOf_GenSamplersImmediate_n_not_4);
+
 struct GenTexturesImmediate {
   typedef GenTexturesImmediate ValueType;
   static const CommandId kCmdId = kGenTexturesImmediate;
@@ -2499,6 +2698,48 @@
 COMPILE_ASSERT(offsetof(GenTexturesImmediate, n) == 4,
                OffsetOf_GenTexturesImmediate_n_not_4);
 
+struct GenTransformFeedbacksImmediate {
+  typedef GenTransformFeedbacksImmediate ValueType;
+  static const CommandId kCmdId = kGenTransformFeedbacksImmediate;
+  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* _ids) {
+    SetHeader(_n);
+    n = _n;
+    memcpy(ImmediateDataAddress(this), _ids, ComputeDataSize(_n));
+  }
+
+  void* Set(void* cmd, GLsizei _n, GLuint* _ids) {
+    static_cast<ValueType*>(cmd)->Init(_n, _ids);
+    const uint32_t size = ComputeSize(_n);
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  int32_t n;
+};
+
+COMPILE_ASSERT(sizeof(GenTransformFeedbacksImmediate) == 8,
+               Sizeof_GenTransformFeedbacksImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenTransformFeedbacksImmediate, header) == 0,
+               OffsetOf_GenTransformFeedbacksImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenTransformFeedbacksImmediate, n) == 4,
+               OffsetOf_GenTransformFeedbacksImmediate_n_not_4);
+
 struct GetActiveAttrib {
   typedef GetActiveAttrib ValueType;
   static const CommandId kCmdId = kGetActiveAttrib;
@@ -3261,6 +3502,116 @@
 COMPILE_ASSERT(offsetof(GetRenderbufferParameteriv, params_shm_offset) == 16,
                OffsetOf_GetRenderbufferParameteriv_params_shm_offset_not_16);
 
+struct GetSamplerParameterfv {
+  typedef GetSamplerParameterfv ValueType;
+  static const CommandId kCmdId = kGetSamplerParameterfv;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  typedef SizedResult<GLfloat> Result;
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _sampler,
+            GLenum _pname,
+            uint32_t _params_shm_id,
+            uint32_t _params_shm_offset) {
+    SetHeader();
+    sampler = _sampler;
+    pname = _pname;
+    params_shm_id = _params_shm_id;
+    params_shm_offset = _params_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _sampler,
+            GLenum _pname,
+            uint32_t _params_shm_id,
+            uint32_t _params_shm_offset) {
+    static_cast<ValueType*>(cmd)
+        ->Init(_sampler, _pname, _params_shm_id, _params_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t sampler;
+  uint32_t pname;
+  uint32_t params_shm_id;
+  uint32_t params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetSamplerParameterfv) == 20,
+               Sizeof_GetSamplerParameterfv_is_not_20);
+COMPILE_ASSERT(offsetof(GetSamplerParameterfv, header) == 0,
+               OffsetOf_GetSamplerParameterfv_header_not_0);
+COMPILE_ASSERT(offsetof(GetSamplerParameterfv, sampler) == 4,
+               OffsetOf_GetSamplerParameterfv_sampler_not_4);
+COMPILE_ASSERT(offsetof(GetSamplerParameterfv, pname) == 8,
+               OffsetOf_GetSamplerParameterfv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetSamplerParameterfv, params_shm_id) == 12,
+               OffsetOf_GetSamplerParameterfv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetSamplerParameterfv, params_shm_offset) == 16,
+               OffsetOf_GetSamplerParameterfv_params_shm_offset_not_16);
+
+struct GetSamplerParameteriv {
+  typedef GetSamplerParameteriv ValueType;
+  static const CommandId kCmdId = kGetSamplerParameteriv;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  typedef SizedResult<GLint> Result;
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLuint _sampler,
+            GLenum _pname,
+            uint32_t _params_shm_id,
+            uint32_t _params_shm_offset) {
+    SetHeader();
+    sampler = _sampler;
+    pname = _pname;
+    params_shm_id = _params_shm_id;
+    params_shm_offset = _params_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _sampler,
+            GLenum _pname,
+            uint32_t _params_shm_id,
+            uint32_t _params_shm_offset) {
+    static_cast<ValueType*>(cmd)
+        ->Init(_sampler, _pname, _params_shm_id, _params_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t sampler;
+  uint32_t pname;
+  uint32_t params_shm_id;
+  uint32_t params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetSamplerParameteriv) == 20,
+               Sizeof_GetSamplerParameteriv_is_not_20);
+COMPILE_ASSERT(offsetof(GetSamplerParameteriv, header) == 0,
+               OffsetOf_GetSamplerParameteriv_header_not_0);
+COMPILE_ASSERT(offsetof(GetSamplerParameteriv, sampler) == 4,
+               OffsetOf_GetSamplerParameteriv_sampler_not_4);
+COMPILE_ASSERT(offsetof(GetSamplerParameteriv, pname) == 8,
+               OffsetOf_GetSamplerParameteriv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetSamplerParameteriv, params_shm_id) == 12,
+               OffsetOf_GetSamplerParameteriv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetSamplerParameteriv, params_shm_offset) == 16,
+               OffsetOf_GetSamplerParameteriv_params_shm_offset_not_16);
+
 struct GetShaderiv {
   typedef GetShaderiv ValueType;
   static const CommandId kCmdId = kGetShaderiv;
@@ -4322,6 +4673,54 @@
 COMPILE_ASSERT(offsetof(IsRenderbuffer, result_shm_offset) == 12,
                OffsetOf_IsRenderbuffer_result_shm_offset_not_12);
 
+struct IsSampler {
+  typedef IsSampler ValueType;
+  static const CommandId kCmdId = kIsSampler;
+  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 _sampler,
+            uint32_t _result_shm_id,
+            uint32_t _result_shm_offset) {
+    SetHeader();
+    sampler = _sampler;
+    result_shm_id = _result_shm_id;
+    result_shm_offset = _result_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _sampler,
+            uint32_t _result_shm_id,
+            uint32_t _result_shm_offset) {
+    static_cast<ValueType*>(cmd)
+        ->Init(_sampler, _result_shm_id, _result_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t sampler;
+  uint32_t result_shm_id;
+  uint32_t result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsSampler) == 16, Sizeof_IsSampler_is_not_16);
+COMPILE_ASSERT(offsetof(IsSampler, header) == 0,
+               OffsetOf_IsSampler_header_not_0);
+COMPILE_ASSERT(offsetof(IsSampler, sampler) == 4,
+               OffsetOf_IsSampler_sampler_not_4);
+COMPILE_ASSERT(offsetof(IsSampler, result_shm_id) == 8,
+               OffsetOf_IsSampler_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsSampler, result_shm_offset) == 12,
+               OffsetOf_IsSampler_result_shm_offset_not_12);
+
 struct IsShader {
   typedef IsShader ValueType;
   static const CommandId kCmdId = kIsShader;
@@ -4416,6 +4815,55 @@
 COMPILE_ASSERT(offsetof(IsTexture, result_shm_offset) == 12,
                OffsetOf_IsTexture_result_shm_offset_not_12);
 
+struct IsTransformFeedback {
+  typedef IsTransformFeedback ValueType;
+  static const CommandId kCmdId = kIsTransformFeedback;
+  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 _transformfeedback,
+            uint32_t _result_shm_id,
+            uint32_t _result_shm_offset) {
+    SetHeader();
+    transformfeedback = _transformfeedback;
+    result_shm_id = _result_shm_id;
+    result_shm_offset = _result_shm_offset;
+  }
+
+  void* Set(void* cmd,
+            GLuint _transformfeedback,
+            uint32_t _result_shm_id,
+            uint32_t _result_shm_offset) {
+    static_cast<ValueType*>(cmd)
+        ->Init(_transformfeedback, _result_shm_id, _result_shm_offset);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t transformfeedback;
+  uint32_t result_shm_id;
+  uint32_t result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsTransformFeedback) == 16,
+               Sizeof_IsTransformFeedback_is_not_16);
+COMPILE_ASSERT(offsetof(IsTransformFeedback, header) == 0,
+               OffsetOf_IsTransformFeedback_header_not_0);
+COMPILE_ASSERT(offsetof(IsTransformFeedback, transformfeedback) == 4,
+               OffsetOf_IsTransformFeedback_transformfeedback_not_4);
+COMPILE_ASSERT(offsetof(IsTransformFeedback, result_shm_id) == 8,
+               OffsetOf_IsTransformFeedback_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsTransformFeedback, result_shm_offset) == 12,
+               OffsetOf_IsTransformFeedback_result_shm_offset_not_12);
+
 struct LineWidth {
   typedef LineWidth ValueType;
   static const CommandId kCmdId = kLineWidth;
@@ -4479,6 +4927,33 @@
 COMPILE_ASSERT(offsetof(LinkProgram, program) == 4,
                OffsetOf_LinkProgram_program_not_4);
 
+struct PauseTransformFeedback {
+  typedef PauseTransformFeedback ValueType;
+  static const CommandId kCmdId = kPauseTransformFeedback;
+  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() { SetHeader(); }
+
+  void* Set(void* cmd) {
+    static_cast<ValueType*>(cmd)->Init();
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(PauseTransformFeedback) == 4,
+               Sizeof_PauseTransformFeedback_is_not_4);
+COMPILE_ASSERT(offsetof(PauseTransformFeedback, header) == 0,
+               OffsetOf_PauseTransformFeedback_header_not_0);
+
 struct PixelStorei {
   typedef PixelStorei ValueType;
   static const CommandId kCmdId = kPixelStorei;
@@ -4760,6 +5235,33 @@
 COMPILE_ASSERT(offsetof(RenderbufferStorage, height) == 16,
                OffsetOf_RenderbufferStorage_height_not_16);
 
+struct ResumeTransformFeedback {
+  typedef ResumeTransformFeedback ValueType;
+  static const CommandId kCmdId = kResumeTransformFeedback;
+  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() { SetHeader(); }
+
+  void* Set(void* cmd) {
+    static_cast<ValueType*>(cmd)->Init();
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(ResumeTransformFeedback) == 4,
+               Sizeof_ResumeTransformFeedback_is_not_4);
+COMPILE_ASSERT(offsetof(ResumeTransformFeedback, header) == 0,
+               OffsetOf_ResumeTransformFeedback_header_not_0);
+
 struct SampleCoverage {
   typedef SampleCoverage ValueType;
   static const CommandId kCmdId = kSampleCoverage;
@@ -4796,6 +5298,176 @@
 COMPILE_ASSERT(offsetof(SampleCoverage, invert) == 8,
                OffsetOf_SampleCoverage_invert_not_8);
 
+struct SamplerParameterf {
+  typedef SamplerParameterf ValueType;
+  static const CommandId kCmdId = kSamplerParameterf;
+  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(GLuint _sampler, GLenum _pname, GLfloat _param) {
+    SetHeader();
+    sampler = _sampler;
+    pname = _pname;
+    param = _param;
+  }
+
+  void* Set(void* cmd, GLuint _sampler, GLenum _pname, GLfloat _param) {
+    static_cast<ValueType*>(cmd)->Init(_sampler, _pname, _param);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t sampler;
+  uint32_t pname;
+  float param;
+};
+
+COMPILE_ASSERT(sizeof(SamplerParameterf) == 16,
+               Sizeof_SamplerParameterf_is_not_16);
+COMPILE_ASSERT(offsetof(SamplerParameterf, header) == 0,
+               OffsetOf_SamplerParameterf_header_not_0);
+COMPILE_ASSERT(offsetof(SamplerParameterf, sampler) == 4,
+               OffsetOf_SamplerParameterf_sampler_not_4);
+COMPILE_ASSERT(offsetof(SamplerParameterf, pname) == 8,
+               OffsetOf_SamplerParameterf_pname_not_8);
+COMPILE_ASSERT(offsetof(SamplerParameterf, param) == 12,
+               OffsetOf_SamplerParameterf_param_not_12);
+
+struct SamplerParameterfvImmediate {
+  typedef SamplerParameterfvImmediate ValueType;
+  static const CommandId kCmdId = kSamplerParameterfvImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize() {
+    return static_cast<uint32_t>(sizeof(GLfloat) * 1);  // NOLINT
+  }
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize());  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmdByTotalSize<ValueType>(ComputeSize()); }
+
+  void Init(GLuint _sampler, GLenum _pname, const GLfloat* _params) {
+    SetHeader();
+    sampler = _sampler;
+    pname = _pname;
+    memcpy(ImmediateDataAddress(this), _params, ComputeDataSize());
+  }
+
+  void* Set(void* cmd, GLuint _sampler, GLenum _pname, const GLfloat* _params) {
+    static_cast<ValueType*>(cmd)->Init(_sampler, _pname, _params);
+    const uint32_t size = ComputeSize();
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t sampler;
+  uint32_t pname;
+};
+
+COMPILE_ASSERT(sizeof(SamplerParameterfvImmediate) == 12,
+               Sizeof_SamplerParameterfvImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(SamplerParameterfvImmediate, header) == 0,
+               OffsetOf_SamplerParameterfvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(SamplerParameterfvImmediate, sampler) == 4,
+               OffsetOf_SamplerParameterfvImmediate_sampler_not_4);
+COMPILE_ASSERT(offsetof(SamplerParameterfvImmediate, pname) == 8,
+               OffsetOf_SamplerParameterfvImmediate_pname_not_8);
+
+struct SamplerParameteri {
+  typedef SamplerParameteri ValueType;
+  static const CommandId kCmdId = kSamplerParameteri;
+  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(GLuint _sampler, GLenum _pname, GLint _param) {
+    SetHeader();
+    sampler = _sampler;
+    pname = _pname;
+    param = _param;
+  }
+
+  void* Set(void* cmd, GLuint _sampler, GLenum _pname, GLint _param) {
+    static_cast<ValueType*>(cmd)->Init(_sampler, _pname, _param);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t sampler;
+  uint32_t pname;
+  int32_t param;
+};
+
+COMPILE_ASSERT(sizeof(SamplerParameteri) == 16,
+               Sizeof_SamplerParameteri_is_not_16);
+COMPILE_ASSERT(offsetof(SamplerParameteri, header) == 0,
+               OffsetOf_SamplerParameteri_header_not_0);
+COMPILE_ASSERT(offsetof(SamplerParameteri, sampler) == 4,
+               OffsetOf_SamplerParameteri_sampler_not_4);
+COMPILE_ASSERT(offsetof(SamplerParameteri, pname) == 8,
+               OffsetOf_SamplerParameteri_pname_not_8);
+COMPILE_ASSERT(offsetof(SamplerParameteri, param) == 12,
+               OffsetOf_SamplerParameteri_param_not_12);
+
+struct SamplerParameterivImmediate {
+  typedef SamplerParameterivImmediate ValueType;
+  static const CommandId kCmdId = kSamplerParameterivImmediate;
+  static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+  static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeDataSize() {
+    return static_cast<uint32_t>(sizeof(GLint) * 1);  // NOLINT
+  }
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType) +
+                                 ComputeDataSize());  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmdByTotalSize<ValueType>(ComputeSize()); }
+
+  void Init(GLuint _sampler, GLenum _pname, const GLint* _params) {
+    SetHeader();
+    sampler = _sampler;
+    pname = _pname;
+    memcpy(ImmediateDataAddress(this), _params, ComputeDataSize());
+  }
+
+  void* Set(void* cmd, GLuint _sampler, GLenum _pname, const GLint* _params) {
+    static_cast<ValueType*>(cmd)->Init(_sampler, _pname, _params);
+    const uint32_t size = ComputeSize();
+    return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t sampler;
+  uint32_t pname;
+};
+
+COMPILE_ASSERT(sizeof(SamplerParameterivImmediate) == 12,
+               Sizeof_SamplerParameterivImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(SamplerParameterivImmediate, header) == 0,
+               OffsetOf_SamplerParameterivImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(SamplerParameterivImmediate, sampler) == 4,
+               OffsetOf_SamplerParameterivImmediate_sampler_not_4);
+COMPILE_ASSERT(offsetof(SamplerParameterivImmediate, pname) == 8,
+               OffsetOf_SamplerParameterivImmediate_pname_not_8);
+
 struct Scissor {
   typedef Scissor ValueType;
   static const CommandId kCmdId = kScissor;
@@ -8264,6 +8936,39 @@
 COMPILE_ASSERT(offsetof(BeginQueryEXT, sync_data_shm_offset) == 16,
                OffsetOf_BeginQueryEXT_sync_data_shm_offset_not_16);
 
+struct BeginTransformFeedback {
+  typedef BeginTransformFeedback ValueType;
+  static const CommandId kCmdId = kBeginTransformFeedback;
+  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 _primitivemode) {
+    SetHeader();
+    primitivemode = _primitivemode;
+  }
+
+  void* Set(void* cmd, GLenum _primitivemode) {
+    static_cast<ValueType*>(cmd)->Init(_primitivemode);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t primitivemode;
+};
+
+COMPILE_ASSERT(sizeof(BeginTransformFeedback) == 8,
+               Sizeof_BeginTransformFeedback_is_not_8);
+COMPILE_ASSERT(offsetof(BeginTransformFeedback, header) == 0,
+               OffsetOf_BeginTransformFeedback_header_not_0);
+COMPILE_ASSERT(offsetof(BeginTransformFeedback, primitivemode) == 4,
+               OffsetOf_BeginTransformFeedback_primitivemode_not_4);
+
 struct EndQueryEXT {
   typedef EndQueryEXT ValueType;
   static const CommandId kCmdId = kEndQueryEXT;
@@ -8300,6 +9005,33 @@
 COMPILE_ASSERT(offsetof(EndQueryEXT, submit_count) == 8,
                OffsetOf_EndQueryEXT_submit_count_not_8);
 
+struct EndTransformFeedback {
+  typedef EndTransformFeedback ValueType;
+  static const CommandId kCmdId = kEndTransformFeedback;
+  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() { SetHeader(); }
+
+  void* Set(void* cmd) {
+    static_cast<ValueType*>(cmd)->Init();
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(EndTransformFeedback) == 4,
+               Sizeof_EndTransformFeedback_is_not_4);
+COMPILE_ASSERT(offsetof(EndTransformFeedback, header) == 0,
+               OffsetOf_EndTransformFeedback_header_not_0);
+
 struct InsertEventMarkerEXT {
   typedef InsertEventMarkerEXT ValueType;
   static const CommandId kCmdId = kInsertEventMarkerEXT;
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 49c108c..ca81047 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -86,6 +86,18 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, BindSampler) {
+  cmds::BindSampler& cmd = *GetBufferAs<cmds::BindSampler>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BindSampler::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.unit);
+  EXPECT_EQ(static_cast<GLuint>(12), cmd.sampler);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, BindTexture) {
   cmds::BindTexture& cmd = *GetBufferAs<cmds::BindTexture>();
   void* next_cmd =
@@ -98,6 +110,19 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, BindTransformFeedback) {
+  cmds::BindTransformFeedback& cmd =
+      *GetBufferAs<cmds::BindTransformFeedback>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLuint>(12));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BindTransformFeedback::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.transformfeedback);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, BlendColor) {
   cmds::BlendColor& cmd = *GetBufferAs<cmds::BlendColor>();
   void* next_cmd =
@@ -518,6 +543,24 @@
   // TODO(gman): Check that ids were inserted;
 }
 
+TEST_F(GLES2FormatTest, DeleteSamplersImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::DeleteSamplersImmediate& cmd =
+      *GetBufferAs<cmds::DeleteSamplersImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::DeleteSamplersImmediate::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, DeleteShader) {
   cmds::DeleteShader& cmd = *GetBufferAs<cmds::DeleteShader>();
   void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11));
@@ -546,6 +589,25 @@
   // TODO(gman): Check that ids were inserted;
 }
 
+TEST_F(GLES2FormatTest, DeleteTransformFeedbacksImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::DeleteTransformFeedbacksImmediate& cmd =
+      *GetBufferAs<cmds::DeleteTransformFeedbacksImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(
+      static_cast<uint32_t>(cmds::DeleteTransformFeedbacksImmediate::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, DepthFunc) {
   cmds::DepthFunc& cmd = *GetBufferAs<cmds::DepthFunc>();
   void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11));
@@ -792,6 +854,23 @@
   // TODO(gman): Check that ids were inserted;
 }
 
+TEST_F(GLES2FormatTest, GenSamplersImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::GenSamplersImmediate& cmd = *GetBufferAs<cmds::GenSamplersImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GenSamplersImmediate::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, GenTexturesImmediate) {
   static GLuint ids[] = {
       12, 23, 34,
@@ -809,6 +888,24 @@
   // TODO(gman): Check that ids were inserted;
 }
 
+TEST_F(GLES2FormatTest, GenTransformFeedbacksImmediate) {
+  static GLuint ids[] = {
+      12, 23, 34,
+  };
+  cmds::GenTransformFeedbacksImmediate& cmd =
+      *GetBufferAs<cmds::GenTransformFeedbacksImmediate>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GenTransformFeedbacksImmediate::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, GetActiveAttrib) {
   cmds::GetActiveAttrib& cmd = *GetBufferAs<cmds::GetActiveAttrib>();
   void* next_cmd =
@@ -1020,6 +1117,38 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, GetSamplerParameterfv) {
+  cmds::GetSamplerParameterfv& cmd =
+      *GetBufferAs<cmds::GetSamplerParameterfv>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLenum>(12),
+              static_cast<uint32_t>(13), static_cast<uint32_t>(14));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GetSamplerParameterfv::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.sampler);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.params_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(14), cmd.params_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetSamplerParameteriv) {
+  cmds::GetSamplerParameteriv& cmd =
+      *GetBufferAs<cmds::GetSamplerParameteriv>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLenum>(12),
+              static_cast<uint32_t>(13), static_cast<uint32_t>(14));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::GetSamplerParameteriv::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.sampler);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+  EXPECT_EQ(static_cast<uint32_t>(13), cmd.params_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(14), cmd.params_shm_offset);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, GetShaderiv) {
   cmds::GetShaderiv& cmd = *GetBufferAs<cmds::GetShaderiv>();
   void* next_cmd =
@@ -1338,6 +1467,19 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, IsSampler) {
+  cmds::IsSampler& cmd = *GetBufferAs<cmds::IsSampler>();
+  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::IsSampler::kCmdId), cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.sampler);
+  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, IsShader) {
   cmds::IsShader& cmd = *GetBufferAs<cmds::IsShader>();
   void* next_cmd =
@@ -1364,6 +1506,20 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, IsTransformFeedback) {
+  cmds::IsTransformFeedback& cmd = *GetBufferAs<cmds::IsTransformFeedback>();
+  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::IsTransformFeedback::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.transformfeedback);
+  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, LineWidth) {
   cmds::LineWidth& cmd = *GetBufferAs<cmds::LineWidth>();
   void* next_cmd = cmd.Set(&cmd, static_cast<GLfloat>(11));
@@ -1383,6 +1539,16 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, PauseTransformFeedback) {
+  cmds::PauseTransformFeedback& cmd =
+      *GetBufferAs<cmds::PauseTransformFeedback>();
+  void* next_cmd = cmd.Set(&cmd);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::PauseTransformFeedback::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, PixelStorei) {
   cmds::PixelStorei& cmd = *GetBufferAs<cmds::PixelStorei>();
   void* next_cmd =
@@ -1467,6 +1633,16 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, ResumeTransformFeedback) {
+  cmds::ResumeTransformFeedback& cmd =
+      *GetBufferAs<cmds::ResumeTransformFeedback>();
+  void* next_cmd = cmd.Set(&cmd);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::ResumeTransformFeedback::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, SampleCoverage) {
   cmds::SampleCoverage& cmd = *GetBufferAs<cmds::SampleCoverage>();
   void* next_cmd =
@@ -1479,6 +1655,72 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, SamplerParameterf) {
+  cmds::SamplerParameterf& cmd = *GetBufferAs<cmds::SamplerParameterf>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11),
+                           static_cast<GLenum>(12), static_cast<GLfloat>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::SamplerParameterf::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.sampler);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+  EXPECT_EQ(static_cast<GLfloat>(13), cmd.param);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, SamplerParameterfvImmediate) {
+  const int kSomeBaseValueToTestWith = 51;
+  static GLfloat data[] = {
+      static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+  };
+  cmds::SamplerParameterfvImmediate& cmd =
+      *GetBufferAs<cmds::SamplerParameterfvImmediate>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLenum>(12), data);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::SamplerParameterfvImmediate::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.sampler);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)));
+  // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, SamplerParameteri) {
+  cmds::SamplerParameteri& cmd = *GetBufferAs<cmds::SamplerParameteri>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11),
+                           static_cast<GLenum>(12), static_cast<GLint>(13));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::SamplerParameteri::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.sampler);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+  EXPECT_EQ(static_cast<GLint>(13), cmd.param);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, SamplerParameterivImmediate) {
+  const int kSomeBaseValueToTestWith = 51;
+  static GLint data[] = {
+      static_cast<GLint>(kSomeBaseValueToTestWith + 0),
+  };
+  cmds::SamplerParameterivImmediate& cmd =
+      *GetBufferAs<cmds::SamplerParameterivImmediate>();
+  void* next_cmd =
+      cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLenum>(12), data);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::SamplerParameterivImmediate::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)),
+            cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLuint>(11), cmd.sampler);
+  EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+  CheckBytesWrittenMatchesExpectedSize(
+      next_cmd, sizeof(cmd) + RoundSizeToMultipleOfEntries(sizeof(data)));
+  // TODO(gman): Check that data was inserted;
+}
+
 TEST_F(GLES2FormatTest, Scissor) {
   cmds::Scissor& cmd = *GetBufferAs<cmds::Scissor>();
   void* next_cmd = cmd.Set(&cmd, static_cast<GLint>(11), static_cast<GLint>(12),
@@ -2962,6 +3204,17 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, BeginTransformFeedback) {
+  cmds::BeginTransformFeedback& cmd =
+      *GetBufferAs<cmds::BeginTransformFeedback>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::BeginTransformFeedback::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLenum>(11), cmd.primitivemode);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, EndQueryEXT) {
   cmds::EndQueryEXT& cmd = *GetBufferAs<cmds::EndQueryEXT>();
   void* next_cmd =
@@ -2974,6 +3227,15 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, EndTransformFeedback) {
+  cmds::EndTransformFeedback& cmd = *GetBufferAs<cmds::EndTransformFeedback>();
+  void* next_cmd = cmd.Set(&cmd);
+  EXPECT_EQ(static_cast<uint32_t>(cmds::EndTransformFeedback::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 TEST_F(GLES2FormatTest, InsertEventMarkerEXT) {
   cmds::InsertEventMarkerEXT& cmd = *GetBufferAs<cmds::InsertEventMarkerEXT>();
   void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11));
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 4fe80f8..34957e4 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -18,232 +18,250 @@
   OP(BindBuffer)                               /* 259 */ \
   OP(BindFramebuffer)                          /* 260 */ \
   OP(BindRenderbuffer)                         /* 261 */ \
-  OP(BindTexture)                              /* 262 */ \
-  OP(BlendColor)                               /* 263 */ \
-  OP(BlendEquation)                            /* 264 */ \
-  OP(BlendEquationSeparate)                    /* 265 */ \
-  OP(BlendFunc)                                /* 266 */ \
-  OP(BlendFuncSeparate)                        /* 267 */ \
-  OP(BufferData)                               /* 268 */ \
-  OP(BufferSubData)                            /* 269 */ \
-  OP(CheckFramebufferStatus)                   /* 270 */ \
-  OP(Clear)                                    /* 271 */ \
-  OP(ClearColor)                               /* 272 */ \
-  OP(ClearDepthf)                              /* 273 */ \
-  OP(ClearStencil)                             /* 274 */ \
-  OP(ColorMask)                                /* 275 */ \
-  OP(CompileShader)                            /* 276 */ \
-  OP(CompressedTexImage2DBucket)               /* 277 */ \
-  OP(CompressedTexImage2D)                     /* 278 */ \
-  OP(CompressedTexSubImage2DBucket)            /* 279 */ \
-  OP(CompressedTexSubImage2D)                  /* 280 */ \
-  OP(CopyBufferSubData)                        /* 281 */ \
-  OP(CopyTexImage2D)                           /* 282 */ \
-  OP(CopyTexSubImage2D)                        /* 283 */ \
-  OP(CreateProgram)                            /* 284 */ \
-  OP(CreateShader)                             /* 285 */ \
-  OP(CullFace)                                 /* 286 */ \
-  OP(DeleteBuffersImmediate)                   /* 287 */ \
-  OP(DeleteFramebuffersImmediate)              /* 288 */ \
-  OP(DeleteProgram)                            /* 289 */ \
-  OP(DeleteRenderbuffersImmediate)             /* 290 */ \
-  OP(DeleteShader)                             /* 291 */ \
-  OP(DeleteTexturesImmediate)                  /* 292 */ \
-  OP(DepthFunc)                                /* 293 */ \
-  OP(DepthMask)                                /* 294 */ \
-  OP(DepthRangef)                              /* 295 */ \
-  OP(DetachShader)                             /* 296 */ \
-  OP(Disable)                                  /* 297 */ \
-  OP(DisableVertexAttribArray)                 /* 298 */ \
-  OP(DrawArrays)                               /* 299 */ \
-  OP(DrawElements)                             /* 300 */ \
-  OP(Enable)                                   /* 301 */ \
-  OP(EnableVertexAttribArray)                  /* 302 */ \
-  OP(Finish)                                   /* 303 */ \
-  OP(Flush)                                    /* 304 */ \
-  OP(FramebufferRenderbuffer)                  /* 305 */ \
-  OP(FramebufferTexture2D)                     /* 306 */ \
-  OP(FramebufferTextureLayer)                  /* 307 */ \
-  OP(FrontFace)                                /* 308 */ \
-  OP(GenBuffersImmediate)                      /* 309 */ \
-  OP(GenerateMipmap)                           /* 310 */ \
-  OP(GenFramebuffersImmediate)                 /* 311 */ \
-  OP(GenRenderbuffersImmediate)                /* 312 */ \
-  OP(GenTexturesImmediate)                     /* 313 */ \
-  OP(GetActiveAttrib)                          /* 314 */ \
-  OP(GetActiveUniform)                         /* 315 */ \
-  OP(GetAttachedShaders)                       /* 316 */ \
-  OP(GetAttribLocation)                        /* 317 */ \
-  OP(GetBooleanv)                              /* 318 */ \
-  OP(GetBufferParameteriv)                     /* 319 */ \
-  OP(GetError)                                 /* 320 */ \
-  OP(GetFloatv)                                /* 321 */ \
-  OP(GetFramebufferAttachmentParameteriv)      /* 322 */ \
-  OP(GetIntegerv)                              /* 323 */ \
-  OP(GetInternalformativ)                      /* 324 */ \
-  OP(GetProgramiv)                             /* 325 */ \
-  OP(GetProgramInfoLog)                        /* 326 */ \
-  OP(GetRenderbufferParameteriv)               /* 327 */ \
-  OP(GetShaderiv)                              /* 328 */ \
-  OP(GetShaderInfoLog)                         /* 329 */ \
-  OP(GetShaderPrecisionFormat)                 /* 330 */ \
-  OP(GetShaderSource)                          /* 331 */ \
-  OP(GetString)                                /* 332 */ \
-  OP(GetTexParameterfv)                        /* 333 */ \
-  OP(GetTexParameteriv)                        /* 334 */ \
-  OP(GetUniformfv)                             /* 335 */ \
-  OP(GetUniformiv)                             /* 336 */ \
-  OP(GetUniformLocation)                       /* 337 */ \
-  OP(GetVertexAttribfv)                        /* 338 */ \
-  OP(GetVertexAttribiv)                        /* 339 */ \
-  OP(GetVertexAttribPointerv)                  /* 340 */ \
-  OP(Hint)                                     /* 341 */ \
-  OP(InvalidateFramebufferImmediate)           /* 342 */ \
-  OP(InvalidateSubFramebufferImmediate)        /* 343 */ \
-  OP(IsBuffer)                                 /* 344 */ \
-  OP(IsEnabled)                                /* 345 */ \
-  OP(IsFramebuffer)                            /* 346 */ \
-  OP(IsProgram)                                /* 347 */ \
-  OP(IsRenderbuffer)                           /* 348 */ \
-  OP(IsShader)                                 /* 349 */ \
-  OP(IsTexture)                                /* 350 */ \
-  OP(LineWidth)                                /* 351 */ \
-  OP(LinkProgram)                              /* 352 */ \
-  OP(PixelStorei)                              /* 353 */ \
-  OP(PolygonOffset)                            /* 354 */ \
-  OP(ReadBuffer)                               /* 355 */ \
-  OP(ReadPixels)                               /* 356 */ \
-  OP(ReleaseShaderCompiler)                    /* 357 */ \
-  OP(RenderbufferStorage)                      /* 358 */ \
-  OP(SampleCoverage)                           /* 359 */ \
-  OP(Scissor)                                  /* 360 */ \
-  OP(ShaderBinary)                             /* 361 */ \
-  OP(ShaderSourceBucket)                       /* 362 */ \
-  OP(StencilFunc)                              /* 363 */ \
-  OP(StencilFuncSeparate)                      /* 364 */ \
-  OP(StencilMask)                              /* 365 */ \
-  OP(StencilMaskSeparate)                      /* 366 */ \
-  OP(StencilOp)                                /* 367 */ \
-  OP(StencilOpSeparate)                        /* 368 */ \
-  OP(TexImage2D)                               /* 369 */ \
-  OP(TexParameterf)                            /* 370 */ \
-  OP(TexParameterfvImmediate)                  /* 371 */ \
-  OP(TexParameteri)                            /* 372 */ \
-  OP(TexParameterivImmediate)                  /* 373 */ \
-  OP(TexStorage3D)                             /* 374 */ \
-  OP(TexSubImage2D)                            /* 375 */ \
-  OP(Uniform1f)                                /* 376 */ \
-  OP(Uniform1fvImmediate)                      /* 377 */ \
-  OP(Uniform1i)                                /* 378 */ \
-  OP(Uniform1ivImmediate)                      /* 379 */ \
-  OP(Uniform1ui)                               /* 380 */ \
-  OP(Uniform1uivImmediate)                     /* 381 */ \
-  OP(Uniform2f)                                /* 382 */ \
-  OP(Uniform2fvImmediate)                      /* 383 */ \
-  OP(Uniform2i)                                /* 384 */ \
-  OP(Uniform2ivImmediate)                      /* 385 */ \
-  OP(Uniform2ui)                               /* 386 */ \
-  OP(Uniform2uivImmediate)                     /* 387 */ \
-  OP(Uniform3f)                                /* 388 */ \
-  OP(Uniform3fvImmediate)                      /* 389 */ \
-  OP(Uniform3i)                                /* 390 */ \
-  OP(Uniform3ivImmediate)                      /* 391 */ \
-  OP(Uniform3ui)                               /* 392 */ \
-  OP(Uniform3uivImmediate)                     /* 393 */ \
-  OP(Uniform4f)                                /* 394 */ \
-  OP(Uniform4fvImmediate)                      /* 395 */ \
-  OP(Uniform4i)                                /* 396 */ \
-  OP(Uniform4ivImmediate)                      /* 397 */ \
-  OP(Uniform4ui)                               /* 398 */ \
-  OP(Uniform4uivImmediate)                     /* 399 */ \
-  OP(UniformMatrix2fvImmediate)                /* 400 */ \
-  OP(UniformMatrix2x3fvImmediate)              /* 401 */ \
-  OP(UniformMatrix2x4fvImmediate)              /* 402 */ \
-  OP(UniformMatrix3fvImmediate)                /* 403 */ \
-  OP(UniformMatrix3x2fvImmediate)              /* 404 */ \
-  OP(UniformMatrix3x4fvImmediate)              /* 405 */ \
-  OP(UniformMatrix4fvImmediate)                /* 406 */ \
-  OP(UniformMatrix4x2fvImmediate)              /* 407 */ \
-  OP(UniformMatrix4x3fvImmediate)              /* 408 */ \
-  OP(UseProgram)                               /* 409 */ \
-  OP(ValidateProgram)                          /* 410 */ \
-  OP(VertexAttrib1f)                           /* 411 */ \
-  OP(VertexAttrib1fvImmediate)                 /* 412 */ \
-  OP(VertexAttrib2f)                           /* 413 */ \
-  OP(VertexAttrib2fvImmediate)                 /* 414 */ \
-  OP(VertexAttrib3f)                           /* 415 */ \
-  OP(VertexAttrib3fvImmediate)                 /* 416 */ \
-  OP(VertexAttrib4f)                           /* 417 */ \
-  OP(VertexAttrib4fvImmediate)                 /* 418 */ \
-  OP(VertexAttribI4i)                          /* 419 */ \
-  OP(VertexAttribI4ivImmediate)                /* 420 */ \
-  OP(VertexAttribI4ui)                         /* 421 */ \
-  OP(VertexAttribI4uivImmediate)               /* 422 */ \
-  OP(VertexAttribIPointer)                     /* 423 */ \
-  OP(VertexAttribPointer)                      /* 424 */ \
-  OP(Viewport)                                 /* 425 */ \
-  OP(BlitFramebufferCHROMIUM)                  /* 426 */ \
-  OP(RenderbufferStorageMultisampleCHROMIUM)   /* 427 */ \
-  OP(RenderbufferStorageMultisampleEXT)        /* 428 */ \
-  OP(FramebufferTexture2DMultisampleEXT)       /* 429 */ \
-  OP(TexStorage2DEXT)                          /* 430 */ \
-  OP(GenQueriesEXTImmediate)                   /* 431 */ \
-  OP(DeleteQueriesEXTImmediate)                /* 432 */ \
-  OP(BeginQueryEXT)                            /* 433 */ \
-  OP(EndQueryEXT)                              /* 434 */ \
-  OP(InsertEventMarkerEXT)                     /* 435 */ \
-  OP(PushGroupMarkerEXT)                       /* 436 */ \
-  OP(PopGroupMarkerEXT)                        /* 437 */ \
-  OP(GenVertexArraysOESImmediate)              /* 438 */ \
-  OP(DeleteVertexArraysOESImmediate)           /* 439 */ \
-  OP(IsVertexArrayOES)                         /* 440 */ \
-  OP(BindVertexArrayOES)                       /* 441 */ \
-  OP(SwapBuffers)                              /* 442 */ \
-  OP(GetMaxValueInBufferCHROMIUM)              /* 443 */ \
-  OP(EnableFeatureCHROMIUM)                    /* 444 */ \
-  OP(ResizeCHROMIUM)                           /* 445 */ \
-  OP(GetRequestableExtensionsCHROMIUM)         /* 446 */ \
-  OP(RequestExtensionCHROMIUM)                 /* 447 */ \
-  OP(GetProgramInfoCHROMIUM)                   /* 448 */ \
-  OP(GetTranslatedShaderSourceANGLE)           /* 449 */ \
-  OP(PostSubBufferCHROMIUM)                    /* 450 */ \
-  OP(TexImageIOSurface2DCHROMIUM)              /* 451 */ \
-  OP(CopyTextureCHROMIUM)                      /* 452 */ \
-  OP(DrawArraysInstancedANGLE)                 /* 453 */ \
-  OP(DrawElementsInstancedANGLE)               /* 454 */ \
-  OP(VertexAttribDivisorANGLE)                 /* 455 */ \
-  OP(GenMailboxCHROMIUM)                       /* 456 */ \
-  OP(ProduceTextureCHROMIUMImmediate)          /* 457 */ \
-  OP(ProduceTextureDirectCHROMIUMImmediate)    /* 458 */ \
-  OP(ConsumeTextureCHROMIUMImmediate)          /* 459 */ \
-  OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 460 */ \
-  OP(BindUniformLocationCHROMIUMBucket)        /* 461 */ \
-  OP(GenValuebuffersCHROMIUMImmediate)         /* 462 */ \
-  OP(DeleteValuebuffersCHROMIUMImmediate)      /* 463 */ \
-  OP(IsValuebufferCHROMIUM)                    /* 464 */ \
-  OP(BindValuebufferCHROMIUM)                  /* 465 */ \
-  OP(SubscribeValueCHROMIUM)                   /* 466 */ \
-  OP(PopulateSubscribedValuesCHROMIUM)         /* 467 */ \
-  OP(UniformValuebufferCHROMIUM)               /* 468 */ \
-  OP(BindTexImage2DCHROMIUM)                   /* 469 */ \
-  OP(ReleaseTexImage2DCHROMIUM)                /* 470 */ \
-  OP(TraceBeginCHROMIUM)                       /* 471 */ \
-  OP(TraceEndCHROMIUM)                         /* 472 */ \
-  OP(AsyncTexSubImage2DCHROMIUM)               /* 473 */ \
-  OP(AsyncTexImage2DCHROMIUM)                  /* 474 */ \
-  OP(WaitAsyncTexImage2DCHROMIUM)              /* 475 */ \
-  OP(WaitAllAsyncTexImage2DCHROMIUM)           /* 476 */ \
-  OP(DiscardFramebufferEXTImmediate)           /* 477 */ \
-  OP(LoseContextCHROMIUM)                      /* 478 */ \
-  OP(InsertSyncPointCHROMIUM)                  /* 479 */ \
-  OP(WaitSyncPointCHROMIUM)                    /* 480 */ \
-  OP(DrawBuffersEXTImmediate)                  /* 481 */ \
-  OP(DiscardBackbufferCHROMIUM)                /* 482 */ \
-  OP(ScheduleOverlayPlaneCHROMIUM)             /* 483 */ \
-  OP(SwapInterval)                             /* 484 */ \
-  OP(MatrixLoadfCHROMIUMImmediate)             /* 485 */ \
-  OP(MatrixLoadIdentityCHROMIUM)               /* 486 */ \
-  OP(BlendBarrierKHR)                          /* 487 */
+  OP(BindSampler)                              /* 262 */ \
+  OP(BindTexture)                              /* 263 */ \
+  OP(BindTransformFeedback)                    /* 264 */ \
+  OP(BlendColor)                               /* 265 */ \
+  OP(BlendEquation)                            /* 266 */ \
+  OP(BlendEquationSeparate)                    /* 267 */ \
+  OP(BlendFunc)                                /* 268 */ \
+  OP(BlendFuncSeparate)                        /* 269 */ \
+  OP(BufferData)                               /* 270 */ \
+  OP(BufferSubData)                            /* 271 */ \
+  OP(CheckFramebufferStatus)                   /* 272 */ \
+  OP(Clear)                                    /* 273 */ \
+  OP(ClearColor)                               /* 274 */ \
+  OP(ClearDepthf)                              /* 275 */ \
+  OP(ClearStencil)                             /* 276 */ \
+  OP(ColorMask)                                /* 277 */ \
+  OP(CompileShader)                            /* 278 */ \
+  OP(CompressedTexImage2DBucket)               /* 279 */ \
+  OP(CompressedTexImage2D)                     /* 280 */ \
+  OP(CompressedTexSubImage2DBucket)            /* 281 */ \
+  OP(CompressedTexSubImage2D)                  /* 282 */ \
+  OP(CopyBufferSubData)                        /* 283 */ \
+  OP(CopyTexImage2D)                           /* 284 */ \
+  OP(CopyTexSubImage2D)                        /* 285 */ \
+  OP(CreateProgram)                            /* 286 */ \
+  OP(CreateShader)                             /* 287 */ \
+  OP(CullFace)                                 /* 288 */ \
+  OP(DeleteBuffersImmediate)                   /* 289 */ \
+  OP(DeleteFramebuffersImmediate)              /* 290 */ \
+  OP(DeleteProgram)                            /* 291 */ \
+  OP(DeleteRenderbuffersImmediate)             /* 292 */ \
+  OP(DeleteSamplersImmediate)                  /* 293 */ \
+  OP(DeleteShader)                             /* 294 */ \
+  OP(DeleteTexturesImmediate)                  /* 295 */ \
+  OP(DeleteTransformFeedbacksImmediate)        /* 296 */ \
+  OP(DepthFunc)                                /* 297 */ \
+  OP(DepthMask)                                /* 298 */ \
+  OP(DepthRangef)                              /* 299 */ \
+  OP(DetachShader)                             /* 300 */ \
+  OP(Disable)                                  /* 301 */ \
+  OP(DisableVertexAttribArray)                 /* 302 */ \
+  OP(DrawArrays)                               /* 303 */ \
+  OP(DrawElements)                             /* 304 */ \
+  OP(Enable)                                   /* 305 */ \
+  OP(EnableVertexAttribArray)                  /* 306 */ \
+  OP(Finish)                                   /* 307 */ \
+  OP(Flush)                                    /* 308 */ \
+  OP(FramebufferRenderbuffer)                  /* 309 */ \
+  OP(FramebufferTexture2D)                     /* 310 */ \
+  OP(FramebufferTextureLayer)                  /* 311 */ \
+  OP(FrontFace)                                /* 312 */ \
+  OP(GenBuffersImmediate)                      /* 313 */ \
+  OP(GenerateMipmap)                           /* 314 */ \
+  OP(GenFramebuffersImmediate)                 /* 315 */ \
+  OP(GenRenderbuffersImmediate)                /* 316 */ \
+  OP(GenSamplersImmediate)                     /* 317 */ \
+  OP(GenTexturesImmediate)                     /* 318 */ \
+  OP(GenTransformFeedbacksImmediate)           /* 319 */ \
+  OP(GetActiveAttrib)                          /* 320 */ \
+  OP(GetActiveUniform)                         /* 321 */ \
+  OP(GetAttachedShaders)                       /* 322 */ \
+  OP(GetAttribLocation)                        /* 323 */ \
+  OP(GetBooleanv)                              /* 324 */ \
+  OP(GetBufferParameteriv)                     /* 325 */ \
+  OP(GetError)                                 /* 326 */ \
+  OP(GetFloatv)                                /* 327 */ \
+  OP(GetFramebufferAttachmentParameteriv)      /* 328 */ \
+  OP(GetIntegerv)                              /* 329 */ \
+  OP(GetInternalformativ)                      /* 330 */ \
+  OP(GetProgramiv)                             /* 331 */ \
+  OP(GetProgramInfoLog)                        /* 332 */ \
+  OP(GetRenderbufferParameteriv)               /* 333 */ \
+  OP(GetSamplerParameterfv)                    /* 334 */ \
+  OP(GetSamplerParameteriv)                    /* 335 */ \
+  OP(GetShaderiv)                              /* 336 */ \
+  OP(GetShaderInfoLog)                         /* 337 */ \
+  OP(GetShaderPrecisionFormat)                 /* 338 */ \
+  OP(GetShaderSource)                          /* 339 */ \
+  OP(GetString)                                /* 340 */ \
+  OP(GetTexParameterfv)                        /* 341 */ \
+  OP(GetTexParameteriv)                        /* 342 */ \
+  OP(GetUniformfv)                             /* 343 */ \
+  OP(GetUniformiv)                             /* 344 */ \
+  OP(GetUniformLocation)                       /* 345 */ \
+  OP(GetVertexAttribfv)                        /* 346 */ \
+  OP(GetVertexAttribiv)                        /* 347 */ \
+  OP(GetVertexAttribPointerv)                  /* 348 */ \
+  OP(Hint)                                     /* 349 */ \
+  OP(InvalidateFramebufferImmediate)           /* 350 */ \
+  OP(InvalidateSubFramebufferImmediate)        /* 351 */ \
+  OP(IsBuffer)                                 /* 352 */ \
+  OP(IsEnabled)                                /* 353 */ \
+  OP(IsFramebuffer)                            /* 354 */ \
+  OP(IsProgram)                                /* 355 */ \
+  OP(IsRenderbuffer)                           /* 356 */ \
+  OP(IsSampler)                                /* 357 */ \
+  OP(IsShader)                                 /* 358 */ \
+  OP(IsTexture)                                /* 359 */ \
+  OP(IsTransformFeedback)                      /* 360 */ \
+  OP(LineWidth)                                /* 361 */ \
+  OP(LinkProgram)                              /* 362 */ \
+  OP(PauseTransformFeedback)                   /* 363 */ \
+  OP(PixelStorei)                              /* 364 */ \
+  OP(PolygonOffset)                            /* 365 */ \
+  OP(ReadBuffer)                               /* 366 */ \
+  OP(ReadPixels)                               /* 367 */ \
+  OP(ReleaseShaderCompiler)                    /* 368 */ \
+  OP(RenderbufferStorage)                      /* 369 */ \
+  OP(ResumeTransformFeedback)                  /* 370 */ \
+  OP(SampleCoverage)                           /* 371 */ \
+  OP(SamplerParameterf)                        /* 372 */ \
+  OP(SamplerParameterfvImmediate)              /* 373 */ \
+  OP(SamplerParameteri)                        /* 374 */ \
+  OP(SamplerParameterivImmediate)              /* 375 */ \
+  OP(Scissor)                                  /* 376 */ \
+  OP(ShaderBinary)                             /* 377 */ \
+  OP(ShaderSourceBucket)                       /* 378 */ \
+  OP(StencilFunc)                              /* 379 */ \
+  OP(StencilFuncSeparate)                      /* 380 */ \
+  OP(StencilMask)                              /* 381 */ \
+  OP(StencilMaskSeparate)                      /* 382 */ \
+  OP(StencilOp)                                /* 383 */ \
+  OP(StencilOpSeparate)                        /* 384 */ \
+  OP(TexImage2D)                               /* 385 */ \
+  OP(TexParameterf)                            /* 386 */ \
+  OP(TexParameterfvImmediate)                  /* 387 */ \
+  OP(TexParameteri)                            /* 388 */ \
+  OP(TexParameterivImmediate)                  /* 389 */ \
+  OP(TexStorage3D)                             /* 390 */ \
+  OP(TexSubImage2D)                            /* 391 */ \
+  OP(Uniform1f)                                /* 392 */ \
+  OP(Uniform1fvImmediate)                      /* 393 */ \
+  OP(Uniform1i)                                /* 394 */ \
+  OP(Uniform1ivImmediate)                      /* 395 */ \
+  OP(Uniform1ui)                               /* 396 */ \
+  OP(Uniform1uivImmediate)                     /* 397 */ \
+  OP(Uniform2f)                                /* 398 */ \
+  OP(Uniform2fvImmediate)                      /* 399 */ \
+  OP(Uniform2i)                                /* 400 */ \
+  OP(Uniform2ivImmediate)                      /* 401 */ \
+  OP(Uniform2ui)                               /* 402 */ \
+  OP(Uniform2uivImmediate)                     /* 403 */ \
+  OP(Uniform3f)                                /* 404 */ \
+  OP(Uniform3fvImmediate)                      /* 405 */ \
+  OP(Uniform3i)                                /* 406 */ \
+  OP(Uniform3ivImmediate)                      /* 407 */ \
+  OP(Uniform3ui)                               /* 408 */ \
+  OP(Uniform3uivImmediate)                     /* 409 */ \
+  OP(Uniform4f)                                /* 410 */ \
+  OP(Uniform4fvImmediate)                      /* 411 */ \
+  OP(Uniform4i)                                /* 412 */ \
+  OP(Uniform4ivImmediate)                      /* 413 */ \
+  OP(Uniform4ui)                               /* 414 */ \
+  OP(Uniform4uivImmediate)                     /* 415 */ \
+  OP(UniformMatrix2fvImmediate)                /* 416 */ \
+  OP(UniformMatrix2x3fvImmediate)              /* 417 */ \
+  OP(UniformMatrix2x4fvImmediate)              /* 418 */ \
+  OP(UniformMatrix3fvImmediate)                /* 419 */ \
+  OP(UniformMatrix3x2fvImmediate)              /* 420 */ \
+  OP(UniformMatrix3x4fvImmediate)              /* 421 */ \
+  OP(UniformMatrix4fvImmediate)                /* 422 */ \
+  OP(UniformMatrix4x2fvImmediate)              /* 423 */ \
+  OP(UniformMatrix4x3fvImmediate)              /* 424 */ \
+  OP(UseProgram)                               /* 425 */ \
+  OP(ValidateProgram)                          /* 426 */ \
+  OP(VertexAttrib1f)                           /* 427 */ \
+  OP(VertexAttrib1fvImmediate)                 /* 428 */ \
+  OP(VertexAttrib2f)                           /* 429 */ \
+  OP(VertexAttrib2fvImmediate)                 /* 430 */ \
+  OP(VertexAttrib3f)                           /* 431 */ \
+  OP(VertexAttrib3fvImmediate)                 /* 432 */ \
+  OP(VertexAttrib4f)                           /* 433 */ \
+  OP(VertexAttrib4fvImmediate)                 /* 434 */ \
+  OP(VertexAttribI4i)                          /* 435 */ \
+  OP(VertexAttribI4ivImmediate)                /* 436 */ \
+  OP(VertexAttribI4ui)                         /* 437 */ \
+  OP(VertexAttribI4uivImmediate)               /* 438 */ \
+  OP(VertexAttribIPointer)                     /* 439 */ \
+  OP(VertexAttribPointer)                      /* 440 */ \
+  OP(Viewport)                                 /* 441 */ \
+  OP(BlitFramebufferCHROMIUM)                  /* 442 */ \
+  OP(RenderbufferStorageMultisampleCHROMIUM)   /* 443 */ \
+  OP(RenderbufferStorageMultisampleEXT)        /* 444 */ \
+  OP(FramebufferTexture2DMultisampleEXT)       /* 445 */ \
+  OP(TexStorage2DEXT)                          /* 446 */ \
+  OP(GenQueriesEXTImmediate)                   /* 447 */ \
+  OP(DeleteQueriesEXTImmediate)                /* 448 */ \
+  OP(BeginQueryEXT)                            /* 449 */ \
+  OP(BeginTransformFeedback)                   /* 450 */ \
+  OP(EndQueryEXT)                              /* 451 */ \
+  OP(EndTransformFeedback)                     /* 452 */ \
+  OP(InsertEventMarkerEXT)                     /* 453 */ \
+  OP(PushGroupMarkerEXT)                       /* 454 */ \
+  OP(PopGroupMarkerEXT)                        /* 455 */ \
+  OP(GenVertexArraysOESImmediate)              /* 456 */ \
+  OP(DeleteVertexArraysOESImmediate)           /* 457 */ \
+  OP(IsVertexArrayOES)                         /* 458 */ \
+  OP(BindVertexArrayOES)                       /* 459 */ \
+  OP(SwapBuffers)                              /* 460 */ \
+  OP(GetMaxValueInBufferCHROMIUM)              /* 461 */ \
+  OP(EnableFeatureCHROMIUM)                    /* 462 */ \
+  OP(ResizeCHROMIUM)                           /* 463 */ \
+  OP(GetRequestableExtensionsCHROMIUM)         /* 464 */ \
+  OP(RequestExtensionCHROMIUM)                 /* 465 */ \
+  OP(GetProgramInfoCHROMIUM)                   /* 466 */ \
+  OP(GetTranslatedShaderSourceANGLE)           /* 467 */ \
+  OP(PostSubBufferCHROMIUM)                    /* 468 */ \
+  OP(TexImageIOSurface2DCHROMIUM)              /* 469 */ \
+  OP(CopyTextureCHROMIUM)                      /* 470 */ \
+  OP(DrawArraysInstancedANGLE)                 /* 471 */ \
+  OP(DrawElementsInstancedANGLE)               /* 472 */ \
+  OP(VertexAttribDivisorANGLE)                 /* 473 */ \
+  OP(GenMailboxCHROMIUM)                       /* 474 */ \
+  OP(ProduceTextureCHROMIUMImmediate)          /* 475 */ \
+  OP(ProduceTextureDirectCHROMIUMImmediate)    /* 476 */ \
+  OP(ConsumeTextureCHROMIUMImmediate)          /* 477 */ \
+  OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 478 */ \
+  OP(BindUniformLocationCHROMIUMBucket)        /* 479 */ \
+  OP(GenValuebuffersCHROMIUMImmediate)         /* 480 */ \
+  OP(DeleteValuebuffersCHROMIUMImmediate)      /* 481 */ \
+  OP(IsValuebufferCHROMIUM)                    /* 482 */ \
+  OP(BindValuebufferCHROMIUM)                  /* 483 */ \
+  OP(SubscribeValueCHROMIUM)                   /* 484 */ \
+  OP(PopulateSubscribedValuesCHROMIUM)         /* 485 */ \
+  OP(UniformValuebufferCHROMIUM)               /* 486 */ \
+  OP(BindTexImage2DCHROMIUM)                   /* 487 */ \
+  OP(ReleaseTexImage2DCHROMIUM)                /* 488 */ \
+  OP(TraceBeginCHROMIUM)                       /* 489 */ \
+  OP(TraceEndCHROMIUM)                         /* 490 */ \
+  OP(AsyncTexSubImage2DCHROMIUM)               /* 491 */ \
+  OP(AsyncTexImage2DCHROMIUM)                  /* 492 */ \
+  OP(WaitAsyncTexImage2DCHROMIUM)              /* 493 */ \
+  OP(WaitAllAsyncTexImage2DCHROMIUM)           /* 494 */ \
+  OP(DiscardFramebufferEXTImmediate)           /* 495 */ \
+  OP(LoseContextCHROMIUM)                      /* 496 */ \
+  OP(InsertSyncPointCHROMIUM)                  /* 497 */ \
+  OP(WaitSyncPointCHROMIUM)                    /* 498 */ \
+  OP(DrawBuffersEXTImmediate)                  /* 499 */ \
+  OP(DiscardBackbufferCHROMIUM)                /* 500 */ \
+  OP(ScheduleOverlayPlaneCHROMIUM)             /* 501 */ \
+  OP(SwapInterval)                             /* 502 */ \
+  OP(MatrixLoadfCHROMIUMImmediate)             /* 503 */ \
+  OP(MatrixLoadIdentityCHROMIUM)               /* 504 */ \
+  OP(BlendBarrierKHR)                          /* 505 */
 
 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 bb809fc..e4ccbe7 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -48,6 +48,7 @@
 static std::string GetStringRenderBufferParameter(uint32_t value);
 static std::string GetStringRenderBufferTarget(uint32_t value);
 static std::string GetStringResetStatus(uint32_t value);
+static std::string GetStringSamplerParameter(uint32_t value);
 static std::string GetStringShaderBinaryFormat(uint32_t value);
 static std::string GetStringShaderParameter(uint32_t value);
 static std::string GetStringShaderPrecision(uint32_t value);
@@ -68,6 +69,8 @@
 static std::string GetStringTextureTarget(uint32_t value);
 static std::string GetStringTextureUsage(uint32_t value);
 static std::string GetStringTextureWrapMode(uint32_t value);
+static std::string GetStringTransformFeedbackBindTarget(uint32_t value);
+static std::string GetStringTransformFeedbackPrimitiveMode(uint32_t value);
 static std::string GetStringValueBufferTarget(uint32_t value);
 static std::string GetStringVertexAttribType(uint32_t value);
 static std::string GetStringVertexAttribute(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 b205347..03a6d4d 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -4938,6 +4938,22 @@
                                            arraysize(string_table), value);
 }
 
+std::string GLES2Util::GetStringSamplerParameter(uint32_t value) {
+  static const EnumToString string_table[] = {
+      {GL_TEXTURE_MAG_FILTER, "GL_TEXTURE_MAG_FILTER"},
+      {GL_TEXTURE_MIN_FILTER, "GL_TEXTURE_MIN_FILTER"},
+      {GL_TEXTURE_MIN_LOD, "GL_TEXTURE_MIN_LOD"},
+      {GL_TEXTURE_MAX_LOD, "GL_TEXTURE_MAX_LOD"},
+      {GL_TEXTURE_WRAP_S, "GL_TEXTURE_WRAP_S"},
+      {GL_TEXTURE_WRAP_T, "GL_TEXTURE_WRAP_T"},
+      {GL_TEXTURE_WRAP_R, "GL_TEXTURE_WRAP_R"},
+      {GL_TEXTURE_COMPARE_MODE, "GL_TEXTURE_COMPARE_MODE"},
+      {GL_TEXTURE_COMPARE_FUNC, "GL_TEXTURE_COMPARE_FUNC"},
+  };
+  return GLES2Util::GetQualifiedEnumString(string_table,
+                                           arraysize(string_table), value);
+}
+
 std::string GLES2Util::GetStringShaderBinaryFormat(uint32_t value) {
   return GLES2Util::GetQualifiedEnumString(NULL, 0, value);
 }
@@ -5168,6 +5184,24 @@
                                            arraysize(string_table), value);
 }
 
+std::string GLES2Util::GetStringTransformFeedbackBindTarget(uint32_t value) {
+  static const EnumToString string_table[] = {
+      {GL_TRANSFORM_FEEDBACK, "GL_TRANSFORM_FEEDBACK"},
+  };
+  return GLES2Util::GetQualifiedEnumString(string_table,
+                                           arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTransformFeedbackPrimitiveMode(uint32_t value) {
+  static const EnumToString string_table[] = {
+      {GL_POINTS, "GL_POINTS"},
+      {GL_LINES, "GL_LINES"},
+      {GL_TRIANGLES, "GL_TRIANGLES"},
+  };
+  return GLES2Util::GetQualifiedEnumString(string_table,
+                                           arraysize(string_table), value);
+}
+
 std::string GLES2Util::GetStringValueBufferTarget(uint32_t value) {
   static const EnumToString string_table[] = {
       {GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index b6b6483..f695a3e 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -5,6 +5,7 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_CONTEXT_GROUP_H_
 #define GPU_COMMAND_BUFFER_SERVICE_CONTEXT_GROUP_H_
 
+#include <map>
 #include <string>
 #include <vector>
 #include "base/basictypes.h"
@@ -174,6 +175,43 @@
     draw_buffer_ = buf;
   }
 
+  void AddSamplerId(GLuint client_id, GLuint service_id) {
+    samplers_id_map_[client_id] = service_id;
+  }
+
+  bool GetSamplerServiceId(GLuint client_id, GLuint* service_id) const {
+    std::map<GLuint, GLuint>::const_iterator iter =
+        samplers_id_map_.find(client_id);
+    if (iter == samplers_id_map_.end())
+      return false;
+    if (service_id)
+      *service_id = iter->second;
+    return true;
+  }
+
+  void RemoveSamplerId(GLuint client_id) {
+    samplers_id_map_.erase(client_id);
+  }
+
+  void AddTransformFeedbackId(GLuint client_id, GLuint service_id) {
+    transformfeedbacks_id_map_[client_id] = service_id;
+  }
+
+  bool GetTransformFeedbackServiceId(
+      GLuint client_id, GLuint* service_id) const {
+    std::map<GLuint, GLuint>::const_iterator iter =
+        transformfeedbacks_id_map_.find(client_id);
+    if (iter == transformfeedbacks_id_map_.end())
+      return false;
+    if (service_id)
+      *service_id = iter->second;
+    return true;
+  }
+
+  void RemoveTransformFeedbackId(GLuint client_id) {
+    transformfeedbacks_id_map_.erase(client_id);
+  }
+
  private:
   friend class base::RefCounted<ContextGroup>;
   ~ContextGroup();
@@ -223,6 +261,10 @@
 
   std::vector<base::WeakPtr<gles2::GLES2Decoder> > decoders_;
 
+  // Mappings from client side IDs to service side IDs.
+  std::map<GLuint, GLuint> samplers_id_map_;
+  std::map<GLuint, GLuint> transformfeedbacks_id_map_;
+
   GLenum draw_buffer_;
 
   DISALLOW_COPY_AND_ASSIGN(ContextGroup);
diff --git a/gpu/command_buffer/service/gl_context_virtual.cc b/gpu/command_buffer/service/gl_context_virtual.cc
index a29e540..765dbee 100644
--- a/gpu/command_buffer/service/gl_context_virtual.cc
+++ b/gpu/command_buffer/service/gl_context_virtual.cc
@@ -82,7 +82,7 @@
   return shared_context_->GetHandle();
 }
 
-void GLContextVirtual::SetSwapInterval(int interval) {
+void GLContextVirtual::OnSetSwapInterval(int interval) {
   shared_context_->SetSwapInterval(interval);
 }
 
diff --git a/gpu/command_buffer/service/gl_context_virtual.h b/gpu/command_buffer/service/gl_context_virtual.h
index ed61016..7a79928 100644
--- a/gpu/command_buffer/service/gl_context_virtual.h
+++ b/gpu/command_buffer/service/gl_context_virtual.h
@@ -41,7 +41,7 @@
   void ReleaseCurrent(gfx::GLSurface* surface) override;
   bool IsCurrent(gfx::GLSurface* surface) override;
   void* GetHandle() override;
-  void SetSwapInterval(int interval) override;
+  void OnSetSwapInterval(int interval) override;
   std::string GetExtensions() override;
   bool GetTotalGpuMemory(size_t* bytes) override;
   void SetSafeToForceGpuSwitch() override;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index f97710e..7ea1a06 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1473,6 +1473,11 @@
   // Wrapper for glReleaseShaderCompiler.
   void DoReleaseShaderCompiler() { }
 
+  // Wrappers for glSamplerParameter*v functions.
+  void DoSamplerParameterfv(
+      GLuint sampler, GLenum pname, const GLfloat* params);
+  void DoSamplerParameteriv(GLuint sampler, GLenum pname, const GLint* params);
+
   // Wrappers for glTexParameter functions.
   void DoTexParameterf(GLenum target, GLenum pname, GLfloat param);
   void DoTexParameteri(GLenum target, GLenum pname, GLint param);
@@ -2955,6 +2960,10 @@
   if (workarounds().regenerate_struct_names)
     driver_bug_workarounds |= SH_REGENERATE_STRUCT_NAMES;
 
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEmulateShaderPrecision))
+    resources.WEBGL_debug_shader_precision = true;
+
   vertex_translator_ = shader_translator_cache()->GetTranslator(
       GL_VERTEX_SHADER,
       shader_spec,
@@ -4269,6 +4278,14 @@
 void GLES2DecoderImpl::OnFboChanged() const {
   if (workarounds().restore_scissor_on_fbo_change)
     state_.fbo_binding_for_scissor_workaround_dirty_ = true;
+
+  if (workarounds().gl_begin_gl_end_on_fbo_change_to_backbuffer) {
+    GLint bound_fbo_unsigned = -1;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &bound_fbo_unsigned);
+    GLuint bound_fbo = static_cast<GLuint>(bound_fbo_unsigned);
+    if (surface_ && surface_->GetBackingFrameBufferObject() == bound_fbo)
+      surface_->NotifyWasBound();
+  }
 }
 
 // Called after the FBO is checked for completeness.
@@ -5858,6 +5875,18 @@
   ExitCommandProcessingEarly();
 };
 
+void GLES2DecoderImpl::DoSamplerParameterfv(
+    GLuint sampler, GLenum pname, const GLfloat* params) {
+  DCHECK(params);
+  glSamplerParameterf(sampler, pname, params[0]);
+}
+
+void GLES2DecoderImpl::DoSamplerParameteriv(
+    GLuint sampler, GLenum pname, const GLint* params) {
+  DCHECK(params);
+  glSamplerParameteri(sampler, pname, params[0]);
+}
+
 void GLES2DecoderImpl::DoTexParameterf(
     GLenum target, GLenum pname, GLfloat param) {
   TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index f81b56a..b7877ff 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -80,6 +80,20 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleBindSampler(uint32_t immediate_data_size,
+                                                 const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::BindSampler& c =
+      *static_cast<const gles2::cmds::BindSampler*>(cmd_data);
+  (void)c;
+  GLuint unit = static_cast<GLuint>(c.unit);
+  GLuint sampler = c.sampler;
+  group_->GetSamplerServiceId(sampler, &sampler);
+  glBindSampler(unit, sampler);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleBindTexture(uint32_t immediate_data_size,
                                                  const void* cmd_data) {
   const gles2::cmds::BindTexture& c =
@@ -95,6 +109,21 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleBindTransformFeedback(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::BindTransformFeedback& c =
+      *static_cast<const gles2::cmds::BindTransformFeedback*>(cmd_data);
+  (void)c;
+  GLenum target = static_cast<GLenum>(c.target);
+  GLuint transformfeedback = c.transformfeedback;
+  group_->GetTransformFeedbackServiceId(transformfeedback, &transformfeedback);
+  glBindTransformFeedback(target, transformfeedback);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleBlendColor(uint32_t immediate_data_size,
                                                 const void* cmd_data) {
   const gles2::cmds::BlendColor& c =
@@ -616,6 +645,34 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleDeleteSamplersImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::DeleteSamplersImmediate& c =
+      *static_cast<const gles2::cmds::DeleteSamplersImmediate*>(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* samplers =
+      GetImmediateDataAs<const GLuint*>(c, data_size, immediate_data_size);
+  if (samplers == NULL) {
+    return error::kOutOfBounds;
+  }
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    GLuint service_id = 0;
+    if (group_->GetSamplerServiceId(samplers[ii], &service_id)) {
+      glDeleteSamplers(1, &service_id);
+      group_->RemoveSamplerId(samplers[ii]);
+    }
+  }
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleDeleteTexturesImmediate(
     uint32_t immediate_data_size,
     const void* cmd_data) {
@@ -636,6 +693,35 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleDeleteTransformFeedbacksImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::DeleteTransformFeedbacksImmediate& c =
+      *static_cast<const gles2::cmds::DeleteTransformFeedbacksImmediate*>(
+          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* ids =
+      GetImmediateDataAs<const GLuint*>(c, data_size, immediate_data_size);
+  if (ids == NULL) {
+    return error::kOutOfBounds;
+  }
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    GLuint service_id = 0;
+    if (group_->GetTransformFeedbackServiceId(ids[ii], &service_id)) {
+      glDeleteTransformFeedbacks(1, &service_id);
+      group_->RemoveTransformFeedbackId(ids[ii]);
+    }
+  }
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleDepthFunc(uint32_t immediate_data_size,
                                                const void* cmd_data) {
   const gles2::cmds::DepthFunc& c =
@@ -934,6 +1020,37 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleGenSamplersImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GenSamplersImmediate& c =
+      *static_cast<const gles2::cmds::GenSamplersImmediate*>(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* samplers =
+      GetImmediateDataAs<GLuint*>(c, data_size, immediate_data_size);
+  if (samplers == NULL) {
+    return error::kOutOfBounds;
+  }
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    if (group_->GetSamplerServiceId(samplers[ii], NULL)) {
+      return error::kInvalidArguments;
+    }
+  }
+  scoped_ptr<GLuint[]> service_ids(new GLuint[n]);
+  glGenSamplers(n, service_ids.get());
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    group_->AddSamplerId(samplers[ii], service_ids[ii]);
+  }
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleGenTexturesImmediate(
     uint32_t immediate_data_size,
     const void* cmd_data) {
@@ -956,6 +1073,37 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleGenTransformFeedbacksImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GenTransformFeedbacksImmediate& c =
+      *static_cast<const gles2::cmds::GenTransformFeedbacksImmediate*>(
+          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* ids = GetImmediateDataAs<GLuint*>(c, data_size, immediate_data_size);
+  if (ids == NULL) {
+    return error::kOutOfBounds;
+  }
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    if (group_->GetTransformFeedbackServiceId(ids[ii], NULL)) {
+      return error::kInvalidArguments;
+    }
+  }
+  scoped_ptr<GLuint[]> service_ids(new GLuint[n]);
+  glGenTransformFeedbacks(n, service_ids.get());
+  for (GLsizei ii = 0; ii < n; ++ii) {
+    group_->AddTransformFeedbackId(ids[ii], service_ids[ii]);
+  }
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleGetBooleanv(uint32_t immediate_data_size,
                                                  const void* cmd_data) {
   const gles2::cmds::GetBooleanv& c =
@@ -1273,6 +1421,76 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleGetSamplerParameterfv(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GetSamplerParameterfv& c =
+      *static_cast<const gles2::cmds::GetSamplerParameterfv*>(cmd_data);
+  (void)c;
+  GLuint sampler = c.sampler;
+  GLenum pname = static_cast<GLenum>(c.pname);
+  typedef cmds::GetSamplerParameterfv::Result Result;
+  GLsizei num_values = 0;
+  GetNumValuesReturnedForGLGet(pname, &num_values);
+  Result* result = GetSharedMemoryAs<Result*>(
+      c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+  GLfloat* params = result ? result->GetData() : NULL;
+  if (params == NULL) {
+    return error::kOutOfBounds;
+  }
+  LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetSamplerParameterfv");
+  // Check that the client initialized the result.
+  if (result->size != 0) {
+    return error::kInvalidArguments;
+  }
+  group_->GetSamplerServiceId(sampler, &sampler);
+  glGetSamplerParameterfv(sampler, pname, params);
+  GLenum error = glGetError();
+  if (error == GL_NO_ERROR) {
+    result->SetNumResults(num_values);
+  } else {
+    LOCAL_SET_GL_ERROR(error, "GetSamplerParameterfv", "");
+  }
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetSamplerParameteriv(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GetSamplerParameteriv& c =
+      *static_cast<const gles2::cmds::GetSamplerParameteriv*>(cmd_data);
+  (void)c;
+  GLuint sampler = c.sampler;
+  GLenum pname = static_cast<GLenum>(c.pname);
+  typedef cmds::GetSamplerParameteriv::Result Result;
+  GLsizei num_values = 0;
+  GetNumValuesReturnedForGLGet(pname, &num_values);
+  Result* result = GetSharedMemoryAs<Result*>(
+      c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+  GLint* params = result ? result->GetData() : NULL;
+  if (params == NULL) {
+    return error::kOutOfBounds;
+  }
+  LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetSamplerParameteriv");
+  // Check that the client initialized the result.
+  if (result->size != 0) {
+    return error::kInvalidArguments;
+  }
+  group_->GetSamplerServiceId(sampler, &sampler);
+  glGetSamplerParameteriv(sampler, pname, params);
+  GLenum error = glGetError();
+  if (error == GL_NO_ERROR) {
+    result->SetNumResults(num_values);
+  } else {
+    LOCAL_SET_GL_ERROR(error, "GetSamplerParameteriv", "");
+  }
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleGetShaderiv(uint32_t immediate_data_size,
                                                  const void* cmd_data) {
   const gles2::cmds::GetShaderiv& c =
@@ -1646,6 +1864,25 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleIsSampler(uint32_t immediate_data_size,
+                                               const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::IsSampler& c =
+      *static_cast<const gles2::cmds::IsSampler*>(cmd_data);
+  (void)c;
+  GLuint sampler = c.sampler;
+  typedef cmds::IsSampler::Result Result;
+  Result* result_dst = GetSharedMemoryAs<Result*>(
+      c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+  if (!result_dst) {
+    return error::kOutOfBounds;
+  }
+  group_->GetSamplerServiceId(sampler, &sampler);
+  *result_dst = glIsSampler(sampler);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleIsShader(uint32_t immediate_data_size,
                                               const void* cmd_data) {
   const gles2::cmds::IsShader& c =
@@ -1678,6 +1915,26 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleIsTransformFeedback(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::IsTransformFeedback& c =
+      *static_cast<const gles2::cmds::IsTransformFeedback*>(cmd_data);
+  (void)c;
+  GLuint transformfeedback = c.transformfeedback;
+  typedef cmds::IsTransformFeedback::Result Result;
+  Result* result_dst = GetSharedMemoryAs<Result*>(
+      c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+  if (!result_dst) {
+    return error::kOutOfBounds;
+  }
+  group_->GetTransformFeedbackServiceId(transformfeedback, &transformfeedback);
+  *result_dst = glIsTransformFeedback(transformfeedback);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleLineWidth(uint32_t immediate_data_size,
                                                const void* cmd_data) {
   const gles2::cmds::LineWidth& c =
@@ -1705,6 +1962,18 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandlePauseTransformFeedback(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::PauseTransformFeedback& c =
+      *static_cast<const gles2::cmds::PauseTransformFeedback*>(cmd_data);
+  (void)c;
+  glPauseTransformFeedback();
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandlePolygonOffset(uint32_t immediate_data_size,
                                                    const void* cmd_data) {
   const gles2::cmds::PolygonOffset& c =
@@ -1774,6 +2043,18 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleResumeTransformFeedback(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::ResumeTransformFeedback& c =
+      *static_cast<const gles2::cmds::ResumeTransformFeedback*>(cmd_data);
+  (void)c;
+  glResumeTransformFeedback();
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleSampleCoverage(
     uint32_t immediate_data_size,
     const void* cmd_data) {
@@ -1786,6 +2067,91 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleSamplerParameterf(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::SamplerParameterf& c =
+      *static_cast<const gles2::cmds::SamplerParameterf*>(cmd_data);
+  (void)c;
+  GLuint sampler = c.sampler;
+  GLenum pname = static_cast<GLenum>(c.pname);
+  GLfloat param = static_cast<GLfloat>(c.param);
+  group_->GetSamplerServiceId(sampler, &sampler);
+  glSamplerParameterf(sampler, pname, param);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleSamplerParameterfvImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::SamplerParameterfvImmediate& c =
+      *static_cast<const gles2::cmds::SamplerParameterfvImmediate*>(cmd_data);
+  (void)c;
+  GLuint sampler = c.sampler;
+  GLenum pname = static_cast<GLenum>(c.pname);
+  uint32_t data_size;
+  if (!ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+    return error::kOutOfBounds;
+  }
+  if (data_size > immediate_data_size) {
+    return error::kOutOfBounds;
+  }
+  const GLfloat* params =
+      GetImmediateDataAs<const GLfloat*>(c, data_size, immediate_data_size);
+  if (params == NULL) {
+    return error::kOutOfBounds;
+  }
+  group_->GetSamplerServiceId(sampler, &sampler);
+  DoSamplerParameterfv(sampler, pname, params);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleSamplerParameteri(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::SamplerParameteri& c =
+      *static_cast<const gles2::cmds::SamplerParameteri*>(cmd_data);
+  (void)c;
+  GLuint sampler = c.sampler;
+  GLenum pname = static_cast<GLenum>(c.pname);
+  GLint param = static_cast<GLint>(c.param);
+  group_->GetSamplerServiceId(sampler, &sampler);
+  glSamplerParameteri(sampler, pname, param);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleSamplerParameterivImmediate(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::SamplerParameterivImmediate& c =
+      *static_cast<const gles2::cmds::SamplerParameterivImmediate*>(cmd_data);
+  (void)c;
+  GLuint sampler = c.sampler;
+  GLenum pname = static_cast<GLenum>(c.pname);
+  uint32_t data_size;
+  if (!ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+    return error::kOutOfBounds;
+  }
+  if (data_size > immediate_data_size) {
+    return error::kOutOfBounds;
+  }
+  const GLint* params =
+      GetImmediateDataAs<const GLint*>(c, data_size, immediate_data_size);
+  if (params == NULL) {
+    return error::kOutOfBounds;
+  }
+  DoSamplerParameteriv(sampler, pname, params);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleScissor(uint32_t immediate_data_size,
                                              const void* cmd_data) {
   const gles2::cmds::Scissor& c =
@@ -3416,6 +3782,31 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleBeginTransformFeedback(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::BeginTransformFeedback& c =
+      *static_cast<const gles2::cmds::BeginTransformFeedback*>(cmd_data);
+  (void)c;
+  GLenum primitivemode = static_cast<GLenum>(c.primitivemode);
+  glBeginTransformFeedback(primitivemode);
+  return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleEndTransformFeedback(
+    uint32_t immediate_data_size,
+    const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::EndTransformFeedback& c =
+      *static_cast<const gles2::cmds::EndTransformFeedback*>(cmd_data);
+  (void)c;
+  glEndTransformFeedback();
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleInsertEventMarkerEXT(
     uint32_t immediate_data_size,
     const void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
index 014007a..2bc23a0 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -124,6 +124,18 @@
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
 
+TEST_P(GLES2DecoderTest1, BindSamplerValidArgs) {
+  EXPECT_CALL(*gl_, BindSampler(1, kServiceSamplerId));
+  SpecializedSetup<cmds::BindSampler, 0>(true);
+  cmds::BindSampler cmd;
+  cmd.Init(1, client_sampler_id_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
 TEST_P(GLES2DecoderTest1, BindTextureValidArgs) {
   EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId));
   SpecializedSetup<cmds::BindTexture, 0>(true);
@@ -163,6 +175,19 @@
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
 
+TEST_P(GLES2DecoderTest1, BindTransformFeedbackValidArgs) {
+  EXPECT_CALL(*gl_, BindTransformFeedback(GL_TRANSFORM_FEEDBACK,
+                                          kServiceTransformFeedbackId));
+  SpecializedSetup<cmds::BindTransformFeedback, 0>(true);
+  cmds::BindTransformFeedback cmd;
+  cmd.Init(GL_TRANSFORM_FEEDBACK, client_transformfeedback_id_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
 TEST_P(GLES2DecoderTest1, BlendColorValidArgs) {
   EXPECT_CALL(*gl_, BlendColor(1, 2, 3, 4));
   SpecializedSetup<cmds::BlendColor, 0>(true);
@@ -515,6 +540,34 @@
   EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
 }
 
+TEST_P(GLES2DecoderTest1, DeleteSamplersImmediateValidArgs) {
+  EXPECT_CALL(*gl_, DeleteSamplers(1, Pointee(kServiceSamplerId))).Times(1);
+  cmds::DeleteSamplersImmediate& cmd =
+      *GetImmediateAs<cmds::DeleteSamplersImmediate>();
+  SpecializedSetup<cmds::DeleteSamplersImmediate, 0>(true);
+  cmd.Init(1, &client_sampler_id_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError,
+            ExecuteImmediateCmd(cmd, sizeof(client_sampler_id_)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  EXPECT_FALSE(GetSamplerServiceId(client_sampler_id_, NULL));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand,
+            ExecuteImmediateCmd(cmd, sizeof(client_sampler_id_)));
+}
+
+TEST_P(GLES2DecoderTest1, DeleteSamplersImmediateInvalidArgs) {
+  cmds::DeleteSamplersImmediate& cmd =
+      *GetImmediateAs<cmds::DeleteSamplersImmediate>();
+  SpecializedSetup<cmds::DeleteSamplersImmediate, 0>(false);
+  GLuint temp = kInvalidClientId;
+  cmd.Init(1, &temp);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+
 TEST_P(GLES2DecoderTest1, DeleteShaderValidArgs) {
   EXPECT_CALL(*gl_, DeleteShader(kServiceShaderId));
   SpecializedSetup<cmds::DeleteShader, 0>(true);
@@ -545,6 +598,36 @@
   EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
 }
 
+TEST_P(GLES2DecoderTest1, DeleteTransformFeedbacksImmediateValidArgs) {
+  EXPECT_CALL(*gl_, DeleteTransformFeedbacks(
+                        1, Pointee(kServiceTransformFeedbackId))).Times(1);
+  cmds::DeleteTransformFeedbacksImmediate& cmd =
+      *GetImmediateAs<cmds::DeleteTransformFeedbacksImmediate>();
+  SpecializedSetup<cmds::DeleteTransformFeedbacksImmediate, 0>(true);
+  cmd.Init(1, &client_transformfeedback_id_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError,
+            ExecuteImmediateCmd(cmd, sizeof(client_transformfeedback_id_)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  EXPECT_FALSE(
+      GetTransformFeedbackServiceId(client_transformfeedback_id_, NULL));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand,
+            ExecuteImmediateCmd(cmd, sizeof(client_transformfeedback_id_)));
+}
+
+TEST_P(GLES2DecoderTest1, DeleteTransformFeedbacksImmediateInvalidArgs) {
+  cmds::DeleteTransformFeedbacksImmediate& cmd =
+      *GetImmediateAs<cmds::DeleteTransformFeedbacksImmediate>();
+  SpecializedSetup<cmds::DeleteTransformFeedbacksImmediate, 0>(false);
+  GLuint temp = kInvalidClientId;
+  cmd.Init(1, &temp);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+
 TEST_P(GLES2DecoderTest1, DepthFuncValidArgs) {
   EXPECT_CALL(*gl_, DepthFunc(GL_NEVER));
   SpecializedSetup<cmds::DepthFunc, 0>(true);
@@ -874,6 +957,36 @@
             ExecuteImmediateCmd(*cmd, sizeof(&client_renderbuffer_id_)));
 }
 
+TEST_P(GLES2DecoderTest1, GenSamplersImmediateValidArgs) {
+  EXPECT_CALL(*gl_, GenSamplers(1, _))
+      .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+  cmds::GenSamplersImmediate* cmd =
+      GetImmediateAs<cmds::GenSamplersImmediate>();
+  GLuint temp = kNewClientId;
+  SpecializedSetup<cmds::GenSamplersImmediate, 0>(true);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  cmd->Init(1, &temp);
+  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(*cmd, sizeof(temp)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  GLuint service_id;
+  EXPECT_TRUE(GetSamplerServiceId(kNewClientId, &service_id));
+  EXPECT_EQ(kNewServiceId, service_id);
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteImmediateCmd(*cmd, sizeof(temp)));
+}
+
+TEST_P(GLES2DecoderTest1, GenSamplersImmediateInvalidArgs) {
+  EXPECT_CALL(*gl_, GenSamplers(_, _)).Times(0);
+  cmds::GenSamplersImmediate* cmd =
+      GetImmediateAs<cmds::GenSamplersImmediate>();
+  SpecializedSetup<cmds::GenSamplersImmediate, 0>(false);
+  cmd->Init(1, &client_sampler_id_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kInvalidArguments,
+            ExecuteImmediateCmd(*cmd, sizeof(&client_sampler_id_)));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+}
+
 TEST_P(GLES2DecoderTest1, GenTexturesImmediateValidArgs) {
   EXPECT_CALL(*gl_, GenTextures(1, _))
       .WillOnce(SetArgumentPointee<1>(kNewServiceId));
@@ -896,6 +1009,36 @@
   EXPECT_EQ(error::kInvalidArguments,
             ExecuteImmediateCmd(*cmd, sizeof(&client_texture_id_)));
 }
+
+TEST_P(GLES2DecoderTest1, GenTransformFeedbacksImmediateValidArgs) {
+  EXPECT_CALL(*gl_, GenTransformFeedbacks(1, _))
+      .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+  cmds::GenTransformFeedbacksImmediate* cmd =
+      GetImmediateAs<cmds::GenTransformFeedbacksImmediate>();
+  GLuint temp = kNewClientId;
+  SpecializedSetup<cmds::GenTransformFeedbacksImmediate, 0>(true);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  cmd->Init(1, &temp);
+  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(*cmd, sizeof(temp)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  GLuint service_id;
+  EXPECT_TRUE(GetTransformFeedbackServiceId(kNewClientId, &service_id));
+  EXPECT_EQ(kNewServiceId, service_id);
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteImmediateCmd(*cmd, sizeof(temp)));
+}
+
+TEST_P(GLES2DecoderTest1, GenTransformFeedbacksImmediateInvalidArgs) {
+  EXPECT_CALL(*gl_, GenTransformFeedbacks(_, _)).Times(0);
+  cmds::GenTransformFeedbacksImmediate* cmd =
+      GetImmediateAs<cmds::GenTransformFeedbacksImmediate>();
+  SpecializedSetup<cmds::GenTransformFeedbacksImmediate, 0>(false);
+  cmd->Init(1, &client_transformfeedback_id_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kInvalidArguments,
+            ExecuteImmediateCmd(*cmd, sizeof(&client_transformfeedback_id_)));
+  decoder_->set_unsafe_es3_apis_enabled(false);
+}
 // TODO(gman): GetActiveAttrib
 
 // TODO(gman): GetActiveUniform
@@ -1397,6 +1540,56 @@
   EXPECT_EQ(0u, result->size);
 }
 
+TEST_P(GLES2DecoderTest1, GetSamplerParameterfvValidArgs) {
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
+  SpecializedSetup<cmds::GetSamplerParameterfv, 0>(true);
+  typedef cmds::GetSamplerParameterfv::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  EXPECT_CALL(*gl_,
+              GetSamplerParameterfv(kServiceSamplerId, GL_TEXTURE_MAG_FILTER,
+                                    result->GetData()));
+  result->size = 0;
+  cmds::GetSamplerParameterfv cmd;
+  cmd.Init(client_sampler_id_, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+           shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(
+      decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_TEXTURE_MAG_FILTER),
+      result->GetNumResults());
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest1, GetSamplerParameterivValidArgs) {
+  EXPECT_CALL(*gl_, GetError())
+      .WillOnce(Return(GL_NO_ERROR))
+      .WillOnce(Return(GL_NO_ERROR))
+      .RetiresOnSaturation();
+  SpecializedSetup<cmds::GetSamplerParameteriv, 0>(true);
+  typedef cmds::GetSamplerParameteriv::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  EXPECT_CALL(*gl_,
+              GetSamplerParameteriv(kServiceSamplerId, GL_TEXTURE_MAG_FILTER,
+                                    result->GetData()));
+  result->size = 0;
+  cmds::GetSamplerParameteriv cmd;
+  cmd.Init(client_sampler_id_, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+           shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(
+      decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_TEXTURE_MAG_FILTER),
+      result->GetNumResults());
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
 TEST_P(GLES2DecoderTest1, GetShaderivValidArgs) {
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -1752,129 +1945,4 @@
   cmd.Init(GL_BLEND, shared_memory_id_, kInvalidSharedMemoryOffset);
   EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
 }
-
-TEST_P(GLES2DecoderTest1, IsFramebufferValidArgs) {
-  SpecializedSetup<cmds::IsFramebuffer, 0>(true);
-  cmds::IsFramebuffer cmd;
-  cmd.Init(client_framebuffer_id_, shared_memory_id_, shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, IsFramebufferInvalidArgsBadSharedMemoryId) {
-  SpecializedSetup<cmds::IsFramebuffer, 0>(false);
-  cmds::IsFramebuffer cmd;
-  cmd.Init(client_framebuffer_id_, kInvalidSharedMemoryId,
-           shared_memory_offset_);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  cmd.Init(client_framebuffer_id_, shared_memory_id_,
-           kInvalidSharedMemoryOffset);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-}
-
-TEST_P(GLES2DecoderTest1, IsProgramValidArgs) {
-  SpecializedSetup<cmds::IsProgram, 0>(true);
-  cmds::IsProgram cmd;
-  cmd.Init(client_program_id_, shared_memory_id_, shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, IsProgramInvalidArgsBadSharedMemoryId) {
-  SpecializedSetup<cmds::IsProgram, 0>(false);
-  cmds::IsProgram cmd;
-  cmd.Init(client_program_id_, kInvalidSharedMemoryId, shared_memory_offset_);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  cmd.Init(client_program_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-}
-
-TEST_P(GLES2DecoderTest1, IsRenderbufferValidArgs) {
-  SpecializedSetup<cmds::IsRenderbuffer, 0>(true);
-  cmds::IsRenderbuffer cmd;
-  cmd.Init(client_renderbuffer_id_, shared_memory_id_, shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, IsRenderbufferInvalidArgsBadSharedMemoryId) {
-  SpecializedSetup<cmds::IsRenderbuffer, 0>(false);
-  cmds::IsRenderbuffer cmd;
-  cmd.Init(client_renderbuffer_id_, kInvalidSharedMemoryId,
-           shared_memory_offset_);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  cmd.Init(client_renderbuffer_id_, shared_memory_id_,
-           kInvalidSharedMemoryOffset);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-}
-
-TEST_P(GLES2DecoderTest1, IsShaderValidArgs) {
-  SpecializedSetup<cmds::IsShader, 0>(true);
-  cmds::IsShader cmd;
-  cmd.Init(client_shader_id_, shared_memory_id_, shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, IsShaderInvalidArgsBadSharedMemoryId) {
-  SpecializedSetup<cmds::IsShader, 0>(false);
-  cmds::IsShader cmd;
-  cmd.Init(client_shader_id_, kInvalidSharedMemoryId, shared_memory_offset_);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  cmd.Init(client_shader_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-}
-
-TEST_P(GLES2DecoderTest1, IsTextureValidArgs) {
-  SpecializedSetup<cmds::IsTexture, 0>(true);
-  cmds::IsTexture cmd;
-  cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, IsTextureInvalidArgsBadSharedMemoryId) {
-  SpecializedSetup<cmds::IsTexture, 0>(false);
-  cmds::IsTexture cmd;
-  cmd.Init(client_texture_id_, kInvalidSharedMemoryId, shared_memory_offset_);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-  cmd.Init(client_texture_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
-  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
-}
-
-TEST_P(GLES2DecoderTest1, LineWidthValidArgs) {
-  EXPECT_CALL(*gl_, LineWidth(0.5f));
-  SpecializedSetup<cmds::LineWidth, 0>(true);
-  cmds::LineWidth cmd;
-  cmd.Init(0.5f);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, LineWidthInvalidValue0_0) {
-  SpecializedSetup<cmds::LineWidth, 0>(false);
-  cmds::LineWidth cmd;
-  cmd.Init(0.0f);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, LineWidthNaNValue0) {
-  SpecializedSetup<cmds::LineWidth, 0>(false);
-  cmds::LineWidth cmd;
-  cmd.Init(nanf(""));
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
-}
-
-TEST_P(GLES2DecoderTest1, LinkProgramValidArgs) {
-  EXPECT_CALL(*gl_, LinkProgram(kServiceProgramId));
-  SpecializedSetup<cmds::LinkProgram, 0>(true);
-  cmds::LinkProgram cmd;
-  cmd.Init(client_program_id_);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
-// TODO(gman): PixelStorei
-
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_1_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
index 602be42..6f8b706 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
@@ -12,6 +12,193 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
 
+TEST_P(GLES2DecoderTest2, IsFramebufferValidArgs) {
+  SpecializedSetup<cmds::IsFramebuffer, 0>(true);
+  cmds::IsFramebuffer cmd;
+  cmd.Init(client_framebuffer_id_, shared_memory_id_, shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, IsFramebufferInvalidArgsBadSharedMemoryId) {
+  SpecializedSetup<cmds::IsFramebuffer, 0>(false);
+  cmds::IsFramebuffer cmd;
+  cmd.Init(client_framebuffer_id_, kInvalidSharedMemoryId,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  cmd.Init(client_framebuffer_id_, shared_memory_id_,
+           kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest2, IsProgramValidArgs) {
+  SpecializedSetup<cmds::IsProgram, 0>(true);
+  cmds::IsProgram cmd;
+  cmd.Init(client_program_id_, shared_memory_id_, shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, IsProgramInvalidArgsBadSharedMemoryId) {
+  SpecializedSetup<cmds::IsProgram, 0>(false);
+  cmds::IsProgram cmd;
+  cmd.Init(client_program_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  cmd.Init(client_program_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest2, IsRenderbufferValidArgs) {
+  SpecializedSetup<cmds::IsRenderbuffer, 0>(true);
+  cmds::IsRenderbuffer cmd;
+  cmd.Init(client_renderbuffer_id_, shared_memory_id_, shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, IsRenderbufferInvalidArgsBadSharedMemoryId) {
+  SpecializedSetup<cmds::IsRenderbuffer, 0>(false);
+  cmds::IsRenderbuffer cmd;
+  cmd.Init(client_renderbuffer_id_, kInvalidSharedMemoryId,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  cmd.Init(client_renderbuffer_id_, shared_memory_id_,
+           kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest2, IsSamplerValidArgs) {
+  EXPECT_CALL(*gl_, IsSampler(kServiceSamplerId));
+  SpecializedSetup<cmds::IsSampler, 0>(true);
+  cmds::IsSampler cmd;
+  cmd.Init(client_sampler_id_, shared_memory_id_, shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest2, IsSamplerInvalidArgsBadSharedMemoryId) {
+  EXPECT_CALL(*gl_, IsSampler(kServiceSamplerId)).Times(0);
+  SpecializedSetup<cmds::IsSampler, 0>(false);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  cmds::IsSampler cmd;
+  cmd.Init(client_sampler_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  cmd.Init(client_sampler_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  decoder_->set_unsafe_es3_apis_enabled(true);
+}
+
+TEST_P(GLES2DecoderTest2, IsShaderValidArgs) {
+  SpecializedSetup<cmds::IsShader, 0>(true);
+  cmds::IsShader cmd;
+  cmd.Init(client_shader_id_, shared_memory_id_, shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, IsShaderInvalidArgsBadSharedMemoryId) {
+  SpecializedSetup<cmds::IsShader, 0>(false);
+  cmds::IsShader cmd;
+  cmd.Init(client_shader_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  cmd.Init(client_shader_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest2, IsTextureValidArgs) {
+  SpecializedSetup<cmds::IsTexture, 0>(true);
+  cmds::IsTexture cmd;
+  cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, IsTextureInvalidArgsBadSharedMemoryId) {
+  SpecializedSetup<cmds::IsTexture, 0>(false);
+  cmds::IsTexture cmd;
+  cmd.Init(client_texture_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  cmd.Init(client_texture_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest2, IsTransformFeedbackValidArgs) {
+  EXPECT_CALL(*gl_, IsTransformFeedback(kServiceTransformFeedbackId));
+  SpecializedSetup<cmds::IsTransformFeedback, 0>(true);
+  cmds::IsTransformFeedback cmd;
+  cmd.Init(client_transformfeedback_id_, shared_memory_id_,
+           shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest2, IsTransformFeedbackInvalidArgsBadSharedMemoryId) {
+  EXPECT_CALL(*gl_, IsTransformFeedback(kServiceTransformFeedbackId)).Times(0);
+  SpecializedSetup<cmds::IsTransformFeedback, 0>(false);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  cmds::IsTransformFeedback cmd;
+  cmd.Init(client_transformfeedback_id_, kInvalidSharedMemoryId,
+           shared_memory_offset_);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  cmd.Init(client_transformfeedback_id_, shared_memory_id_,
+           kInvalidSharedMemoryOffset);
+  EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+  decoder_->set_unsafe_es3_apis_enabled(true);
+}
+
+TEST_P(GLES2DecoderTest2, LineWidthValidArgs) {
+  EXPECT_CALL(*gl_, LineWidth(0.5f));
+  SpecializedSetup<cmds::LineWidth, 0>(true);
+  cmds::LineWidth cmd;
+  cmd.Init(0.5f);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, LineWidthInvalidValue0_0) {
+  SpecializedSetup<cmds::LineWidth, 0>(false);
+  cmds::LineWidth cmd;
+  cmd.Init(0.0f);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, LineWidthNaNValue0) {
+  SpecializedSetup<cmds::LineWidth, 0>(false);
+  cmds::LineWidth cmd;
+  cmd.Init(nanf(""));
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, LinkProgramValidArgs) {
+  EXPECT_CALL(*gl_, LinkProgram(kServiceProgramId));
+  SpecializedSetup<cmds::LinkProgram, 0>(true);
+  cmds::LinkProgram cmd;
+  cmd.Init(client_program_id_);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, PauseTransformFeedbackValidArgs) {
+  EXPECT_CALL(*gl_, PauseTransformFeedback());
+  SpecializedSetup<cmds::PauseTransformFeedback, 0>(true);
+  cmds::PauseTransformFeedback cmd;
+  cmd.Init();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+// TODO(gman): PixelStorei
+
 TEST_P(GLES2DecoderTest2, PolygonOffsetValidArgs) {
   EXPECT_CALL(*gl_, PolygonOffset(1, 2));
   SpecializedSetup<cmds::PolygonOffset, 0>(true);
@@ -71,6 +258,18 @@
   EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
 }
 
+TEST_P(GLES2DecoderTest2, ResumeTransformFeedbackValidArgs) {
+  EXPECT_CALL(*gl_, ResumeTransformFeedback());
+  SpecializedSetup<cmds::ResumeTransformFeedback, 0>(true);
+  cmds::ResumeTransformFeedback cmd;
+  cmd.Init();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
 TEST_P(GLES2DecoderTest2, SampleCoverageValidArgs) {
   EXPECT_CALL(*gl_, SampleCoverage(1, true));
   SpecializedSetup<cmds::SampleCoverage, 0>(true);
@@ -80,6 +279,68 @@
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
 }
 
+TEST_P(GLES2DecoderTest2, SamplerParameterfValidArgs) {
+  EXPECT_CALL(*gl_, SamplerParameterf(kServiceSamplerId, GL_TEXTURE_MAG_FILTER,
+                                      GL_NEAREST));
+  SpecializedSetup<cmds::SamplerParameterf, 0>(true);
+  cmds::SamplerParameterf cmd;
+  cmd.Init(client_sampler_id_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest2, SamplerParameterfvImmediateValidArgs) {
+  cmds::SamplerParameterfvImmediate& cmd =
+      *GetImmediateAs<cmds::SamplerParameterfvImmediate>();
+  SpecializedSetup<cmds::SamplerParameterfvImmediate, 0>(true);
+  GLfloat temp[1] = {
+      GL_NEAREST,
+  };
+  cmd.Init(kServiceSamplerId, GL_TEXTURE_MAG_FILTER, &temp[0]);
+  EXPECT_CALL(*gl_, SamplerParameterf(kServiceSamplerId, GL_TEXTURE_MAG_FILTER,
+                                      *reinterpret_cast<GLfloat*>(
+                                          ImmediateDataAddress(&cmd))));
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+
+TEST_P(GLES2DecoderTest2, SamplerParameteriValidArgs) {
+  EXPECT_CALL(*gl_, SamplerParameteri(kServiceSamplerId, GL_TEXTURE_MAG_FILTER,
+                                      GL_NEAREST));
+  SpecializedSetup<cmds::SamplerParameteri, 0>(true);
+  cmds::SamplerParameteri cmd;
+  cmd.Init(client_sampler_id_, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest2, SamplerParameterivImmediateValidArgs) {
+  cmds::SamplerParameterivImmediate& cmd =
+      *GetImmediateAs<cmds::SamplerParameterivImmediate>();
+  SpecializedSetup<cmds::SamplerParameterivImmediate, 0>(true);
+  GLint temp[1] = {
+      GL_NEAREST,
+  };
+  cmd.Init(kServiceSamplerId, GL_TEXTURE_MAG_FILTER, &temp[0]);
+  EXPECT_CALL(*gl_, SamplerParameteri(
+                        kServiceSamplerId, GL_TEXTURE_MAG_FILTER,
+                        *reinterpret_cast<GLint*>(ImmediateDataAddress(&cmd))));
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+
 TEST_P(GLES2DecoderTest2, ScissorValidArgs) {
   EXPECT_CALL(*gl_, Scissor(1, 2, 3, 4));
   SpecializedSetup<cmds::Scissor, 0>(true);
@@ -220,12 +481,14 @@
   cmds::TexParameterfvImmediate& cmd =
       *GetImmediateAs<cmds::TexParameterfvImmediate>();
   EXPECT_CALL(*gl_, TexParameterf(_, _, _)).Times(0);
+
   SpecializedSetup<cmds::TexParameterfvImmediate, 0>(false);
   GLfloat temp[1] = {
       GL_NEAREST,
   };
   cmd.Init(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, &temp[0]);
   EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
 
@@ -233,12 +496,14 @@
   cmds::TexParameterfvImmediate& cmd =
       *GetImmediateAs<cmds::TexParameterfvImmediate>();
   EXPECT_CALL(*gl_, TexParameterf(_, _, _)).Times(0);
+
   SpecializedSetup<cmds::TexParameterfvImmediate, 0>(false);
   GLfloat temp[1] = {
       GL_NEAREST,
   };
   cmd.Init(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, &temp[0]);
   EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
 
@@ -246,12 +511,14 @@
   cmds::TexParameterfvImmediate& cmd =
       *GetImmediateAs<cmds::TexParameterfvImmediate>();
   EXPECT_CALL(*gl_, TexParameterf(_, _, _)).Times(0);
+
   SpecializedSetup<cmds::TexParameterfvImmediate, 0>(false);
   GLfloat temp[1] = {
       GL_NEAREST,
   };
   cmd.Init(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, &temp[0]);
   EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
 
@@ -311,12 +578,14 @@
   cmds::TexParameterivImmediate& cmd =
       *GetImmediateAs<cmds::TexParameterivImmediate>();
   EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+
   SpecializedSetup<cmds::TexParameterivImmediate, 0>(false);
   GLint temp[1] = {
       GL_NEAREST,
   };
   cmd.Init(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, &temp[0]);
   EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
 
@@ -324,12 +593,14 @@
   cmds::TexParameterivImmediate& cmd =
       *GetImmediateAs<cmds::TexParameterivImmediate>();
   EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+
   SpecializedSetup<cmds::TexParameterivImmediate, 0>(false);
   GLint temp[1] = {
       GL_NEAREST,
   };
   cmd.Init(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, &temp[0]);
   EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
 
@@ -337,12 +608,14 @@
   cmds::TexParameterivImmediate& cmd =
       *GetImmediateAs<cmds::TexParameterivImmediate>();
   EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+
   SpecializedSetup<cmds::TexParameterivImmediate, 0>(false);
   GLint temp[1] = {
       GL_NEAREST,
   };
   cmd.Init(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, &temp[0]);
   EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+
   EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
 }
 
@@ -1006,35 +1279,17 @@
 // TODO(gman): DeleteQueriesEXTImmediate
 // TODO(gman): BeginQueryEXT
 
-// TODO(gman): EndQueryEXT
-
-// TODO(gman): InsertEventMarkerEXT
-
-// TODO(gman): PushGroupMarkerEXT
-
-TEST_P(GLES2DecoderTest2, PopGroupMarkerEXTValidArgs) {
-  SpecializedSetup<cmds::PopGroupMarkerEXT, 0>(true);
-  cmds::PopGroupMarkerEXT cmd;
-  cmd.Init();
+TEST_P(GLES2DecoderTest2, BeginTransformFeedbackValidArgs) {
+  EXPECT_CALL(*gl_, BeginTransformFeedback(GL_POINTS));
+  SpecializedSetup<cmds::BeginTransformFeedback, 0>(true);
+  cmds::BeginTransformFeedback cmd;
+  cmd.Init(GL_POINTS);
+  decoder_->set_unsafe_es3_apis_enabled(true);
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
 }
-// TODO(gman): GenVertexArraysOESImmediate
-// TODO(gman): DeleteVertexArraysOESImmediate
-// TODO(gman): IsVertexArrayOES
-// TODO(gman): BindVertexArrayOES
-// TODO(gman): SwapBuffers
-// TODO(gman): GetMaxValueInBufferCHROMIUM
-// TODO(gman): EnableFeatureCHROMIUM
+// TODO(gman): EndQueryEXT
 
-// TODO(gman): ResizeCHROMIUM
-// TODO(gman): GetRequestableExtensionsCHROMIUM
-
-// TODO(gman): RequestExtensionCHROMIUM
-
-// TODO(gman): GetProgramInfoCHROMIUM
-
-// TODO(gman): GetTranslatedShaderSourceANGLE
-// TODO(gman): PostSubBufferCHROMIUM
-// TODO(gman): TexImageIOSurface2DCHROMIUM
 #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 6de18e0..506e045 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -12,6 +12,46 @@
 #ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
 #define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
 
+TEST_P(GLES2DecoderTest3, EndTransformFeedbackValidArgs) {
+  EXPECT_CALL(*gl_, EndTransformFeedback());
+  SpecializedSetup<cmds::EndTransformFeedback, 0>(true);
+  cmds::EndTransformFeedback cmd;
+  cmd.Init();
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+// TODO(gman): InsertEventMarkerEXT
+
+// TODO(gman): PushGroupMarkerEXT
+
+TEST_P(GLES2DecoderTest3, PopGroupMarkerEXTValidArgs) {
+  SpecializedSetup<cmds::PopGroupMarkerEXT, 0>(true);
+  cmds::PopGroupMarkerEXT cmd;
+  cmd.Init();
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+// TODO(gman): GenVertexArraysOESImmediate
+// TODO(gman): DeleteVertexArraysOESImmediate
+// TODO(gman): IsVertexArrayOES
+// TODO(gman): BindVertexArrayOES
+// TODO(gman): SwapBuffers
+// TODO(gman): GetMaxValueInBufferCHROMIUM
+// TODO(gman): EnableFeatureCHROMIUM
+
+// TODO(gman): ResizeCHROMIUM
+// TODO(gman): GetRequestableExtensionsCHROMIUM
+
+// TODO(gman): RequestExtensionCHROMIUM
+
+// TODO(gman): GetProgramInfoCHROMIUM
+
+// TODO(gman): GetTranslatedShaderSourceANGLE
+// TODO(gman): PostSubBufferCHROMIUM
+// TODO(gman): TexImageIOSurface2DCHROMIUM
 // TODO(gman): CopyTextureCHROMIUM
 // TODO(gman): DrawArraysInstancedANGLE
 // TODO(gman): DrawElementsInstancedANGLE
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 017f36c..aeb4477 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -90,7 +90,8 @@
       client_framebuffer_id_(101),
       client_program_id_(102),
       client_renderbuffer_id_(103),
-      client_shader_id_(104),
+      client_sampler_id_(104),
+      client_shader_id_(105),
       client_texture_id_(106),
       client_element_buffer_id_(107),
       client_vertex_shader_id_(121),
@@ -98,6 +99,7 @@
       client_query_id_(123),
       client_vertexarray_id_(124),
       client_valuebuffer_id_(125),
+      client_transformfeedback_id_(126),
       service_renderbuffer_id_(0),
       service_renderbuffer_valid_(false),
       ignore_cached_state_for_test_(GetParam()),
@@ -413,6 +415,24 @@
   DoCreateProgram(client_program_id_, kServiceProgramId);
   DoCreateShader(GL_VERTEX_SHADER, client_shader_id_, kServiceShaderId);
 
+  // Unsafe commands.
+  bool reset_unsafe_es3_apis_enabled = false;
+  if (!decoder_->unsafe_es3_apis_enabled()) {
+    decoder_->set_unsafe_es3_apis_enabled(true);
+    reset_unsafe_es3_apis_enabled = true;
+  }
+  EXPECT_CALL(*gl_, GenSamplers(_, _))
+      .WillOnce(SetArgumentPointee<1>(kServiceSamplerId))
+      .RetiresOnSaturation();
+  GenHelper<cmds::GenSamplersImmediate>(client_sampler_id_);
+  EXPECT_CALL(*gl_, GenTransformFeedbacks(_, _))
+      .WillOnce(SetArgumentPointee<1>(kServiceTransformFeedbackId))
+      .RetiresOnSaturation();
+  GenHelper<cmds::GenTransformFeedbacksImmediate>(client_transformfeedback_id_);
+  if (reset_unsafe_es3_apis_enabled) {
+    decoder_->set_unsafe_es3_apis_enabled(false);
+  }
+
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
 }
 
@@ -1245,12 +1265,14 @@
 const GLuint GLES2DecoderTestBase::kServiceBufferId;
 const GLuint GLES2DecoderTestBase::kServiceFramebufferId;
 const GLuint GLES2DecoderTestBase::kServiceRenderbufferId;
+const GLuint GLES2DecoderTestBase::kServiceSamplerId;
 const GLuint GLES2DecoderTestBase::kServiceTextureId;
 const GLuint GLES2DecoderTestBase::kServiceProgramId;
 const GLuint GLES2DecoderTestBase::kServiceShaderId;
 const GLuint GLES2DecoderTestBase::kServiceElementBufferId;
 const GLuint GLES2DecoderTestBase::kServiceQueryId;
 const GLuint GLES2DecoderTestBase::kServiceVertexArrayId;
+const GLuint GLES2DecoderTestBase::kServiceTransformFeedbackId;
 
 const int32 GLES2DecoderTestBase::kSharedMemoryId;
 const size_t GLES2DecoderTestBase::kSharedBufferSize;
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 459f1e0..6d6ddd2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -131,6 +131,15 @@
     return decoder_->GetQueryManager()->GetQuery(client_id);
   }
 
+  bool GetSamplerServiceId(GLuint client_id, GLuint* service_id) const {
+    return group_->GetSamplerServiceId(client_id, service_id);
+  }
+
+  bool GetTransformFeedbackServiceId(
+      GLuint client_id, GLuint* service_id) const {
+    return group_->GetTransformFeedbackServiceId(client_id, service_id);
+  }
+
   // This name doesn't match the underlying function, but doing it this way
   // prevents the need to special-case the unit test generation
   VertexAttribManager* GetVertexArrayInfo(GLuint client_id) {
@@ -427,10 +436,12 @@
   static const GLuint kServiceRenderbufferId = 303;
   static const GLuint kServiceTextureId = 304;
   static const GLuint kServiceProgramId = 305;
-  static const GLuint kServiceShaderId = 306;
+  static const GLuint kServiceSamplerId = 306;
+  static const GLuint kServiceShaderId = 307;
   static const GLuint kServiceElementBufferId = 308;
   static const GLuint kServiceQueryId = 309;
   static const GLuint kServiceVertexArrayId = 310;
+  static const GLuint kServiceTransformFeedbackId = 311;
 
   static const int32 kSharedMemoryId = 401;
   static const size_t kSharedBufferSize = 2048;
@@ -520,6 +531,7 @@
   GLuint client_framebuffer_id_;
   GLuint client_program_id_;
   GLuint client_renderbuffer_id_;
+  GLuint client_sampler_id_;
   GLuint client_shader_id_;
   GLuint client_texture_id_;
   GLuint client_element_buffer_id_;
@@ -528,6 +540,7 @@
   GLuint client_query_id_;
   GLuint client_vertexarray_id_;
   GLuint client_valuebuffer_id_;
+  GLuint client_transformfeedback_id_;
 
   uint32 shared_memory_id_;
   uint32 shared_memory_offset_;
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
index 3436e96..fc650d2 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -49,6 +49,7 @@
 ValueValidator<GLenum> render_buffer_parameter;
 ValueValidator<GLenum> render_buffer_target;
 ValueValidator<GLenum> reset_status;
+ValueValidator<GLenum> sampler_parameter;
 ValueValidator<GLenum> shader_binary_format;
 ValueValidator<GLenum> shader_parameter;
 ValueValidator<GLenum> shader_precision;
@@ -69,6 +70,8 @@
 ValueValidator<GLenum> texture_target;
 ValueValidator<GLenum> texture_usage;
 ValueValidator<GLenum> texture_wrap_mode;
+ValueValidator<GLenum> transform_feedback_bind_target;
+ValueValidator<GLenum> transform_feedback_primitive_mode;
 ValueValidator<GLenum> value_buffer_target;
 ValueValidator<GLint> vertex_attrib_size;
 ValueValidator<GLenum> vertex_attrib_type;
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 d718391..a1e5c74 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -353,6 +353,18 @@
     GL_UNKNOWN_CONTEXT_RESET_ARB,
 };
 
+static const GLenum valid_sampler_parameter_table[] = {
+    GL_TEXTURE_MAG_FILTER,
+    GL_TEXTURE_MIN_FILTER,
+    GL_TEXTURE_MIN_LOD,
+    GL_TEXTURE_MAX_LOD,
+    GL_TEXTURE_WRAP_S,
+    GL_TEXTURE_WRAP_T,
+    GL_TEXTURE_WRAP_R,
+    GL_TEXTURE_COMPARE_MODE,
+    GL_TEXTURE_COMPARE_FUNC,
+};
+
 static const GLenum valid_shader_parameter_table[] = {
     GL_SHADER_TYPE,
     GL_DELETE_STATUS,
@@ -502,6 +514,16 @@
     GL_REPEAT,
 };
 
+static const GLenum valid_transform_feedback_bind_target_table[] = {
+    GL_TRANSFORM_FEEDBACK,
+};
+
+static const GLenum valid_transform_feedback_primitive_mode_table[] = {
+    GL_POINTS,
+    GL_LINES,
+    GL_TRIANGLES,
+};
+
 static const GLenum valid_value_buffer_target_table[] = {
     GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
 };
@@ -596,6 +618,8 @@
                            arraysize(valid_render_buffer_target_table)),
       reset_status(valid_reset_status_table,
                    arraysize(valid_reset_status_table)),
+      sampler_parameter(valid_sampler_parameter_table,
+                        arraysize(valid_sampler_parameter_table)),
       shader_binary_format(),
       shader_parameter(valid_shader_parameter_table,
                        arraysize(valid_shader_parameter_table)),
@@ -633,6 +657,12 @@
                     arraysize(valid_texture_usage_table)),
       texture_wrap_mode(valid_texture_wrap_mode_table,
                         arraysize(valid_texture_wrap_mode_table)),
+      transform_feedback_bind_target(
+          valid_transform_feedback_bind_target_table,
+          arraysize(valid_transform_feedback_bind_target_table)),
+      transform_feedback_primitive_mode(
+          valid_transform_feedback_primitive_mode_table,
+          arraysize(valid_transform_feedback_primitive_mode_table)),
       value_buffer_target(valid_value_buffer_target_table,
                           arraysize(valid_value_buffer_target_table)),
       vertex_attrib_size(valid_vertex_attrib_size_table,
diff --git a/gpu/command_buffer/service/gpu_switches.cc b/gpu/command_buffer/service/gpu_switches.cc
index 7298140..a2d43e9 100644
--- a/gpu/command_buffer/service/gpu_switches.cc
+++ b/gpu/command_buffer/service/gpu_switches.cc
@@ -68,6 +68,14 @@
 // Enable OpenGL ES 3 APIs without proper service side validation.
 const char kEnableUnsafeES3APIs[] = "enable-unsafe-es3-apis";
 
+// Include ANGLE's intermediate representation (AST) output in shader
+// compilation info logs.
+const char kGLShaderIntermOutput[] = "gl-shader-interm-output";
+
+// Emulate ESSL lowp and mediump float precisions by mutating the shaders to
+// round intermediate values in ANGLE.
+const char kEmulateShaderPrecision[] = "emulate-shader-precision";
+
 const char* kGpuSwitches[] = {
   kCompileShaderAlwaysSucceeds,
   kDisableGLErrorLimit,
@@ -86,6 +94,8 @@
   kEnableShareGroupAsyncTextureUpload,
   kEnableUnsafeES3APIs,
   kEnableSubscribeUniformExtension,
+  kGLShaderIntermOutput,
+  kEmulateShaderPrecision,
 };
 
 const int kNumGpuSwitches = arraysize(kGpuSwitches);
diff --git a/gpu/command_buffer/service/gpu_switches.h b/gpu/command_buffer/service/gpu_switches.h
index c7a34f6..5ed2861 100644
--- a/gpu/command_buffer/service/gpu_switches.h
+++ b/gpu/command_buffer/service/gpu_switches.h
@@ -29,6 +29,8 @@
 GPU_EXPORT extern const char kEnableSubscribeUniformExtension[];
 GPU_EXPORT extern const char kEnableThreadedTextureMailboxes[];
 GPU_EXPORT extern const char kEnableUnsafeES3APIs[];
+GPU_EXPORT extern const char kGLShaderIntermOutput[];
+GPU_EXPORT extern const char kEmulateShaderPrecision[];
 
 GPU_EXPORT extern const char* kGpuSwitches[];
 GPU_EXPORT extern const int kNumGpuSwitches;
diff --git a/gpu/command_buffer/service/shader_translator.cc b/gpu/command_buffer/service/shader_translator.cc
index 576c7c8..d7def00 100644
--- a/gpu/command_buffer/service/shader_translator.cc
+++ b/gpu/command_buffer/service/shader_translator.cc
@@ -14,7 +14,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
-#include "ui/gl/gl_switches.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
 
 namespace gpu {
 namespace gles2 {
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index b447c1a..8014746 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
 {
   "name": "gpu driver bug list",
   // Please update the version number whenever you change this file.
-  "version": "7.11",
+  "version": "7.12",
   "entries": [
     {
       "id": 1,
@@ -1081,6 +1081,17 @@
       "features": [
         "gl_clear_broken"
       ]
+    },
+    {
+      "id": 96,
+      "description": "glBindFramebuffer sometimes requires a glBegin/End to take effect",
+      "cr_bugs": [435786],
+      "os": {
+        "type": "macosx"
+      },
+      "features": [
+        "gl_begin_gl_end_on_fbo_change_to_backbuffer"
+      ]
     }
   ]
 }
diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h
index 841a470..77d721b 100644
--- a/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/gpu/config/gpu_driver_bug_workaround_type.h
@@ -54,6 +54,8 @@
          force_gl_finish_after_compositing)                  \
   GPU_OP(FORCE_INTEGRATED_GPU,                               \
          force_integrated_gpu)                               \
+  GPU_OP(GL_BEGIN_GL_END_ON_FBO_CHANGE_TO_BACKBUFFER,        \
+         gl_begin_gl_end_on_fbo_change_to_backbuffer)        \
   GPU_OP(GL_CLEAR_BROKEN,                                    \
          gl_clear_broken)                                    \
   GPU_OP(INIT_GL_POSITION_IN_VERTEX_SHADER,                  \
diff --git a/gpu/tools/compositor_model_bench/compositor_model_bench.cc b/gpu/tools/compositor_model_bench/compositor_model_bench.cc
index 5108a87..375bce2 100644
--- a/gpu/tools/compositor_model_bench/compositor_model_bench.cc
+++ b/gpu/tools/compositor_model_bench/compositor_model_bench.cc
@@ -61,12 +61,12 @@
      : current_sim_(NULL),
        output_path_(output_path),
        seconds_per_test_(seconds_per_test),
-       weak_factory_(this),
        display_(NULL),
        window_(0),
        gl_context_(NULL),
        window_width_(WINDOW_WIDTH),
-       window_height_(WINDOW_HEIGHT) {
+       window_height_(WINDOW_HEIGHT),
+       weak_factory_(this) {
   }
 
   ~Simulator() {
@@ -344,12 +344,12 @@
   // Amount of time to run each simulation
   int seconds_per_test_;
   // GUI data
-  base::WeakPtrFactory<Simulator> weak_factory_;
   Display* display_;
   Window window_;
   GLXContext gl_context_;
   int window_width_;
   int window_height_;
+  base::WeakPtrFactory<Simulator> weak_factory_;
 };
 
 int main(int argc, char* argv[]) {
diff --git a/mojo/converters/surfaces/surfaces_type_converters.cc b/mojo/converters/surfaces/surfaces_type_converters.cc
index 1a6ab99..4d563e1 100644
--- a/mojo/converters/surfaces/surfaces_type_converters.cc
+++ b/mojo/converters/surfaces/surfaces_type_converters.cc
@@ -158,7 +158,8 @@
                         tile_state->resource_id,
                         tile_state->tex_coord_rect.To<gfx::RectF>(),
                         tile_state->texture_size.To<gfx::Size>(),
-                        tile_state->swizzle_contents);
+                        tile_state->swizzle_contents,
+                        tile_state->nearest_neighbor);
       break;
     }
     case MATERIAL_YUV_VIDEO_CONTENT: {
diff --git a/mojo/public/python/BUILD.gn b/mojo/public/python/BUILD.gn
index 51bd6eb..70c2dca 100644
--- a/mojo/public/python/BUILD.gn
+++ b/mojo/public/python/BUILD.gn
@@ -16,44 +16,40 @@
 # GYP version: mojo.gyp:mojo_python_system
 python_binary_module("system") {
   python_base_module = "mojo"
-  sources = [
+  cython_sources = [
     "mojo/c_core.pxd",
     "mojo/system.pyx",
   ]
-  configs = [ "../build/config:mojo_sdk" ]
   deps = [
     ":base",
     "../c/environment",
-    "../c/system",
+    "../c/system:for_shared_library",
     "../cpp/environment:standalone",
     "../cpp/system",
     "../cpp/utility",
     "../cpp/bindings:callback",
-    "../platform/native:system",
   ]
 }
 
 python_binary_module("system_impl") {
   python_base_module = "mojo"
-  sources = [
+  cython_sources = [
     "mojo/c_core.pxd",
     "mojo/c_environment.pxd",
     "mojo/system_impl.pyx",
   ]
-  additional_sources = [
+  sources = [
     "src/python_system_helper.cc",
     "src/python_system_helper.h",
   ]
-  configs = [ "../build/config:mojo_sdk" ]
   deps = [
     ":base",
     "../c/environment",
-    "../c/system",
+    "../c/system:for_shared_library",
     "../cpp/environment:standalone",
     "../cpp/system",
     "../cpp/utility",
     "../cpp/bindings:callback",
-    "../platform/native:system",
   ]
 }
 
diff --git a/mojo/python/BUILD.gn b/mojo/python/BUILD.gn
index f96c2cc..8cbb5fa 100644
--- a/mojo/python/BUILD.gn
+++ b/mojo/python/BUILD.gn
@@ -16,7 +16,7 @@
 # GYP version: mojo/mojo.gyp:mojo_python_embedder
 python_binary_module("embedder") {
   python_base_module = "mojo"
-  sources = [
+  cython_sources = [
     "system/mojo/embedder.pyx",
   ]
   deps = [
@@ -38,7 +38,7 @@
 
 python_binary_module("validation_util") {
   python_base_module = "mojo/tests"
-  sources = [
+  cython_sources = [
     "system/mojo/tests/validation_util.pyx",
   ]
   deps = [
diff --git a/mojo/services/surfaces/public/interfaces/quads.mojom b/mojo/services/surfaces/public/interfaces/quads.mojom
index 88006f7..52a667d 100644
--- a/mojo/services/surfaces/public/interfaces/quads.mojom
+++ b/mojo/services/surfaces/public/interfaces/quads.mojom
@@ -72,6 +72,7 @@
   Size texture_size;
   bool swizzle_contents;
   uint32 resource_id;
+  bool nearest_neighbor;
 };
 
 struct StreamVideoQuadState {};
diff --git a/mojo/tools/roll/cc_strip_video.patch b/mojo/tools/roll/cc_strip_video.patch
index df14109..aefb753 100644
--- a/mojo/tools/roll/cc_strip_video.patch
+++ b/mojo/tools/roll/cc_strip_video.patch
@@ -1,8 +1,8 @@
 diff --git a/cc/BUILD.gn b/cc/BUILD.gn
-index c744c5b..16a1589 100644
+index 826e12c..13e974d 100644
 --- a/cc/BUILD.gn
 +++ b/cc/BUILD.gn
-@@ -212,13 +212,6 @@ component("cc") {
+@@ -213,13 +213,6 @@ component("cc") {
      "layers/ui_resource_layer.h",
      "layers/ui_resource_layer_impl.cc",
      "layers/ui_resource_layer_impl.h",
@@ -16,7 +16,7 @@
      "output/begin_frame_args.cc",
      "output/begin_frame_args.h",
      "output/bsp_tree.cc",
-@@ -453,8 +446,6 @@ component("cc") {
+@@ -456,8 +449,6 @@ component("cc") {
      "resources/ui_resource_client.h",
      "resources/ui_resource_request.cc",
      "resources/ui_resource_request.h",
@@ -25,16 +25,16 @@
      "resources/zero_copy_tile_task_worker_pool.cc",
      "resources/zero_copy_tile_task_worker_pool.h",
      "scheduler/begin_frame_source.cc",
-@@ -588,8 +579,6 @@ source_set("test_support") {
+@@ -590,8 +581,6 @@ source_set("test_support") {
      "test/fake_tile_manager_client.h",
      "test/fake_ui_resource_layer_tree_host_impl.cc",
      "test/fake_ui_resource_layer_tree_host_impl.h",
 -    "test/fake_video_frame_provider.cc",
 -    "test/fake_video_frame_provider.h",
+     "test/failure_output_surface.cc",
+     "test/failure_output_surface.h",
      "test/geometry_test_utils.cc",
-     "test/geometry_test_utils.h",
-     "test/test_in_process_context_provider.cc",
-@@ -744,7 +733,6 @@ test("cc_unittests") {
+@@ -747,7 +736,6 @@ test("cc_unittests") {
      "layers/tiled_layer_unittest.cc",
      "layers/ui_resource_layer_impl_unittest.cc",
      "layers/ui_resource_layer_unittest.cc",
@@ -42,7 +42,7 @@
      "output/begin_frame_args_unittest.cc",
      "output/delegating_renderer_unittest.cc",
      "output/filter_operations_unittest.cc",
-@@ -775,7 +763,6 @@ test("cc_unittests") {
+@@ -778,7 +766,6 @@ test("cc_unittests") {
      "resources/texture_uploader_unittest.cc",
      "resources/tile_manager_unittest.cc",
      "resources/tile_priority_unittest.cc",
@@ -50,7 +50,7 @@
      "scheduler/begin_frame_source_unittest.cc",
      "scheduler/delay_based_time_source_unittest.cc",
      "scheduler/scheduler_state_machine_unittest.cc",
-@@ -804,7 +791,6 @@ test("cc_unittests") {
+@@ -807,7 +794,6 @@ test("cc_unittests") {
      "trees/layer_tree_host_unittest_picture.cc",
      "trees/layer_tree_host_unittest_proxy.cc",
      "trees/layer_tree_host_unittest_scroll.cc",
@@ -229,7 +229,7 @@
 -
 -}  // namespace cc
 diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
-index 27f40eb..49af1c3 100644
+index ee94a4c..7896bb8 100644
 --- a/cc/output/gl_renderer.cc
 +++ b/cc/output/gl_renderer.cc
 @@ -13,7 +13,6 @@
@@ -241,7 +241,7 @@
  #include "cc/output/compositor_frame_metadata.h"
  #include "cc/output/context_provider.h"
 diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
-index 0c2bc3d..d112ed1 100644
+index b51aef6..58205a9 100644
 --- a/cc/output/renderer_pixeltest.cc
 +++ b/cc/output/renderer_pixeltest.cc
 @@ -12,7 +12,6 @@
@@ -252,7 +252,7 @@
  #include "third_party/skia/include/core/SkColorPriv.h"
  #include "third_party/skia/include/core/SkImageFilter.h"
  #include "third_party/skia/include/core/SkMatrix.h"
-@@ -385,346 +384,6 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) {
+@@ -386,346 +385,6 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) {
        FuzzyPixelOffByOneComparator(true)));
  }
  
@@ -624,7 +624,7 @@
  #include "third_party/skia/include/core/SkMatrix.h"
  #include "third_party/skia/include/core/SkPicture.h"
 diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
-index f31cde0..4e070e2 100644
+index fc4780f..61bda89 100644
 --- a/cc/trees/layer_tree_host_impl_unittest.cc
 +++ b/cc/trees/layer_tree_host_impl_unittest.cc
 @@ -27,7 +27,6 @@
@@ -667,7 +667,7 @@
    }
  
    LayerTreeSettings DefaultSettings() {
-@@ -5247,18 +5242,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
+@@ -5248,18 +5243,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
        LayerImpl::Create(host_impl_->active_tree(), 1);
    root_layer->SetBounds(gfx::Size(10, 10));
  
@@ -686,7 +686,7 @@
    scoped_ptr<IOSurfaceLayerImpl> io_surface_layer =
        IOSurfaceLayerImpl::Create(host_impl_->active_tree(), 5);
    io_surface_layer->SetBounds(gfx::Size(10, 10));
-@@ -6321,16 +6304,6 @@ TEST_F(LayerTreeHostImplTest,
+@@ -6322,16 +6305,6 @@ TEST_F(LayerTreeHostImplTest,
    scoped_ptr<SolidColorLayerImpl> root_layer =
        SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
  
@@ -704,7 +704,7 @@
    EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
    host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
 diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
-index 712909f..51c5d7e 100644
+index a343466..eee6275 100644
 --- a/cc/trees/layer_tree_host_unittest.cc
 +++ b/cc/trees/layer_tree_host_unittest.cc
 @@ -18,7 +18,6 @@
@@ -723,7 +723,7 @@
  #include "cc/test/geometry_test_utils.h"
  #include "cc/test/layer_tree_test.h"
  #include "cc/test/test_shared_bitmap_manager.h"
-@@ -4189,28 +4187,6 @@ class LayerInvalidateCausesDraw : public LayerTreeHostTest {
+@@ -4183,28 +4181,6 @@ class LayerInvalidateCausesDraw : public LayerTreeHostTest {
    int num_draws_;
  };
  
@@ -753,7 +753,7 @@
  // to the compositor thread, even though no resources are updated in
  // response to that invalidation.
 diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
-index 2d23d75..b646e6a 100644
+index 24ffcd4..cc4f28f 100644
 --- a/cc/trees/layer_tree_host_unittest_context.cc
 +++ b/cc/trees/layer_tree_host_unittest_context.cc
 @@ -15,8 +15,6 @@
@@ -764,8 +764,8 @@
 -#include "cc/layers/video_layer_impl.h"
  #include "cc/output/filter_operations.h"
  #include "cc/resources/single_release_callback.h"
- #include "cc/test/fake_content_layer.h"
-@@ -32,7 +30,6 @@
+ #include "cc/test/failure_output_surface.h"
+@@ -33,7 +31,6 @@
  #include "cc/test/fake_picture_layer_impl.h"
  #include "cc/test/fake_scoped_ui_resource.h"
  #include "cc/test/fake_scrollbar.h"
@@ -773,7 +773,7 @@
  #include "cc/test/layer_tree_test.h"
  #include "cc/test/render_pass_test_common.h"
  #include "cc/test/test_context_provider.h"
-@@ -42,9 +39,6 @@
+@@ -43,9 +40,6 @@
  #include "cc/trees/layer_tree_impl.h"
  #include "cc/trees/single_thread_proxy.h"
  #include "gpu/GLES2/gl2extchromium.h"
@@ -783,7 +783,7 @@
  
  namespace cc {
  namespace {
-@@ -65,7 +59,6 @@ class LayerTreeHostContextTest : public LayerTreeTest {
+@@ -66,7 +60,6 @@ class LayerTreeHostContextTest : public LayerTreeTest {
          context_should_support_io_surface_(false),
          fallback_context_works_(false),
          async_output_surface_creation_(false) {
@@ -791,7 +791,7 @@
    }
  
    void LoseContext() {
-@@ -1083,49 +1076,6 @@ class LayerTreeHostContextTestDontUseLostResources
+@@ -1041,49 +1034,6 @@ class LayerTreeHostContextTestDontUseLostResources
      layer_with_mask->SetMaskLayer(mask.get());
      root->AddChild(layer_with_mask);
  
@@ -841,7 +841,7 @@
      if (!delegating_renderer()) {
        // TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
        scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create();
-@@ -1155,14 +1105,6 @@ class LayerTreeHostContextTestDontUseLostResources
+@@ -1113,14 +1063,6 @@ class LayerTreeHostContextTestDontUseLostResources
  
    void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
      LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
@@ -856,7 +856,7 @@
    }
  
    DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-@@ -1212,14 +1154,6 @@ class LayerTreeHostContextTestDontUseLostResources
+@@ -1169,14 +1111,6 @@ class LayerTreeHostContextTestDontUseLostResources
    scoped_refptr<DelegatedFrameResourceCollection>
        delegated_resource_collection_;
    scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 4cecaef..c4c928e 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -566,6 +566,8 @@
     "server/http_server_response_info.h",
     "server/web_socket.cc",
     "server/web_socket.h",
+    "server/web_socket_encoder.cc",
+    "server/web_socket_encoder.h",
   ]
   configs += [
     "//build/config/compiler:wexit_time_destructors",
@@ -677,6 +679,8 @@
     "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_data_job.cc",
+    "test/url_request/url_request_mock_data_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",
@@ -1247,6 +1251,10 @@
 
     if (!enable_websockets) {
       sources -= [
+        "server/http_connection_unittest.cc",
+        "server/http_server_response_info_unittest.cc",
+        "server/http_server_unittest.cc",
+        "server/web_socket_encoder_unittest.cc",
         "websockets/websocket_basic_stream_test.cc",
         "websockets/websocket_channel_test.cc",
         "websockets/websocket_deflate_predictor_impl_test.cc",
@@ -1263,6 +1271,7 @@
         "websockets/websocket_test_util.cc",
         "websockets/websocket_test_util.h",
       ]
+      deps -= [ ":http_server" ]
     }
 
     if (disable_file_support) {
diff --git a/net/base/filename_util_unittest.cc b/net/base/filename_util_unittest.cc
index 391baeb..0e7d504 100644
--- a/net/base/filename_util_unittest.cc
+++ b/net/base/filename_util_unittest.cc
@@ -48,6 +48,25 @@
 #endif
 }
 
+std::string GetLocaleWarningString() {
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+  // The generate filename tests can fail on certain OS_POSIX platforms when
+  // LC_CTYPE is not "utf8" or "utf-8" because some of the string conversions
+  // fail.
+  // This warning text is appended to any test failures to save people time if
+  // this happens to be the cause of failure :)
+  // Note: some platforms (MACOSX, Chromecast) don't have this problem:
+  // setlocale returns "c" but it functions as utf8.  And Android doesn't
+  // have setlocale at all.
+  std::string locale = setlocale(LC_CTYPE, NULL);
+  return " this test may have failed because the current LC_CTYPE locale is "
+         "not utf8 (currently set to " +
+         locale + ")";
+#else
+  return "";
+#endif
+}
+
 void RunGenerateFileNameTestCase(const GenerateFilenameCase* test_case) {
   std::string default_filename(base::WideToUTF8(test_case->default_filename));
   base::FilePath file_path = GenerateFileName(
@@ -55,7 +74,8 @@
       test_case->referrer_charset, test_case->suggested_filename,
       test_case->mime_type, default_filename);
   EXPECT_EQ(test_case->expected_filename, FilePathAsWString(file_path))
-      << "test case at line number: " << test_case->lineno;
+      << "test case at line number: " << test_case->lineno << "; "
+      << GetLocaleWarningString();
 }
 
 }  // namespace
@@ -418,18 +438,6 @@
 }
 
 TEST(FilenameUtilTest, GenerateFileName) {
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
-  // This test doesn't run when the locale is not UTF-8 because some of the
-  // string conversions fail. This is OK (we have the default value) but they
-  // don't match our expectations.
-  std::string locale = setlocale(LC_CTYPE, NULL);
-  base::StringToLowerASCII(&locale);
-  EXPECT_TRUE(locale.find("utf-8") != std::string::npos ||
-              locale.find("utf8") != std::string::npos)
-      << "Your locale (" << locale << ") must be set to UTF-8 "
-      << "for this test to pass!";
-#endif
-
   // Tests whether the correct filename is selected from the the given
   // parameters and that Content-Disposition headers are properly
   // handled including failovers when the header is malformed.
diff --git a/net/base/net_log_util.cc b/net/base/net_log_util.cc
index 3b437aa..75be128 100644
--- a/net/base/net_log_util.cc
+++ b/net/base/net_log_util.cc
@@ -33,6 +33,7 @@
 #include "net/proxy/proxy_service.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_utils.h"
+#include "net/socket/ssl_client_socket.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
 
@@ -447,10 +448,17 @@
         "force_spdy_always",
         http_network_session->params().force_spdy_always);
 
-    std::vector<std::string> next_protos;
+    NextProtoVector next_protos;
     http_network_session->GetNextProtos(&next_protos);
-    std::string next_protos_string = JoinString(next_protos, ',');
-    status_dict->SetString("next_protos", next_protos_string);
+    if (!next_protos.empty()) {
+      std::string next_protos_string;
+      for (const NextProto proto : next_protos) {
+        if (!next_protos_string.empty())
+          next_protos_string.append(",");
+        next_protos_string.append(SSLClientSocket::NextProtoToString(proto));
+      }
+      status_dict->SetString("next_protos", next_protos_string);
+    }
 
     net_info_dict->Set(NetInfoSourceToString(NET_INFO_SPDY_STATUS),
                         status_dict);
diff --git a/net/data/proxy_resolver_v8_unittest/pac_library_unittest.js b/net/data/proxy_resolver_v8_unittest/pac_library_unittest.js
index 0c0a4a9..58de402 100644
--- a/net/data/proxy_resolver_v8_unittest/pac_library_unittest.js
+++ b/net/data/proxy_resolver_v8_unittest/pac_library_unittest.js
@@ -1,3 +1,7 @@
+// 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.
+
 // This should output "PROXY success:80" if all the tests pass.
 // Otherwise it will output "PROXY failure:<num-failures>".
 //
@@ -61,6 +65,56 @@
 Tests.testIsPlainHostName = function(t) {
   t.expectTrue(isPlainHostName("google"));
   t.expectFalse(isPlainHostName("google.com"));
+  t.expectFalse(isPlainHostName("192.168.1.1"));
+  t.expectFalse(isPlainHostName("."));
+  t.expectFalse(isPlainHostName(".:"));
+
+  // Valid IPv6 address
+  t.expectFalse(isPlainHostName("::1"));
+
+  // Not a valid IPv6 address
+  t.expectTrue(isPlainHostName("foopy::1"));
+  t.expectTrue(isPlainHostName("foo:112"));
+  t.expectTrue(isPlainHostName(":"));
+  t.expectTrue(isPlainHostName("[:]"));
+
+  // Not considered a valid IPv6 address because of surrounding brackets.
+  t.expectTrue(isPlainHostName("[::1]"));
+
+  // Calling with more than 1 argument is allowed.
+  t.expectTrue(isPlainHostName("foo", "foo", "foo"));
+
+  // Calling with no arguments is an error.
+  try {
+    isPlainHostName();
+    t.expectTrue(false);  // Not reached.
+  } catch (e) {
+    t.expectEquals('TypeError: Requires 1 string parameter', e.toString());
+  }
+
+  // Calling with the wrong argument type is an error.
+  try {
+    isPlainHostName(null);
+    t.expectTrue(false);  // Not reached.
+  } catch (e) {
+    t.expectEquals('TypeError: Requires 1 string parameter', e.toString());
+  }
+
+  // Calling with the wrong argument type is an error.
+  try {
+    isPlainHostName(1);
+    t.expectTrue(false);  // Not reached.
+  } catch (e) {
+    t.expectEquals('TypeError: Requires 1 string parameter', e.toString());
+  }
+
+  // Calling with the wrong argument type is an error.
+  try {
+    isPlainHostName(function() {});
+    t.expectTrue(false);  // Not reached.
+  } catch (e) {
+    t.expectEquals('TypeError: Requires 1 string parameter', e.toString());
+  }
 };
 
 Tests.testLocalHostOrDomainIs = function(t) {
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index 843a619..3b1f669 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -6,6 +6,7 @@
 #include "base/files/file_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/port.h"
+#include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
@@ -3282,6 +3283,10 @@
   entry->Close();
   entry = NULL;
 
+  // The entry is being closed on the Simple Cache worker pool
+  disk_cache::SimpleBackendImpl::FlushWorkerPoolForTesting();
+  base::RunLoop().RunUntilIdle();
+
   // Write an invalid header for stream 0 and stream 1.
   base::FilePath entry_file1_path = cache_path_.AppendASCII(
       disk_cache::simple_util::GetFilenameFromKeyAndFileIndex(key, 0));
diff --git a/net/disk_cache/blockfile/stress_cache.cc b/net/disk_cache/blockfile/stress_cache.cc
index f28e8af..d43cb74 100644
--- a/net/disk_cache/blockfile/stress_cache.cc
+++ b/net/disk_cache/blockfile/stress_cache.cc
@@ -27,7 +27,6 @@
 #include "base/path_service.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
-#include "base/process/process_handle.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -59,14 +58,14 @@
   base::CommandLine cmdline(exe);
   cmdline.AppendArg(base::IntToString(iteration));
 
-  base::ProcessHandle handle;
-  if (!base::LaunchProcess(cmdline, base::LaunchOptions(), &handle)) {
+  base::Process process = base::LaunchProcess(cmdline, base::LaunchOptions());
+  if (!process.IsValid()) {
     printf("Unable to run test\n");
     return kError;
   }
 
   int exit_code;
-  if (!base::WaitForExitCode(handle, &exit_code)) {
+  if (!process.WaitForExit(&exit_code)) {
     printf("Unable to get return code\n");
     return kError;
   }
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 656db54..405c88c 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -26,6 +26,7 @@
 #include "net/socket/client_socket_factory.h"
 #include "net/socket/client_socket_pool_manager_impl.h"
 #include "net/socket/next_proto.h"
+#include "net/socket/ssl_client_socket.h"
 #include "net/spdy/hpack_huffman_aggregator.h"
 #include "net/spdy/spdy_session_pool.h"
 
@@ -166,7 +167,7 @@
     // Add the protocol to the TLS next protocol list, except for QUIC
     // since it uses UDP.
     if (proto != kProtoQUIC1SPDY3) {
-      next_protos_.push_back(SSLClientSocket::NextProtoToString(proto));
+      next_protos_.push_back(proto);
     }
 
     // Enable the corresponding alternate protocol, except for HTTP
@@ -284,8 +285,7 @@
       protocol - ALTERNATE_PROTOCOL_MINIMUM_VALID_VERSION];
 }
 
-void HttpNetworkSession::GetNextProtos(
-    std::vector<std::string>* next_protos) const {
+void HttpNetworkSession::GetNextProtos(NextProtoVector* next_protos) const {
   if (HttpStreamFactory::spdy_enabled()) {
     *next_protos = next_protos_;
   } else {
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index bf93c83..c9704a4 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -205,7 +205,8 @@
 
   bool IsProtocolEnabled(AlternateProtocol protocol) const;
 
-  void GetNextProtos(std::vector<std::string>* next_protos) const;
+  // Populates |*next_protos| with protocols.
+  void GetNextProtos(NextProtoVector* next_protos) const;
 
   // Convenience function for searching through |params_| for
   // |forced_spdy_exclusions|.
@@ -242,7 +243,7 @@
   // TODO(jgraettinger): Remove when Huffman collection is complete.
   scoped_ptr<HpackHuffmanAggregator> huffman_aggregator_;
 
-  std::vector<std::string> next_protos_;
+  NextProtoVector next_protos_;
   bool enabled_protocols_[NUM_VALID_ALTERNATE_PROTOCOLS];
 
   Params params_;
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h
index 4c09bec..3c59a75 100644
--- a/net/http/transport_security_state_static.h
+++ b/net/http/transport_security_state_static.h
@@ -2060,297 +2060,296 @@
   0x15, 0xcf, 0xf7, 0x1d, 0xd6, 0x29, 0xba, 0x86,
   0x8a, 0xe2, 0x1c, 0x7f, 0x5a, 0x6b, 0x3d, 0x79,
   0xdc, 0x1d, 0x3f, 0xaf, 0xc3, 0xff, 0xfd, 0xd0,
-  0xe9, 0x37, 0x40, 0x7a, 0xb4, 0x20, 0x9f, 0xfb,
-  0x7c, 0xff, 0x06, 0x3b, 0xc8, 0xd9, 0xd3, 0xeb,
-  0xf7, 0x23, 0x67, 0x4e, 0xc5, 0x3d, 0x93, 0xe9,
-  0xc2, 0x1c, 0xf8, 0x53, 0x75, 0x0d, 0x14, 0xf4,
-  0xfd, 0x74, 0xe0, 0x1a, 0xf3, 0xa3, 0x8d, 0x4c,
-  0x99, 0x61, 0x2b, 0x66, 0x80, 0x61, 0x3f, 0xfb,
-  0x5e, 0xee, 0x43, 0x7e, 0xa5, 0x17, 0xf3, 0xa1,
-  0xc8, 0x90, 0xe5, 0x16, 0x73, 0xb9, 0xb3, 0xa7,
-  0xca, 0xff, 0xfb, 0x79, 0xd3, 0xc9, 0xba, 0x86,
-  0x8a, 0xce, 0x1a, 0x3d, 0x41, 0x29, 0x9f, 0xaa,
-  0x62, 0x83, 0xe8, 0x74, 0xe5, 0xab, 0xc7, 0x4f,
-  0xb1, 0xff, 0x50, 0x79, 0xd3, 0xbb, 0xda, 0x1d,
-  0x3e, 0xb6, 0xaa, 0xef, 0xf3, 0xa4, 0xeb, 0x46,
-  0xe0, 0x91, 0x64, 0xb7, 0x47, 0x00, 0xab, 0xa8,
-  0xe4, 0xff, 0xce, 0xd7, 0xba, 0xc5, 0x37, 0x50,
-  0xd1, 0x22, 0xcf, 0xe7, 0x58, 0xa6, 0xea, 0x1a,
-  0x2c, 0x99, 0xfc, 0xeb, 0x14, 0xdd, 0x43, 0x45,
-  0xb1, 0x3a, 0xe9, 0x67, 0x4f, 0x85, 0x37, 0x50,
-  0xd1, 0x6d, 0xc9, 0xcf, 0x3c, 0xab, 0x1a, 0x9d,
-  0x56, 0x7c, 0x74, 0xff, 0xb8, 0xde, 0x35, 0xb8,
-  0x63, 0x36, 0x0b, 0xf9, 0xd3, 0xf2, 0x83, 0xf9,
-  0xed, 0x87, 0x4f, 0x85, 0x37, 0x50, 0xd1, 0x78,
-  0x4f, 0x63, 0x8a, 0xf2, 0x74, 0xff, 0xcb, 0xd5,
-  0x95, 0xbf, 0x16, 0x18, 0xa1, 0xd3, 0xeb, 0x0f,
-  0xdb, 0xd4, 0xe9, 0xf2, 0xf5, 0xef, 0x68, 0x74,
-  0xec, 0x2f, 0xe7, 0x49, 0xdc, 0x6a, 0x74, 0x2d,
-  0xc6, 0x8e, 0xd4, 0x9d, 0x65, 0xd5, 0x98, 0x64,
-  0x93, 0xf4, 0x60, 0x29, 0xc1, 0x4c, 0xef, 0x5d,
-  0x67, 0x4f, 0x85, 0x37, 0x50, 0xd1, 0x7a, 0x4f,
-  0xf8, 0x37, 0x0f, 0x5e, 0x98, 0xf5, 0x47, 0x4f,
-  0xad, 0x99, 0xde, 0x4e, 0x93, 0xb9, 0x45, 0x9d,
-  0x8e, 0x75, 0x30, 0x6f, 0x40, 0x85, 0x64, 0x87,
-  0xd5, 0x0b, 0x5b, 0x94, 0x58, 0x84, 0x9e, 0x8d,
-  0x30, 0x56, 0xd8, 0x99, 0xf9, 0xd8, 0x42, 0x17,
-  0xb8, 0xf2, 0x3e, 0x8d, 0x1e, 0x6e, 0xf2, 0x74,
-  0xf5, 0xe7, 0x70, 0x74, 0xfe, 0xbf, 0x0f, 0xff,
-  0xf7, 0x43, 0xa4, 0xdd, 0x01, 0xea, 0xd0, 0x82,
-  0x7d, 0xec, 0x2d, 0x75, 0x1d, 0x3e, 0x14, 0xdd,
-  0x43, 0x44, 0x47, 0x3f, 0xfd, 0x9e, 0xe9, 0x4b,
-  0x60, 0x5b, 0x6e, 0x0a, 0xdd, 0x8e, 0x9f, 0xf3,
-  0xd6, 0xa1, 0xbc, 0x63, 0xd8, 0x3a, 0x7f, 0xff,
-  0x97, 0x3b, 0xec, 0x2e, 0x42, 0xf1, 0x9f, 0x66,
-  0xfd, 0xf1, 0xd3, 0x54, 0xc2, 0xa6, 0xfb, 0xe2,
-  0xa7, 0xfe, 0x7b, 0x93, 0x3e, 0x6b, 0x2b, 0x53,
-  0xbf, 0x35, 0xff, 0x0b, 0xcf, 0xeb, 0xe3, 0x85,
-  0xe7, 0x70, 0x74, 0xff, 0xfc, 0x8e, 0x1d, 0x0f,
-  0x61, 0xc2, 0xb8, 0x0d, 0xfc, 0xe8, 0xe3, 0x15,
-  0x83, 0x71, 0xad, 0x8a, 0x59, 0x65, 0x28, 0x61,
-  0x5a, 0xc8, 0x9f, 0x6c, 0x25, 0x30, 0xbe, 0xd8,
-  0xd2, 0x7c, 0x29, 0xba, 0x86, 0x88, 0xba, 0x7d,
-  0x8f, 0xfa, 0x83, 0xcb, 0x67, 0xb2, 0x4e, 0xb3,
-  0xe8, 0xd3, 0x08, 0x72, 0x65, 0x0f, 0x8c, 0x0a,
-  0x7f, 0xe6, 0x6b, 0xdd, 0x62, 0x9b, 0xa8, 0x68,
-  0x99, 0xa7, 0x56, 0xb4, 0x3a, 0x72, 0x79, 0x87,
-  0x4d, 0xc4, 0xdd, 0xce, 0x9f, 0xb1, 0x75, 0x5f,
-  0xed, 0x1d, 0x0d, 0xdc, 0xf3, 0x9a, 0x1f, 0x9f,
-  0x26, 0xe7, 0xcd, 0x1d, 0x3f, 0xf3, 0x7f, 0xb1,
-  0xe4, 0xf7, 0x38, 0xb4, 0x3a, 0x7f, 0xff, 0xbb,
-  0xd0, 0x40, 0xbe, 0x73, 0xdf, 0x0c, 0xab, 0xc5,
-  0x6a, 0x3a, 0x2d, 0x15, 0xf9, 0x47, 0x9f, 0xff,
-  0x73, 0xe0, 0xaa, 0xe9, 0xed, 0xcb, 0xbe, 0xfb,
-  0xe2, 0xa7, 0x93, 0x75, 0x0d, 0x16, 0x7c, 0xff,
-  0xbd, 0x95, 0x7f, 0xb0, 0xb8, 0xa1, 0xd3, 0xff,
-  0xde, 0x1c, 0xef, 0x0b, 0x6c, 0x17, 0x4b, 0x03,
-  0xa7, 0x7d, 0xf7, 0xc5, 0x4f, 0xfb, 0x5f, 0x40,
-  0xb4, 0xe6, 0xc4, 0xa7, 0x17, 0xf3, 0xfc, 0xb9,
-  0xf7, 0x21, 0xba, 0xd1, 0xd3, 0xfd, 0xe0, 0xe7,
-  0xaf, 0x3d, 0xe2, 0x87, 0x42, 0x27, 0xe2, 0x2b,
-  0x4c, 0x2b, 0xc9, 0xf7, 0xed, 0xd8, 0x4a, 0x6c,
-  0x71, 0x3f, 0xc3, 0xbf, 0x67, 0xca, 0x2a, 0x74,
-  0xff, 0xff, 0xfd, 0x77, 0xfd, 0x2e, 0xc3, 0xa7,
-  0x51, 0x05, 0xbc, 0xba, 0x81, 0x75, 0x32, 0xd8,
-  0x74, 0xea, 0x2d, 0x47, 0x4e, 0xe2, 0xbc, 0x9d,
-  0x0f, 0x46, 0x15, 0x21, 0x11, 0x81, 0xc9, 0xea,
-  0xff, 0xed, 0x0e, 0x9f, 0x64, 0x16, 0xc4, 0xc9,
-  0xff, 0x78, 0x5f, 0x63, 0x57, 0x7b, 0xc9, 0xa2,
-  0x0d, 0x71, 0xa4, 0x9f, 0x6a, 0x79, 0x8a, 0x74,
-  0xfc, 0xfc, 0x86, 0xd7, 0x83, 0xa5, 0x68, 0x7a,
-  0x40, 0x4b, 0x3f, 0xff, 0xed, 0xfb, 0x17, 0x9c,
-  0x2d, 0x85, 0x78, 0xb1, 0xf5, 0x5a, 0xc3, 0xa1,
-  0xe9, 0x9f, 0x5c, 0x2b, 0x80, 0x96, 0x7e, 0x1b,
-  0xe6, 0x99, 0x53, 0xa7, 0xff, 0xf7, 0x61, 0xbd,
-  0x38, 0x75, 0x0d, 0xc5, 0x3d, 0x5e, 0x7d, 0xf1,
-  0xd3, 0xff, 0xfd, 0x4a, 0x28, 0xe1, 0x5c, 0xcb,
-  0xc5, 0x3a, 0xd3, 0x5f, 0x67, 0x4f, 0x66, 0xfc,
-  0xd8, 0xe8, 0xf2, 0x22, 0x72, 0xcd, 0x33, 0x1b,
-  0xa3, 0x45, 0xf9, 0x3f, 0xf3, 0xf1, 0xdb, 0xde,
-  0xcc, 0x61, 0x58, 0x74, 0xff, 0xde, 0xb0, 0xbb,
-  0xa7, 0x07, 0xd1, 0x87, 0x45, 0x68, 0x8a, 0xa2,
-  0x34, 0xde, 0x68, 0xe9, 0xd8, 0xf5, 0x47, 0x4e,
-  0x05, 0x43, 0xa3, 0x81, 0xe6, 0xb0, 0x5c, 0x07,
-  0x61, 0x53, 0x76, 0xe4, 0x8e, 0xe1, 0x65, 0xae,
-  0x33, 0xff, 0xff, 0x37, 0xae, 0x7c, 0xc7, 0x34,
-  0xfd, 0x1e, 0xb9, 0xf5, 0x74, 0x4f, 0x54, 0x74,
-  0xf7, 0xdb, 0x74, 0x3a, 0x7f, 0x9e, 0xcd, 0x7e,
-  0x28, 0xbd, 0x0e, 0x85, 0x3d, 0xbd, 0x21, 0x9e,
-  0xba, 0x78, 0x0e, 0x80, 0x3c, 0x0e, 0xc8, 0x27,
-  0xba, 0xf7, 0xb4, 0x3a, 0x7f, 0xd8, 0xa7, 0xfe,
-  0xae, 0xb7, 0xde, 0x0e, 0x85, 0x3e, 0x6b, 0x24,
-  0x99, 0xae, 0xce, 0x93, 0x0e, 0x8a, 0xcd, 0x43,
-  0x72, 0x31, 0x3f, 0xb7, 0x6b, 0x78, 0x2f, 0x27,
-  0x4f, 0xff, 0xfb, 0x3e, 0xaf, 0x17, 0x5e, 0x04,
-  0x57, 0x1f, 0xf5, 0x07, 0xe6, 0xce, 0x9d, 0xf7,
-  0xdf, 0x15, 0x3d, 0xcf, 0x3a, 0x05, 0x38, 0xbf,
-  0x9f, 0xf6, 0xe5, 0x3d, 0xbc, 0x29, 0xb9, 0x3a,
-  0x15, 0x35, 0x6e, 0x49, 0xd0, 0xcb, 0xd0, 0x8e,
-  0xc9, 0x8c, 0xff, 0xd6, 0x15, 0xe2, 0xc7, 0xd5,
-  0x6b, 0x0e, 0x9f, 0x5e, 0x1e, 0xcc, 0x9d, 0x3e,
-  0xae, 0x80, 0xac, 0x3a, 0x15, 0x12, 0x34, 0x43,
-  0xec, 0x9e, 0x6f, 0xf2, 0x74, 0xfd, 0x53, 0x4f,
-  0xe3, 0x46, 0xa3, 0xa7, 0xf7, 0x4c, 0xde, 0x33,
-  0xec, 0x1d, 0x37, 0x84, 0xe8, 0x6e, 0xe7, 0xff,
-  0xe3, 0x5c, 0x9a, 0xcf, 0xfd, 0xca, 0xf2, 0x2b,
-  0x8f, 0x27, 0xb9, 0x3a, 0x7e, 0xcf, 0x75, 0x35,
-  0x9f, 0x1d, 0x1c, 0x9f, 0xb6, 0x51, 0x64, 0xee,
-  0x31, 0x9e, 0xd0, 0xdc, 0x07, 0x15, 0xa6, 0xa2,
-  0x9e, 0x61, 0xad, 0x72, 0x84, 0xfa, 0x33, 0x57,
-  0x0f, 0x8f, 0x1a, 0xb5, 0x1c, 0x30, 0x9a, 0x30,
-  0xb3, 0x32, 0x9a, 0x35, 0x07, 0xf8, 0xc5, 0x42,
-  0x11, 0x14, 0x8e, 0x7b, 0x10, 0xe0, 0xf8, 0xc3,
-  0x8a, 0x12, 0xdd, 0x61, 0x57, 0x0e, 0x6c, 0x4a,
-  0x73, 0x4f, 0xb4, 0x9f, 0xfc, 0xe6, 0x6b, 0xdd,
-  0x62, 0x9b, 0xa8, 0x68, 0x9b, 0x27, 0xf3, 0xac,
-  0x53, 0x75, 0x0d, 0x15, 0x6c, 0xfe, 0x7b, 0xfb,
-  0xc0, 0x2b, 0xce, 0x9e, 0xbc, 0xee, 0x0e, 0x93,
-  0x75, 0x67, 0xa6, 0x06, 0x73, 0xe1, 0x4d, 0xd4,
-  0x34, 0x56, 0x93, 0xff, 0xc8, 0xa3, 0x7f, 0xeb,
-  0x35, 0xeb, 0xe4, 0x3a, 0x7f, 0xf9, 0xf4, 0xb0,
-  0x56, 0x6d, 0xe3, 0x0a, 0xc3, 0xa6, 0xc6, 0x15,
-  0x12, 0xfa, 0x97, 0x3f, 0x95, 0xb7, 0x5c, 0x02,
-  0xfe, 0x74, 0xfd, 0x55, 0xe7, 0xd6, 0xc3, 0xa7,
-  0xfa, 0xdb, 0xc1, 0x7e, 0xad, 0xf4, 0x3a, 0x7f,
-  0x3e, 0xf1, 0xa1, 0xff, 0x67, 0x49, 0xdc, 0x6a,
-  0x7e, 0x36, 0x57, 0xe8, 0x63, 0xe4, 0xb7, 0x4d,
-  0x80, 0xb7, 0x07, 0x93, 0xf9, 0xd6, 0x29, 0xba,
-  0x86, 0x8b, 0x02, 0x7c, 0x29, 0xba, 0x86, 0x89,
-  0xd6, 0x7f, 0xff, 0x65, 0x6a, 0xe6, 0xd8, 0xea,
-  0x52, 0xf3, 0xea, 0x77, 0x51, 0xd3, 0xe7, 0x33,
-  0x5e, 0xeb, 0x44, 0xab, 0x46, 0x13, 0xe1, 0x4d,
-  0xd4, 0x34, 0x5b, 0x33, 0xfe, 0xfd, 0x68, 0xec,
-  0xf9, 0x34, 0x4e, 0x93, 0xac, 0xfb, 0x74, 0xc2,
-  0x79, 0x37, 0x50, 0xd1, 0x73, 0x49, 0x87, 0x4c,
-  0xeb, 0x13, 0x77, 0xf1, 0x5c, 0xfe, 0x75, 0x8a,
-  0x6e, 0xa1, 0xa2, 0xef, 0x9e, 0x77, 0x4e, 0x7f,
-  0x3a, 0x15, 0xb7, 0x32, 0xba, 0xc5, 0x4d, 0x0c,
-  0x6b, 0x52, 0xf4, 0xa7, 0xf1, 0x72, 0x64, 0x34,
-  0x3f, 0x85, 0x6d, 0x18, 0x70, 0x59, 0xd4, 0xee,
-  0x7f, 0xc1, 0xae, 0x5a, 0x51, 0x9a, 0xf3, 0xa7,
-  0xf0, 0x55, 0x6d, 0xf8, 0x5e, 0x87, 0x4f, 0x85,
-  0x37, 0x50, 0xd1, 0x2b, 0xcf, 0xf8, 0x37, 0xee,
-  0x72, 0xb5, 0x5f, 0xc7, 0x4f, 0x77, 0xa2, 0xf3,
-  0xa7, 0xff, 0xf7, 0xb1, 0xac, 0xd0, 0xff, 0x3f,
-  0x68, 0x54, 0x9e, 0xa8, 0xe8, 0xe5, 0x10, 0x7a,
-  0x43, 0x1c, 0xa3, 0x9b, 0x30, 0xc3, 0x9d, 0xaf,
-  0x72, 0xa6, 0xed, 0x66, 0xf4, 0x8c, 0x5a, 0x76,
-  0x17, 0x92, 0xa7, 0xff, 0x67, 0x7d, 0x85, 0x7f,
-  0x86, 0xae, 0xff, 0x2a, 0x7f, 0x6a, 0x3b, 0x91,
-  0x6e, 0x5c, 0xa7, 0xd1, 0x41, 0xc9, 0x39, 0x15,
-  0x57, 0x32, 0x3b, 0x26, 0xd0, 0xae, 0x9f, 0xfc,
-  0xe6, 0x6b, 0xdd, 0x62, 0x9b, 0xa8, 0x68, 0x98,
-  0x67, 0xff, 0xeb, 0x77, 0x51, 0xdf, 0xdd, 0xd3,
-  0x0f, 0xf9, 0x68, 0xf3, 0xa7, 0xfe, 0x6e, 0xae,
-  0xb7, 0xf7, 0xb8, 0x05, 0x79, 0xd3, 0xf9, 0x76,
-  0xac, 0x74, 0xd1, 0x3a, 0x7d, 0xa2, 0xfd, 0x61,
-  0xd0, 0x07, 0xb1, 0xd9, 0x9c, 0xfc, 0xc5, 0xb0,
-  0xc7, 0x11, 0xd3, 0xe5, 0xb0, 0xc7, 0x11, 0xd3,
-  0xf6, 0x7d, 0x8a, 0x6d, 0x7c, 0x0f, 0x59, 0x85,
-  0xd3, 0xff, 0xfe, 0x0b, 0xf9, 0xbf, 0x17, 0x9e,
-  0x01, 0x75, 0x7a, 0xc2, 0xb7, 0xd0, 0xe9, 0xf9,
-  0xb7, 0x5c, 0x02, 0xfe, 0x74, 0xff, 0xe5, 0xc7,
-  0xea, 0xfb, 0xaf, 0x15, 0x77, 0xf1, 0xd0, 0xa7,
-  0xff, 0xe3, 0x19, 0xfa, 0x9e, 0xe8, 0xcd, 0xc1,
-  0xd3, 0xff, 0xfe, 0x1b, 0x6c, 0xa1, 0x8e, 0x1d,
-  0x41, 0x73, 0xbe, 0xc2, 0xe2, 0x87, 0x4a, 0xeb,
-  0x44, 0xe8, 0x97, 0xcf, 0xff, 0xb2, 0x17, 0x8c,
-  0xfa, 0xeb, 0xc5, 0xb6, 0x5a, 0x1d, 0x39, 0x7f,
-  0xea, 0x74, 0x59, 0xfa, 0x02, 0xb4, 0xf6, 0xf5,
-  0xe6, 0xce, 0x93, 0xb8, 0xd5, 0x7d, 0xdc, 0xc2,
-  0x85, 0x1e, 0x1a, 0x48, 0xcc, 0x3c, 0x02, 0x17,
-  0xd8, 0x84, 0xe7, 0x64, 0x13, 0xe1, 0x4d, 0xd4,
-  0x34, 0x55, 0xd3, 0xfc, 0xf7, 0x58, 0xa6, 0xea,
-  0x1a, 0x23, 0xc9, 0x3a, 0xcf, 0xc7, 0x4c, 0x27,
-  0xf3, 0xac, 0x53, 0x75, 0x0d, 0x16, 0x0c, 0xfe,
-  0x75, 0x8a, 0x6e, 0xa1, 0xa2, 0xca, 0x9f, 0xce,
-  0xb1, 0x4d, 0xd4, 0x34, 0x5a, 0x73, 0xc9, 0xba,
-  0x86, 0x8b, 0x72, 0x7f, 0xe5, 0xb1, 0xb0, 0xe1,
-  0x9b, 0xaf, 0xe3, 0xa0, 0x4f, 0xbe, 0x85, 0x73,
-  0xfc, 0xa1, 0xdb, 0x16, 0x98, 0xf1, 0xd3, 0xfe,
-  0xd7, 0xba, 0xc5, 0x37, 0x50, 0xd1, 0x43, 0xcf,
-  0xfc, 0xcd, 0xe5, 0x79, 0xcf, 0x83, 0xcc, 0x3a,
-  0x7f, 0xdd, 0x8f, 0xe3, 0xa1, 0x8b, 0xfc, 0xe9,
-  0xfa, 0x9b, 0x5d, 0x31, 0xe3, 0xa7, 0xe0, 0xe3,
-  0x6c, 0x56, 0x87, 0x4f, 0xff, 0xd7, 0xce, 0x57,
-  0xab, 0xb0, 0x1b, 0xfd, 0x28, 0xbf, 0x95, 0x27,
-  0x5a, 0x7b, 0xbe, 0x21, 0x61, 0xc6, 0xa3, 0x51,
-  0x17, 0x07, 0xdd, 0x97, 0x71, 0x17, 0xcf, 0xe7,
-  0x58, 0xa6, 0xea, 0x1a, 0x2f, 0x38, 0x56, 0x4e,
-  0x03, 0xd1, 0x39, 0x52, 0xb9, 0xc4, 0xea, 0xe3,
-  0x04, 0x12, 0x66, 0x1d, 0xe4, 0xec, 0x25, 0x43,
-  0xb6, 0x7a, 0x9f, 0xce, 0xb1, 0x4d, 0xd4, 0x34,
-  0x52, 0xd3, 0xf9, 0xd6, 0x29, 0xba, 0x86, 0x8b,
-  0x0a, 0x7f, 0x3a, 0xc5, 0x37, 0x50, 0xd1, 0x65,
-  0xcf, 0x3b, 0xa3, 0x71, 0xdb, 0xb1, 0xd3, 0x9d,
-  0xd5, 0x87, 0x4f, 0x23, 0x96, 0x88, 0x7a, 0x1d,
-  0x99, 0x4f, 0xfe, 0x73, 0x35, 0xee, 0xb1, 0x4d,
-  0xd4, 0x34, 0x51, 0x93, 0xf9, 0xca, 0xd9, 0x45,
-  0x7f, 0x3a, 0x1e, 0x9d, 0xf0, 0x9d, 0xb0, 0xef,
-  0x61, 0x17, 0x43, 0x8c, 0x29, 0x4f, 0xfc, 0xed,
-  0x7b, 0xac, 0x53, 0x75, 0x0d, 0x11, 0xcc, 0xff,
-  0xe7, 0x33, 0x5e, 0xeb, 0x14, 0xdd, 0x43, 0x44,
-  0xe5, 0x3f, 0x9d, 0x62, 0x9b, 0xa8, 0x68, 0xb3,
-  0x27, 0xfe, 0x72, 0xfe, 0x2b, 0x8c, 0xed, 0x6f,
-  0x3a, 0x7f, 0x3a, 0xc5, 0x37, 0x50, 0xd1, 0x6e,
-  0xcf, 0xfe, 0x73, 0x35, 0xee, 0xb1, 0x4d, 0xd4,
-  0x34, 0x52, 0x13, 0xff, 0x3b, 0x5e, 0xeb, 0x14,
-  0xdd, 0x43, 0x44, 0xa5, 0x15, 0x27, 0xec, 0xd2,
-  0x63, 0x14, 0xbf, 0x3b, 0x04, 0x4c, 0x1d, 0xb7,
-  0xa9, 0x4f, 0xfb, 0x5e, 0xeb, 0x14, 0xdd, 0x43,
-  0x44, 0xed, 0x3f, 0xfe, 0xf7, 0x3d, 0xb1, 0x5b,
-  0xf7, 0x90, 0x50, 0xb4, 0x3a, 0x4e, 0x62, 0x27,
-  0x75, 0x1a, 0x7f, 0xed, 0x66, 0x6d, 0x37, 0x2b,
-  0xd5, 0xe7, 0x4f, 0xfc, 0x17, 0x9d, 0xaa, 0xe8,
-  0x1b, 0x59, 0xd3, 0x71, 0x3b, 0x94, 0x42, 0xd1,
-  0x0e, 0x18, 0x8e, 0x0e, 0x28, 0x56, 0xcf, 0x85,
-  0x37, 0x50, 0xd1, 0x16, 0x4f, 0xfb, 0x5e, 0xeb,
-  0x14, 0xdd, 0x43, 0x44, 0xbb, 0x3f, 0xff, 0x5f,
-  0x39, 0x5e, 0xae, 0xc0, 0x6f, 0xf4, 0xa2, 0xfe,
-  0x54, 0x9d, 0x68, 0xd4, 0x61, 0x87, 0x12, 0x34,
-  0xff, 0xe7, 0x33, 0x5e, 0xeb, 0x14, 0xdd, 0x43,
-  0x44, 0xc5, 0x3f, 0x58, 0xa6, 0xea, 0x1a, 0x2a,
-  0x99, 0xff, 0xff, 0xc3, 0xb9, 0xad, 0xf7, 0x87,
-  0x67, 0x68, 0x3e, 0xfb, 0x19, 0xf0, 0xbc, 0xe8,
-  0x72, 0x2b, 0x74, 0xd6, 0x7f, 0xf3, 0x99, 0xaf,
-  0x75, 0x8a, 0x6e, 0xa1, 0xa2, 0x74, 0x9f, 0xde,
-  0xd1, 0x57, 0xeb, 0x63, 0xa7, 0xcd, 0x2b, 0x4b,
-  0x43, 0xa7, 0xef, 0xaf, 0xcd, 0xac, 0x0e, 0x9e,
-  0xf6, 0x55, 0xde, 0x3d, 0x6a, 0x14, 0x4f, 0xfd,
-  0xdd, 0x30, 0xb5, 0xbb, 0xb6, 0xbc, 0xc3, 0xa1,
-  0x88, 0x82, 0xc9, 0xcc, 0xff, 0xb5, 0xee, 0xb1,
-  0x4d, 0xd4, 0x34, 0x4e, 0xf3, 0xec, 0x77, 0xac,
-  0xf1, 0x52, 0x77, 0x29, 0xcd, 0xdc, 0x61, 0x4c,
-  0x23, 0xd4, 0x69, 0xff, 0xce, 0x66, 0xbd, 0xd6,
-  0x29, 0xba, 0x86, 0x8a, 0x16, 0x7f, 0xf3, 0x99,
-  0xaf, 0x75, 0x8a, 0x6e, 0xa1, 0xa2, 0x92, 0x9f,
-  0xff, 0xd7, 0x47, 0x75, 0xb6, 0xb3, 0xac, 0xc6,
-  0x57, 0x1d, 0xb0, 0xe8, 0xa9, 0x72, 0x5d, 0xe7,
-  0x09, 0x0f, 0xf1, 0x22, 0x64, 0x7d, 0xbf, 0xa4,
-  0xf6, 0xa5, 0xc4, 0xa5, 0x3f, 0x9d, 0x62, 0x9b,
-  0xa8, 0x68, 0x89, 0x27, 0xff, 0x39, 0x9a, 0xf7,
-  0x58, 0xa6, 0xea, 0x1a, 0x25, 0xe9, 0xf0, 0xfe,
-  0xcf, 0x50, 0xe9, 0xdf, 0xae, 0x0e, 0x9f, 0xfb,
-  0x5a, 0xa2, 0xb6, 0xdc, 0xad, 0x6d, 0x1d, 0x1e,
-  0x44, 0x5b, 0x45, 0x02, 0x39, 0x3f, 0xde, 0xd0,
-  0xef, 0x0d, 0x2f, 0x43, 0xa7, 0xc2, 0x9b, 0xa8,
-  0x68, 0xa5, 0xe7, 0xff, 0x5b, 0xd7, 0xfa, 0x0a,
-  0xd6, 0xff, 0x30, 0xe9, 0xf3, 0x7f, 0x98, 0xb4,
-  0x3a, 0x7d, 0xad, 0xac, 0x68, 0x74, 0x97, 0x93,
-  0xd1, 0x61, 0x54, 0x9c, 0xa9, 0xaf, 0x72, 0x61,
-  0x67, 0x6d, 0x18, 0x62, 0x13, 0x73, 0xf9, 0xd6,
-  0x29, 0xba, 0x86, 0x8a, 0x72, 0x7f, 0xde, 0x1d,
-  0xa6, 0x6e, 0xc1, 0x0e, 0x9f, 0xf5, 0xe5, 0x46,
-  0xdd, 0xf7, 0xdf, 0x15, 0x37, 0xbe, 0x3a, 0x6a,
-  0x9d, 0xca, 0x24, 0x38, 0x8e, 0x9b, 0xcf, 0xe7,
-  0xc2, 0x9b, 0xa8, 0x68, 0xaf, 0x27, 0xff, 0xeb,
-  0xe7, 0x2b, 0xd5, 0xd8, 0x0d, 0xfe, 0x94, 0x5f,
-  0xca, 0x93, 0xad, 0x11, 0xdc, 0x46, 0x13, 0xff,
-  0x3b, 0x5e, 0xeb, 0x14, 0xdd, 0x43, 0x44, 0x8f,
-  0x3b, 0xdf, 0xa9, 0xd3, 0x92, 0xd8, 0x53, 0x8b,
-  0xc9, 0xf0, 0xa6, 0xea, 0x1a, 0x24, 0x89, 0xe7,
-  0x6b, 0xdc, 0xa7, 0xb3, 0x65, 0x33, 0xff, 0x3b,
-  0x5e, 0xeb, 0x14, 0xdd, 0x43, 0x44, 0x95, 0x3e,
-  0x14, 0xdd, 0x43, 0x45, 0xe3, 0x3f, 0x76, 0x15,
-  0xed, 0x74, 0x3a, 0x7d, 0x4a, 0x62, 0xd0, 0xe9,
-  0xfe, 0x7b, 0xac, 0x53, 0x75, 0x0d, 0x12, 0x6c,
-  0x9d, 0x68, 0xc6, 0xac, 0xc0, 0x4b, 0xf4, 0x9a,
-  0x15, 0x7b, 0x7e, 0xa3, 0xb7, 0xca, 0x3b, 0xe5,
-  0x5b, 0xd0, 0xcb, 0x6a, 0x1a, 0x4c, 0x2b, 0xcc,
-  0x30, 0x70, 0x6f, 0xdc, 0x62, 0x50, 0xb1, 0xc7,
-  0x36, 0xd5, 0x1d, 0x83, 0xe5, 0x05, 0x73, 0x28,
-  0x6a, 0xed, 0xe8, 0x9f, 0x49, 0x4b, 0x49, 0x68,
-  0x6f, 0x2b, 0x9e, 0xd3, 0xf4, 0xe9, 0x7f, 0x1e,
-  0x3b, 0x66, 0xab, 0x05, 0x41, 0xa5, 0x2a, 0xb3,
-  0x12, 0x76, 0x39, 0x9d, 0xfe, 0xda, 0xc7, 0x9b,
-  0xf9, 0x62, 0xed, 0xcc, 0x2c, 0x42, 0x90, 0xcd,
-  0x4a, 0x4e, 0x4e, 0x2b, 0xc1, 0xee, 0xe9, 0xa4,
-  0xcd, 0xa5, 0x31, 0x7d, 0x29, 0x47, 0x8a, 0x3e,
-  0x7e, 0xb3, 0xb2, 0xcd, 0xf3, 0xec, 0x50,
+  0xe9, 0x37, 0x40, 0x7a, 0xb4, 0x20, 0x9f, 0xff,
+  0xb1, 0x4f, 0x67, 0x7c, 0xff, 0x06, 0x3b, 0xc8,
+  0xd9, 0xd3, 0xe1, 0x4d, 0xd4, 0x34, 0x53, 0xd3,
+  0xf5, 0xd3, 0x80, 0x6b, 0xce, 0x8e, 0x35, 0x1c,
+  0x8a, 0x59, 0x6b, 0x60, 0x61, 0x3f, 0xfb, 0x5e,
+  0xee, 0x43, 0x7e, 0xa5, 0x17, 0xf3, 0xa1, 0xc8,
+  0x8a, 0xe4, 0xfe, 0x73, 0xb9, 0xb3, 0xa7, 0xca,
+  0xff, 0xfb, 0x79, 0xd3, 0xc9, 0xba, 0x86, 0x8a,
+  0xce, 0x1a, 0x3d, 0x41, 0x29, 0x9f, 0xaa, 0x62,
+  0x83, 0xe8, 0x74, 0xe5, 0xab, 0xc7, 0x4f, 0xb1,
+  0xff, 0x50, 0x79, 0xd3, 0xbb, 0xda, 0x1d, 0x3e,
+  0xb6, 0xaa, 0xef, 0xf3, 0xa4, 0xeb, 0x46, 0xe0,
+  0x91, 0x64, 0xb7, 0x47, 0x00, 0xab, 0xa8, 0xe4,
+  0xff, 0xce, 0xd7, 0xba, 0xc5, 0x37, 0x50, 0xd1,
+  0x22, 0xcf, 0xe7, 0x58, 0xa6, 0xea, 0x1a, 0x2c,
+  0x99, 0xfc, 0xeb, 0x14, 0xdd, 0x43, 0x45, 0xb1,
+  0x3a, 0xe9, 0x67, 0x4f, 0x85, 0x37, 0x50, 0xd1,
+  0x6d, 0xc9, 0xcf, 0x3c, 0xab, 0x1a, 0x9d, 0x56,
+  0x7c, 0x74, 0xff, 0xb8, 0xde, 0x35, 0xb8, 0x63,
+  0x36, 0x0b, 0xf9, 0xd3, 0xf2, 0x83, 0xf9, 0xed,
+  0x87, 0x4f, 0x85, 0x37, 0x50, 0xd1, 0x78, 0x4f,
+  0x63, 0x8a, 0xf2, 0x74, 0xff, 0xcb, 0xd5, 0x95,
+  0xbf, 0x16, 0x18, 0xa1, 0xd3, 0xeb, 0x0f, 0xdb,
+  0xd4, 0xe9, 0xf2, 0xf5, 0xef, 0x68, 0x74, 0xec,
+  0x2f, 0xe7, 0x49, 0xdc, 0x6a, 0x74, 0x2d, 0xc6,
+  0x8e, 0xd4, 0x9d, 0x65, 0xd5, 0x98, 0x64, 0x93,
+  0xf4, 0x60, 0x29, 0xc1, 0x4c, 0xef, 0x5d, 0x67,
+  0x4f, 0x85, 0x37, 0x50, 0xd1, 0x7a, 0x4f, 0xf8,
+  0x37, 0x0f, 0x5e, 0x98, 0xf5, 0x47, 0x4f, 0xad,
+  0x99, 0xde, 0x4e, 0x93, 0xb9, 0x45, 0x9d, 0x8e,
+  0x75, 0x30, 0x6f, 0x40, 0x85, 0x64, 0x63, 0xd5,
+  0x0b, 0x5b, 0x8f, 0x91, 0x09, 0x3d, 0x1a, 0x60,
+  0xad, 0xb1, 0x33, 0xf3, 0xb0, 0x84, 0x2f, 0x71,
+  0xe4, 0x7d, 0x1a, 0x3c, 0xdd, 0xe4, 0xe9, 0xeb,
+  0xce, 0xe0, 0xe9, 0xfd, 0x7e, 0x1f, 0xff, 0xee,
+  0x87, 0x49, 0xba, 0x03, 0xd5, 0xa1, 0x04, 0xfb,
+  0xd8, 0x5a, 0xea, 0x3a, 0x7c, 0x29, 0xba, 0x86,
+  0x88, 0x8e, 0x7f, 0xfb, 0x3d, 0xd2, 0x96, 0xc0,
+  0xb6, 0xdc, 0x15, 0xbb, 0x1d, 0x3f, 0xe7, 0xad,
+  0x43, 0x78, 0xc7, 0xb0, 0x74, 0xff, 0xff, 0x2e,
+  0x77, 0xd8, 0x5c, 0x85, 0xe3, 0x3e, 0xcd, 0xfb,
+  0xe3, 0xa6, 0xa9, 0x85, 0x4d, 0xf7, 0xc5, 0x4f,
+  0xfc, 0xf7, 0x26, 0x7c, 0xd6, 0x56, 0xa7, 0x7e,
+  0x6b, 0xfe, 0x17, 0x9f, 0xd7, 0xc7, 0x0b, 0xce,
+  0xe0, 0xe9, 0xff, 0xf9, 0x1c, 0x3a, 0x1e, 0xc3,
+  0x85, 0x70, 0x1b, 0xf9, 0xd1, 0xc6, 0x2b, 0x06,
+  0xe3, 0x5b, 0x14, 0xb2, 0xca, 0x50, 0xc2, 0xb5,
+  0x91, 0x3e, 0xd8, 0x4a, 0x61, 0x7d, 0xb1, 0xa4,
+  0xf8, 0x53, 0x75, 0x0d, 0x11, 0x74, 0xfb, 0x1f,
+  0xf5, 0x07, 0x96, 0xcf, 0x64, 0x9d, 0x67, 0xd1,
+  0xa6, 0x10, 0xe4, 0xca, 0x1f, 0x18, 0x14, 0xff,
+  0xcc, 0xd7, 0xba, 0xc5, 0x37, 0x50, 0xd1, 0x33,
+  0x4e, 0xad, 0x68, 0x74, 0xe4, 0xf3, 0x0e, 0x9b,
+  0x89, 0xbb, 0x9d, 0x3f, 0x62, 0xea, 0xbf, 0xda,
+  0x3a, 0x1b, 0xb9, 0xe7, 0x34, 0x3f, 0x3e, 0x4d,
+  0xcf, 0x9a, 0x3a, 0x7f, 0xe6, 0xff, 0x63, 0xc9,
+  0xee, 0x71, 0x68, 0x74, 0xff, 0xff, 0x77, 0xa0,
+  0x81, 0x7c, 0xe7, 0xbe, 0x19, 0x57, 0x8a, 0xd4,
+  0x74, 0x5a, 0x2b, 0xf2, 0x8f, 0x3f, 0xfe, 0xe7,
+  0xc1, 0x55, 0xd3, 0xdb, 0x97, 0x7d, 0xf7, 0xc5,
+  0x4f, 0x26, 0xea, 0x1a, 0x2c, 0xf9, 0xff, 0x7b,
+  0x2a, 0xff, 0x61, 0x71, 0x43, 0xa7, 0xff, 0xbc,
+  0x39, 0xde, 0x16, 0xd8, 0x2e, 0x96, 0x07, 0x4e,
+  0xfb, 0xef, 0x8a, 0x9f, 0xf6, 0xbe, 0x81, 0x69,
+  0xcd, 0x89, 0x4e, 0x2f, 0xe7, 0xf9, 0x73, 0xee,
+  0x43, 0x75, 0xa3, 0xa7, 0xfb, 0xc1, 0xcf, 0x5e,
+  0x7b, 0xc5, 0x0e, 0x84, 0x4f, 0xc4, 0x56, 0x98,
+  0x57, 0x93, 0xef, 0xdb, 0xb0, 0x94, 0xd8, 0xe2,
+  0x7f, 0x87, 0x7e, 0xcf, 0x94, 0x54, 0xe9, 0xff,
+  0xff, 0xfa, 0xef, 0xfa, 0x5d, 0x87, 0x4e, 0xa2,
+  0x0b, 0x79, 0x75, 0x02, 0xea, 0x65, 0xb0, 0xe9,
+  0xd4, 0x5a, 0x8e, 0x9d, 0xc5, 0x79, 0x3a, 0x1e,
+  0x8c, 0x2a, 0x42, 0x23, 0x03, 0x93, 0xd5, 0xff,
+  0xda, 0x1d, 0x3e, 0xc8, 0x2d, 0x89, 0x93, 0xfe,
+  0xf0, 0xbe, 0xc6, 0xae, 0xf7, 0x93, 0x44, 0x1a,
+  0xe3, 0x49, 0x3e, 0xd4, 0xf3, 0x14, 0xe9, 0xf9,
+  0xf9, 0x0d, 0xaf, 0x07, 0x4a, 0xd0, 0xf4, 0x80,
+  0x96, 0x7f, 0xff, 0xdb, 0xf6, 0x2f, 0x38, 0x5b,
+  0x0a, 0xf1, 0x63, 0xea, 0xb5, 0x87, 0x43, 0xd3,
+  0x3e, 0xb8, 0x57, 0x01, 0x2c, 0xfc, 0x37, 0xcd,
+  0x32, 0xa7, 0x4f, 0xff, 0xee, 0xc3, 0x7a, 0x70,
+  0xea, 0x1b, 0x8a, 0x7a, 0xbc, 0xfb, 0xe3, 0xa7,
+  0xff, 0xfa, 0x94, 0x51, 0xc2, 0xb9, 0x97, 0x8a,
+  0x75, 0xa6, 0xbe, 0xce, 0x9e, 0xcd, 0xf9, 0xb1,
+  0xd1, 0xe4, 0x44, 0xe5, 0x9a, 0x66, 0x37, 0x46,
+  0x8b, 0xf2, 0x7f, 0xe7, 0xe3, 0xb7, 0xbd, 0x98,
+  0xc2, 0xb0, 0xe9, 0xff, 0xbd, 0x61, 0x77, 0x4e,
+  0x0f, 0xa3, 0x0e, 0x8a, 0xd1, 0x15, 0x44, 0x69,
+  0xbc, 0xd1, 0xd3, 0xb1, 0xea, 0x8e, 0x9c, 0x0a,
+  0x87, 0x47, 0x03, 0xcd, 0x60, 0xb8, 0x0e, 0xc2,
+  0xa6, 0xed, 0xc9, 0x1d, 0xc2, 0xcb, 0x5c, 0x67,
+  0xff, 0xfe, 0x6f, 0x5c, 0xf9, 0x8e, 0x69, 0xfa,
+  0x3d, 0x73, 0xea, 0xe8, 0x9e, 0xa8, 0xe9, 0xef,
+  0xb6, 0xe8, 0x74, 0xff, 0x3d, 0x9a, 0xfc, 0x51,
+  0x7a, 0x1d, 0x0a, 0x7b, 0x7a, 0x43, 0x3d, 0x74,
+  0xf0, 0x1d, 0x00, 0x78, 0x1d, 0x90, 0x4f, 0x75,
+  0xef, 0x68, 0x74, 0xff, 0xb1, 0x4f, 0xfd, 0x5d,
+  0x6f, 0xbc, 0x1d, 0x0a, 0x7c, 0xd6, 0x49, 0x33,
+  0x5d, 0x9d, 0x26, 0x1d, 0x15, 0x9a, 0x86, 0xe4,
+  0x62, 0x7f, 0x6e, 0xd6, 0xf0, 0x5e, 0x4e, 0x9f,
+  0xff, 0xf6, 0x7d, 0x5e, 0x2e, 0xbc, 0x08, 0xae,
+  0x3f, 0xea, 0x0f, 0xcd, 0x9d, 0x3b, 0xef, 0xbe,
+  0x2a, 0x7b, 0x9e, 0x74, 0x0a, 0x71, 0x7f, 0x3f,
+  0xed, 0xca, 0x7b, 0x78, 0x53, 0x72, 0x74, 0x2a,
+  0x6a, 0xdc, 0x93, 0xa1, 0x97, 0xa1, 0x1d, 0x93,
+  0x19, 0xff, 0xac, 0x2b, 0xc5, 0x8f, 0xaa, 0xd6,
+  0x1d, 0x3e, 0xbc, 0x3d, 0x99, 0x3a, 0x7d, 0x5d,
+  0x01, 0x58, 0x74, 0x2a, 0x24, 0x68, 0x87, 0xd9,
+  0x3c, 0xdf, 0xe4, 0xe9, 0xfa, 0xa6, 0x9f, 0xc6,
+  0x8d, 0x47, 0x4f, 0xee, 0x99, 0xbc, 0x67, 0xd8,
+  0x3a, 0x6f, 0x09, 0xd0, 0xdd, 0xcf, 0xff, 0xc6,
+  0xb9, 0x35, 0x9f, 0xfb, 0x95, 0xe4, 0x57, 0x1e,
+  0x4f, 0x72, 0x74, 0xfd, 0x9e, 0xea, 0x6b, 0x3e,
+  0x3a, 0x39, 0x3f, 0x6c, 0xa2, 0xc9, 0xdc, 0x63,
+  0x3d, 0xa1, 0xb8, 0x0e, 0x2b, 0x4d, 0x45, 0x3c,
+  0xc3, 0x5a, 0xe5, 0x09, 0xf4, 0x66, 0xae, 0x1f,
+  0x1e, 0x35, 0x6a, 0x38, 0x61, 0x34, 0x61, 0x66,
+  0x65, 0x34, 0x6a, 0x0f, 0xf1, 0x8a, 0x84, 0x22,
+  0x29, 0x1c, 0xf6, 0x21, 0xc1, 0xf1, 0x87, 0x14,
+  0x25, 0xba, 0xc2, 0xae, 0x1c, 0xd8, 0x94, 0xe6,
+  0x9f, 0x69, 0x3f, 0xf9, 0xcc, 0xd7, 0xba, 0xc5,
+  0x37, 0x50, 0xd1, 0x36, 0x4f, 0xe7, 0x58, 0xa6,
+  0xea, 0x1a, 0x2a, 0xd9, 0xfc, 0xf7, 0xf7, 0x80,
+  0x57, 0x9d, 0x3d, 0x79, 0xdc, 0x1d, 0x26, 0xea,
+  0xcf, 0x4c, 0x0c, 0xe7, 0xc2, 0x9b, 0xa8, 0x68,
+  0xad, 0x27, 0xff, 0x91, 0x46, 0xff, 0xd6, 0x6b,
+  0xd7, 0xc8, 0x74, 0xff, 0xf3, 0xe9, 0x60, 0xac,
+  0xdb, 0xc6, 0x15, 0x87, 0x4d, 0x8c, 0x2a, 0x25,
+  0xf5, 0x2e, 0x7f, 0x2b, 0x6e, 0xb8, 0x05, 0xfc,
+  0xe9, 0xfa, 0xab, 0xcf, 0xad, 0x87, 0x4f, 0xf5,
+  0xb7, 0x82, 0xfd, 0x5b, 0xe8, 0x74, 0xfe, 0x7d,
+  0xe3, 0x43, 0xfe, 0xce, 0x93, 0xb8, 0xd4, 0xfc,
+  0x6c, 0xaf, 0xd0, 0xc7, 0xc9, 0x6e, 0x9b, 0x01,
+  0x6e, 0x0f, 0x27, 0xf3, 0xac, 0x53, 0x75, 0x0d,
+  0x16, 0x04, 0xf8, 0x53, 0x75, 0x0d, 0x13, 0xac,
+  0xff, 0xfe, 0xca, 0xd5, 0xcd, 0xb1, 0xd4, 0xa5,
+  0xe7, 0xd4, 0xee, 0xa3, 0xa7, 0xce, 0x66, 0xbd,
+  0xd6, 0x89, 0x56, 0x8c, 0x27, 0xc2, 0x9b, 0xa8,
+  0x68, 0xb6, 0x67, 0xfd, 0xfa, 0xd1, 0xd9, 0xf2,
+  0x68, 0x9d, 0x27, 0x59, 0xf6, 0xe9, 0x84, 0xf2,
+  0x6e, 0xa1, 0xa2, 0xe6, 0x93, 0x0e, 0x99, 0xd6,
+  0x26, 0xef, 0xe2, 0xb9, 0xfc, 0xeb, 0x14, 0xdd,
+  0x43, 0x45, 0xdf, 0x3c, 0xee, 0x9c, 0xfe, 0x74,
+  0x2b, 0x6e, 0x65, 0x75, 0x8a, 0x9a, 0x18, 0xd6,
+  0xa5, 0xe9, 0x4f, 0xe2, 0xe4, 0xc8, 0x68, 0x7f,
+  0x0a, 0xda, 0x30, 0xe0, 0xb3, 0xa9, 0xdc, 0xff,
+  0x83, 0x5c, 0xb4, 0xa3, 0x35, 0xe7, 0x4f, 0xe0,
+  0xaa, 0xdb, 0xf0, 0xbd, 0x0e, 0x9f, 0x0a, 0x6e,
+  0xa1, 0xa2, 0x57, 0x9f, 0xf0, 0x6f, 0xdc, 0xe5,
+  0x6a, 0xbf, 0x8e, 0x9e, 0xef, 0x45, 0xe7, 0x4f,
+  0xff, 0xef, 0x63, 0x59, 0xa1, 0xfe, 0x7e, 0xd0,
+  0xa9, 0x3d, 0x51, 0xd1, 0xca, 0x20, 0xf4, 0x86,
+  0x39, 0x47, 0x36, 0x61, 0x87, 0x3b, 0x5e, 0xe5,
+  0x4d, 0xda, 0xcd, 0xe9, 0x18, 0xb4, 0xec, 0x2f,
+  0x25, 0x4f, 0xfe, 0xce, 0xfb, 0x0a, 0xff, 0x0d,
+  0x5d, 0xfe, 0x54, 0xfe, 0xd4, 0x77, 0x22, 0xdc,
+  0xb9, 0x4f, 0xa2, 0x83, 0x92, 0x72, 0x2a, 0xae,
+  0x64, 0x76, 0x4d, 0xa1, 0x5d, 0x3f, 0xf9, 0xcc,
+  0xd7, 0xba, 0xc5, 0x37, 0x50, 0xd1, 0x30, 0xcf,
+  0xff, 0xd6, 0xee, 0xa3, 0xbf, 0xbb, 0xa6, 0x1f,
+  0xf2, 0xd1, 0xe7, 0x4f, 0xfc, 0xdd, 0x5d, 0x6f,
+  0xef, 0x70, 0x0a, 0xf3, 0xa7, 0xf2, 0xed, 0x58,
+  0xe9, 0xa2, 0x74, 0xfb, 0x45, 0xfa, 0xc3, 0xa0,
+  0x0f, 0x63, 0xb3, 0x39, 0xf9, 0x8b, 0x61, 0x8e,
+  0x23, 0xa7, 0xcb, 0x61, 0x8e, 0x23, 0xa7, 0xec,
+  0xfb, 0x14, 0xda, 0xf8, 0x1e, 0xb3, 0x0b, 0xa7,
+  0xff, 0xfc, 0x17, 0xf3, 0x7e, 0x2f, 0x3c, 0x02,
+  0xea, 0xf5, 0x85, 0x6f, 0xa1, 0xd3, 0xf3, 0x6e,
+  0xb8, 0x05, 0xfc, 0xe9, 0xff, 0xcb, 0x8f, 0xd5,
+  0xf7, 0x5e, 0x2a, 0xef, 0xe3, 0xa1, 0x4f, 0xff,
+  0xc6, 0x33, 0xf5, 0x3d, 0xd1, 0x9b, 0x83, 0xa7,
+  0xff, 0xfc, 0x36, 0xd9, 0x43, 0x1c, 0x3a, 0x82,
+  0xe7, 0x7d, 0x85, 0xc5, 0x0e, 0x95, 0xd6, 0x89,
+  0xd1, 0x2f, 0x9f, 0xff, 0x64, 0x2f, 0x19, 0xf5,
+  0xd7, 0x8b, 0x6c, 0xb4, 0x3a, 0x72, 0xff, 0xd4,
+  0xe8, 0xb3, 0xf4, 0x05, 0x69, 0xed, 0xeb, 0xcd,
+  0x9d, 0x27, 0x71, 0xaa, 0xfb, 0xb9, 0x85, 0x0a,
+  0x3c, 0x34, 0x91, 0x98, 0x78, 0x04, 0x2f, 0xb1,
+  0x09, 0xce, 0xc8, 0x27, 0xc2, 0x9b, 0xa8, 0x68,
+  0xab, 0xa7, 0xf9, 0xee, 0xb1, 0x4d, 0xd4, 0x34,
+  0x47, 0x92, 0x75, 0x9f, 0x8e, 0x98, 0x4f, 0xe7,
+  0x58, 0xa6, 0xea, 0x1a, 0x2c, 0x19, 0xfc, 0xeb,
+  0x14, 0xdd, 0x43, 0x45, 0x95, 0x3f, 0x9d, 0x62,
+  0x9b, 0xa8, 0x68, 0xb4, 0xe7, 0x93, 0x75, 0x0d,
+  0x16, 0xe4, 0xff, 0xcb, 0x63, 0x61, 0xc3, 0x37,
+  0x5f, 0xc7, 0x40, 0x9f, 0x7d, 0x0a, 0xe7, 0xf9,
+  0x43, 0xb6, 0x2d, 0x31, 0xe3, 0xa7, 0xfd, 0xaf,
+  0x75, 0x8a, 0x6e, 0xa1, 0xa2, 0x87, 0x9f, 0xf9,
+  0x9b, 0xca, 0xf3, 0x9f, 0x07, 0x98, 0x74, 0xff,
+  0xbb, 0x1f, 0xc7, 0x43, 0x17, 0xf9, 0xd3, 0xf5,
+  0x36, 0xba, 0x63, 0xc7, 0x4f, 0xc1, 0xc6, 0xd8,
+  0xad, 0x0e, 0x9f, 0xff, 0xaf, 0x9c, 0xaf, 0x57,
+  0x60, 0x37, 0xfa, 0x51, 0x7f, 0x2a, 0x4e, 0xb4,
+  0xf7, 0x7c, 0x42, 0xc3, 0x8d, 0x46, 0xa2, 0x2e,
+  0x0f, 0xbb, 0x2e, 0xe2, 0x2f, 0x9f, 0xce, 0xb1,
+  0x4d, 0xd4, 0x34, 0x5e, 0x70, 0xac, 0x9c, 0x07,
+  0xa2, 0x72, 0xa5, 0x73, 0x89, 0xd5, 0xc6, 0x08,
+  0x24, 0xcc, 0x3b, 0xc9, 0xd8, 0x4a, 0x87, 0x6c,
+  0xf5, 0x3f, 0x9d, 0x62, 0x9b, 0xa8, 0x68, 0xa5,
+  0xa7, 0xf3, 0xac, 0x53, 0x75, 0x0d, 0x16, 0x14,
+  0xfe, 0x75, 0x8a, 0x6e, 0xa1, 0xa2, 0xcb, 0x9e,
+  0x77, 0x46, 0xe3, 0xb7, 0x63, 0xa7, 0x3b, 0xab,
+  0x0e, 0x9e, 0x47, 0x2d, 0x10, 0xf4, 0x3b, 0x32,
+  0x9f, 0xfc, 0xe6, 0x6b, 0xdd, 0x62, 0x9b, 0xa8,
+  0x68, 0xa3, 0x27, 0xf3, 0x95, 0xb2, 0x8a, 0xfe,
+  0x74, 0x3d, 0x3b, 0xe1, 0x3b, 0x61, 0xde, 0xc2,
+  0x2e, 0x87, 0x18, 0x52, 0x9f, 0xf9, 0xda, 0xf7,
+  0x58, 0xa6, 0xea, 0x1a, 0x23, 0x99, 0xff, 0xce,
+  0x66, 0xbd, 0xd6, 0x29, 0xba, 0x86, 0x89, 0xca,
+  0x7f, 0x3a, 0xc5, 0x37, 0x50, 0xd1, 0x66, 0x4f,
+  0xfc, 0xe5, 0xfc, 0x57, 0x19, 0xda, 0xde, 0x74,
+  0xfe, 0x75, 0x8a, 0x6e, 0xa1, 0xa2, 0xdd, 0x9f,
+  0xfc, 0xe6, 0x6b, 0xdd, 0x62, 0x9b, 0xa8, 0x68,
+  0xa4, 0x27, 0xfe, 0x76, 0xbd, 0xd6, 0x29, 0xba,
+  0x86, 0x89, 0x4a, 0x2a, 0x4f, 0xd9, 0xa4, 0xc6,
+  0x29, 0x7e, 0x76, 0x08, 0x98, 0x3b, 0x6f, 0x52,
+  0x9f, 0xf6, 0xbd, 0xd6, 0x29, 0xba, 0x86, 0x89,
+  0xda, 0x7f, 0xfd, 0xee, 0x7b, 0x62, 0xb7, 0xef,
+  0x20, 0xa1, 0x68, 0x74, 0x9c, 0xc4, 0x4e, 0xea,
+  0x34, 0xff, 0xda, 0xcc, 0xda, 0x6e, 0x57, 0xab,
+  0xce, 0x9f, 0xf8, 0x2f, 0x3b, 0x55, 0xd0, 0x36,
+  0xb3, 0xa6, 0xe2, 0x77, 0x28, 0x85, 0xa2, 0x1c,
+  0x31, 0x1c, 0x1c, 0x50, 0xad, 0x9f, 0x0a, 0x6e,
+  0xa1, 0xa2, 0x2c, 0x9f, 0xf6, 0xbd, 0xd6, 0x29,
+  0xba, 0x86, 0x89, 0x76, 0x7f, 0xfe, 0xbe, 0x72,
+  0xbd, 0x5d, 0x80, 0xdf, 0xe9, 0x45, 0xfc, 0xa9,
+  0x3a, 0xd1, 0xa8, 0xc3, 0x0e, 0x24, 0x69, 0xff,
+  0xce, 0x66, 0xbd, 0xd6, 0x29, 0xba, 0x86, 0x89,
+  0x8a, 0x7e, 0xb1, 0x4d, 0xd4, 0x34, 0x55, 0x33,
+  0xff, 0xff, 0x87, 0x73, 0x5b, 0xef, 0x0e, 0xce,
+  0xd0, 0x7d, 0xf6, 0x33, 0xe1, 0x79, 0xd0, 0xe4,
+  0x56, 0xe9, 0xac, 0xff, 0xe7, 0x33, 0x5e, 0xeb,
+  0x14, 0xdd, 0x43, 0x44, 0xe9, 0x3f, 0xbd, 0xa2,
+  0xaf, 0xd6, 0xc7, 0x4f, 0x9a, 0x56, 0x96, 0x87,
+  0x4f, 0xdf, 0x5f, 0x9b, 0x58, 0x1d, 0x3d, 0xec,
+  0xab, 0xbc, 0x7a, 0xd4, 0x28, 0x9f, 0xfb, 0xba,
+  0x61, 0x6b, 0x77, 0x6d, 0x79, 0x87, 0x43, 0x11,
+  0x05, 0x93, 0x99, 0xff, 0x6b, 0xdd, 0x62, 0x9b,
+  0xa8, 0x68, 0x9d, 0xe7, 0xd8, 0xef, 0x59, 0xe2,
+  0xa4, 0xee, 0x53, 0x9b, 0xb8, 0xc2, 0x98, 0x47,
+  0xa8, 0xd3, 0xff, 0x9c, 0xcd, 0x7b, 0xac, 0x53,
+  0x75, 0x0d, 0x14, 0x2c, 0xff, 0xe7, 0x33, 0x5e,
+  0xeb, 0x14, 0xdd, 0x43, 0x45, 0x25, 0x3f, 0xff,
+  0xae, 0x8e, 0xeb, 0x6d, 0x67, 0x59, 0x8c, 0xae,
+  0x3b, 0x61, 0xd1, 0x52, 0xe4, 0xbb, 0xce, 0x12,
+  0x1f, 0xe2, 0x44, 0xc8, 0xfb, 0x7f, 0x49, 0xed,
+  0x4b, 0x89, 0x4a, 0x7f, 0x3a, 0xc5, 0x37, 0x50,
+  0xd1, 0x12, 0x4f, 0xfe, 0x73, 0x35, 0xee, 0xb1,
+  0x4d, 0xd4, 0x34, 0x4b, 0xd3, 0xe1, 0xfd, 0x9e,
+  0xa1, 0xd3, 0xbf, 0x5c, 0x1d, 0x3f, 0xf6, 0xb5,
+  0x45, 0x6d, 0xb9, 0x5a, 0xda, 0x3a, 0x3c, 0x88,
+  0xb6, 0x8a, 0x04, 0x72, 0x7f, 0xbd, 0xa1, 0xde,
+  0x1a, 0x5e, 0x87, 0x4f, 0x85, 0x37, 0x50, 0xd1,
+  0x4b, 0xcf, 0xfe, 0xb7, 0xaf, 0xf4, 0x15, 0xad,
+  0xfe, 0x61, 0xd3, 0xe6, 0xff, 0x31, 0x68, 0x74,
+  0xfb, 0x5b, 0x58, 0xd0, 0xe9, 0x2f, 0x27, 0xa2,
+  0xc2, 0xa9, 0x39, 0x53, 0x5e, 0xe4, 0xc2, 0xce,
+  0xda, 0x30, 0xc4, 0x26, 0xe7, 0xf3, 0xac, 0x53,
+  0x75, 0x0d, 0x14, 0xe4, 0xff, 0xbc, 0x3b, 0x4c,
+  0xdd, 0x82, 0x1d, 0x3f, 0xeb, 0xca, 0x8d, 0xbb,
+  0xef, 0xbe, 0x2a, 0x6f, 0x7c, 0x74, 0xd5, 0x3b,
+  0x94, 0x48, 0x71, 0x1d, 0x37, 0x9f, 0xcf, 0x85,
+  0x37, 0x50, 0xd1, 0x5e, 0x4f, 0xff, 0xd7, 0xce,
+  0x57, 0xab, 0xb0, 0x1b, 0xfd, 0x28, 0xbf, 0x95,
+  0x27, 0x5a, 0x23, 0xb8, 0x8c, 0x27, 0xfe, 0x76,
+  0xbd, 0xd6, 0x29, 0xba, 0x86, 0x89, 0x1e, 0x77,
+  0xbf, 0x53, 0xa7, 0x25, 0xb0, 0xa7, 0x17, 0x93,
+  0xe1, 0x4d, 0xd4, 0x34, 0x49, 0x13, 0xce, 0xd7,
+  0xb9, 0x4f, 0x66, 0xca, 0x67, 0xfe, 0x76, 0xbd,
+  0xd6, 0x29, 0xba, 0x86, 0x89, 0x2a, 0x7c, 0x29,
+  0xba, 0x86, 0x8b, 0xc6, 0x7e, 0xec, 0x2b, 0xda,
+  0xe8, 0x74, 0xfa, 0x94, 0xc5, 0xa1, 0xd3, 0xfc,
+  0xf7, 0x58, 0xa6, 0xea, 0x1a, 0x24, 0xd9, 0x3a,
+  0xd1, 0x8d, 0x59, 0x80, 0x97, 0xe9, 0x34, 0x2a,
+  0xf6, 0xfd, 0x47, 0x6f, 0x94, 0x77, 0xca, 0xb7,
+  0xa1, 0x96, 0xd4, 0x34, 0x98, 0x57, 0x98, 0x60,
+  0xe0, 0xdf, 0xb8, 0xc4, 0xa1, 0x63, 0x8e, 0x24,
+  0xaa, 0x3b, 0x07, 0xca, 0x0a, 0xe6, 0x50, 0xd5,
+  0xdb, 0xd1, 0x3e, 0x92, 0x96, 0x92, 0xd0, 0xde,
+  0x57, 0x3d, 0xa7, 0xe9, 0xd2, 0xfe, 0x3c, 0x76,
+  0xcd, 0x56, 0x0a, 0x83, 0x4a, 0x55, 0x66, 0x24,
+  0xec, 0x73, 0x3b, 0xfd, 0xb5, 0x8f, 0x37, 0xf2,
+  0xc5, 0xdb, 0x98, 0x58, 0x85, 0x21, 0x9a, 0x94,
+  0x98, 0x1c, 0x57, 0x83, 0xbd, 0xd3, 0x49, 0x9b,
+  0x4a, 0x62, 0xfa, 0x52, 0x8f, 0x14, 0x7c, 0xfd,
+  0x67, 0x65, 0x9b, 0xe7, 0xd8, 0xa0,
 };
 
-static const unsigned kPreloadedHSTSBits = 103990;
+static const unsigned kPreloadedHSTSBits = 103917;
 
-static const unsigned kHSTSRootPosition = 103406;
+static const unsigned kHSTSRootPosition = 103333;
 
 #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 a8a5bf1..ff5d79a 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -1217,7 +1217,6 @@
     { "name": "cloudstoragemaus.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "comdurav.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "digitaldaddy.net", "include_subdomains": true, "mode": "force-https" },
-    { "name": "eldietista.es", "include_subdomains": true, "mode": "force-https" },
     { "name": "elnutricionista.es", "include_subdomains": true, "mode": "force-https" },
     { "name": "fronteers.nl", "include_subdomains": true, "mode": "force-https" },
     { "name": "getssl.uz", "include_subdomains": true, "mode": "force-https" },
diff --git a/net/net.gyp b/net/net.gyp
index 8bfcc7b..c1338bf 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -665,6 +665,10 @@
         [ 'enable_websockets != 1', {
             'sources/': [
               ['exclude', '^websockets/'],
+              ['exclude', '^server/'],
+            ],
+            'dependencies!': [
+              'http_server',
             ],
         }],
         ['disable_file_support==1', {
@@ -959,6 +963,8 @@
         '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_data_job.cc',
+        'test/url_request/url_request_mock_data_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',
@@ -1075,6 +1081,8 @@
         'server/http_server_response_info.h',
         'server/web_socket.cc',
         'server/web_socket.h',
+        'server/web_socket_encoder.cc',
+        'server/web_socket_encoder.h',
       ],
       # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
       'msvs_disabled_warnings': [4267, ],
diff --git a/net/net.gypi b/net/net.gypi
index 7d7d2f0..5ca70f7 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -153,6 +153,8 @@
       'ssl/signed_certificate_timestamp_and_status.h',
       'ssl/ssl_cert_request_info.cc',
       'ssl/ssl_cert_request_info.h',
+      'ssl/ssl_cipher_suite_names.cc',
+      'ssl/ssl_cipher_suite_names.h',
       'ssl/ssl_client_auth_cache.cc',
       'ssl/ssl_client_auth_cache.h',
       'ssl/ssl_client_cert_type.h',
@@ -1107,8 +1109,6 @@
       'ssl/client_cert_store_nss.h',
       'ssl/client_cert_store_win.cc',
       'ssl/client_cert_store_win.h',
-      'ssl/ssl_cipher_suite_names.cc',
-      'ssl/ssl_cipher_suite_names.h',
       'ssl/ssl_config_service_defaults.cc',
       'ssl/ssl_config_service_defaults.h',
       'third_party/mozilla_security_manager/nsKeygenHandler.cpp',
@@ -1587,6 +1587,7 @@
       'server/http_connection_unittest.cc',
       'server/http_server_response_info_unittest.cc',
       'server/http_server_unittest.cc',
+      'server/web_socket_encoder_unittest.cc',
       'socket/client_socket_pool_base_unittest.cc',
       'socket/deterministic_socket_data_unittest.cc',
       'socket/mock_client_socket_pool_manager.cc',
diff --git a/net/proxy/proxy_config_service_android.cc b/net/proxy/proxy_config_service_android.cc
index 50407fe..80e3b92 100644
--- a/net/proxy/proxy_config_service_android.cc
+++ b/net/proxy/proxy_config_service_android.cc
@@ -98,6 +98,12 @@
   // by | and that use * as a wildcard. For example, setting the
   // http.nonProxyHosts property to *.android.com|*.kernel.org will cause
   // requests to http://developer.android.com to be made without a proxy.
+
+  // Force localhost to be on the proxy exclusion list;
+  // otherwise all localhost traffic is routed through
+  // the proxy which is not desired.
+  bypass_rules->AddRuleToBypassLocal();
+
   std::string non_proxy_hosts =
       get_property.Run(scheme + ".nonProxyHosts");
   if (non_proxy_hosts.empty())
diff --git a/net/proxy/proxy_resolver_script.h b/net/proxy/proxy_resolver_script.h
index 283eff9..e838bed 100644
--- a/net/proxy/proxy_resolver_script.h
+++ b/net/proxy/proxy_resolver_script.h
@@ -1,3 +1,10 @@
+// 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 NET_PROXY_PROXY_RESOLVER_SCRIPT_H_
+#define NET_PROXY_PROXY_RESOLVER_SCRIPT_H_
+
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
@@ -37,9 +44,6 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef NET_PROXY_PROXY_RESOLVER_SCRIPT_H_
-#define NET_PROXY_PROXY_RESOLVER_SCRIPT_H_
-
 // The following code was formatted from:
 //   'mozilla/netwerk/base/src/nsProxyAutoConfig.js' (1.55)
 //
@@ -51,6 +55,8 @@
 //       sed -e 's/"$/" \\/g' |
 //       sed -e 's/\/(ipaddr);/\/.exec(ipaddr);/g' |
 //       grep -v '^var pacUtils ='
+//
+// isPlainHost() was removed.
 #define PROXY_RESOLVER_SCRIPT \
   "function dnsDomainIs(host, domain) {\n" \
   "    return (host.length >= domain.length &&\n" \
@@ -87,10 +93,6 @@
   "    \n" \
   "}\n" \
   "" \
-  "function isPlainHostName(host) {\n" \
-  "    return (host.search('\\\\.') == -1);\n" \
-  "}\n" \
-  "" \
   "function isResolvable(host) {\n" \
   "    var ip = dnsResolve(host);\n" \
   "    return (ip != null);\n" \
diff --git a/net/proxy/proxy_resolver_v8.cc b/net/proxy/proxy_resolver_v8.cc
index 963153d..57ee714 100644
--- a/net/proxy/proxy_resolver_v8.cc
+++ b/net/proxy/proxy_resolver_v8.cc
@@ -334,6 +334,17 @@
   return IPNumberMatchesPrefix(address, prefix, prefix_length_in_bits);
 }
 
+// Consider only single component domains like 'foo' as plain host names.
+bool IsPlainHostName(const std::string& hostname_utf8) {
+  if (hostname_utf8.find('.') != std::string::npos)
+    return false;
+
+  // IPv6 addresses may not contain periods, however are not be considered a
+  // plain host name.
+  IPAddressNumber unused;
+  return !ParseIPLiteralToNumber(hostname_utf8, &unused);
+}
+
 }  // namespace
 
 // ProxyResolverV8::Context ---------------------------------------------------
@@ -439,6 +450,11 @@
     global_template->Set(ASCIILiteralToV8String(isolate_, "dnsResolve"),
                          dns_resolve_template);
 
+    v8::Local<v8::FunctionTemplate> is_plain_host_name_template =
+        v8::FunctionTemplate::New(isolate_, &IsPlainHostNameCallback, v8_this);
+    global_template->Set(ASCIILiteralToV8String(isolate_, "isPlainHostName"),
+                         is_plain_host_name_template);
+
     // Microsoft's PAC extensions:
 
     v8::Local<v8::FunctionTemplate> dns_resolve_ex_template =
@@ -698,6 +714,22 @@
     args.GetReturnValue().Set(IsInNetEx(ip_address, ip_prefix));
   }
 
+  // V8 callback for when "isPlainHostName()" is invoked by the PAC script.
+  static void IsPlainHostNameCallback(
+      const v8::FunctionCallbackInfo<v8::Value>& args) {
+    // Need at least 1 string arguments.
+    if (args.Length() < 1 || args[0].IsEmpty() || !args[0]->IsString()) {
+      args.GetIsolate()->ThrowException(
+          v8::Exception::TypeError(ASCIIStringToV8String(
+              args.GetIsolate(), "Requires 1 string parameter")));
+      return;
+    }
+
+    std::string hostname_utf8 =
+        V8StringToUTF8(v8::Local<v8::String>::Cast(args[0]));
+    args.GetReturnValue().Set(IsPlainHostName(hostname_utf8));
+  }
+
   mutable base::Lock lock_;
   ProxyResolverV8* parent_;
   v8::Isolate* isolate_;
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 738326a..ecd338a 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -292,13 +292,17 @@
 }
 
 void QuicStreamFactory::Job::OnIOComplete(int rv) {
-  // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
-  tracked_objects::ScopedTracker tracking_profile(
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "436634 QuicStreamFactory::Job::OnIOComplete"));
+          "422516 QuicStreamFactory::Job::OnIOComplete1"));
 
   rv = DoLoop(rv);
 
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "422516 QuicStreamFactory::Job::OnIOComplete2"));
+
   if (rv != ERR_IO_PENDING && !callback_.is_null()) {
     callback_.Run(rv);
   }
@@ -647,6 +651,11 @@
 
 void QuicStreamFactory::OnJobComplete(Job* job, int rv) {
   if (rv == OK) {
+    // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
+    tracked_objects::ScopedTracker tracking_profile1(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "422516 QuicStreamFactory::OnJobComplete1"));
+
     if (!always_require_handshake_confirmation_)
       set_require_confirmation(false);
 
@@ -658,6 +667,12 @@
                                               (*it)->net_log()));
     }
   }
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "422516 QuicStreamFactory::OnJobComplete2"));
+
   while (!job_requests_map_[job].empty()) {
     RequestSet::iterator it = job_requests_map_[job].begin();
     QuicStreamRequest* request = *it;
@@ -668,6 +683,12 @@
     // profile which can not be deleted via callbacks.
     request->OnRequestComplete(rv);
   }
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
+  tracked_objects::ScopedTracker tracking_profile3(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "422516 QuicStreamFactory::OnJobComplete3"));
+
   active_jobs_.erase(job->server_id());
   job_requests_map_.erase(job);
   delete job;
diff --git a/net/server/web_socket.cc b/net/server/web_socket.cc
index d67ecb6..e5d1cb7 100644
--- a/net/server/web_socket.cc
+++ b/net/server/web_socket.cc
@@ -4,10 +4,7 @@
 
 #include "net/server/web_socket.h"
 
-#include <limits>
-
 #include "base/base64.h"
-#include "base/rand_util.h"
 #include "base/logging.h"
 #include "base/md5.h"
 #include "base/sha1.h"
@@ -18,6 +15,7 @@
 #include "net/server/http_server.h"
 #include "net/server/http_server_request_info.h"
 #include "net/server/http_server_response_info.h"
+#include "net/server/web_socket_encoder.h"
 
 namespace net {
 
@@ -152,31 +150,6 @@
 
 const int WebSocketHixie76::kWebSocketHandshakeBodyLen = 8;
 
-
-// Constants for hybi-10 frame format.
-
-typedef int OpCode;
-
-const OpCode kOpCodeContinuation = 0x0;
-const OpCode kOpCodeText = 0x1;
-const OpCode kOpCodeBinary = 0x2;
-const OpCode kOpCodeClose = 0x8;
-const OpCode kOpCodePing = 0x9;
-const OpCode kOpCodePong = 0xA;
-
-const unsigned char kFinalBit = 0x80;
-const unsigned char kReserved1Bit = 0x40;
-const unsigned char kReserved2Bit = 0x20;
-const unsigned char kReserved3Bit = 0x10;
-const unsigned char kOpCodeMask = 0xF;
-const unsigned char kMaskBit = 0x80;
-const unsigned char kPayloadLengthMask = 0x7F;
-
-const size_t kMaxSingleBytePayloadLength = 125;
-const size_t kTwoBytePayloadLengthField = 126;
-const size_t kEightBytePayloadLengthField = 127;
-const size_t kMaskingKeyWidthInBytes = 4;
-
 class WebSocketHybi17 : public WebSocket {
  public:
   static WebSocket* Create(HttpServer* server,
@@ -207,22 +180,22 @@
     std::string encoded_hash;
     base::Base64Encode(base::SHA1HashString(data), &encoded_hash);
 
-    server_->SendRaw(
-        connection_->id(),
-        base::StringPrintf("HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
-                           "Upgrade: WebSocket\r\n"
-                           "Connection: Upgrade\r\n"
-                           "Sec-WebSocket-Accept: %s\r\n"
-                           "\r\n",
-                           encoded_hash.c_str()));
+    server_->SendRaw(connection_->id(),
+                     base::StringPrintf(
+                         "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
+                         "Upgrade: WebSocket\r\n"
+                         "Connection: Upgrade\r\n"
+                         "Sec-WebSocket-Accept: %s\r\n"
+                         "%s"
+                         "\r\n",
+                         encoded_hash.c_str(), response_extensions_.c_str()));
   }
 
   ParseResult Read(std::string* message) override {
     HttpConnection::ReadIOBuffer* read_buf = connection_->read_buf();
     base::StringPiece frame(read_buf->StartOfBuffer(), read_buf->GetSize());
     int bytes_consumed = 0;
-    ParseResult result =
-        WebSocket::DecodeFrameHybi17(frame, true, &bytes_consumed, message);
+    ParseResult result = encoder_->DecodeFrame(frame, &bytes_consumed, message);
     if (result == FRAME_OK)
       read_buf->DidConsume(bytes_consumed);
     if (result == FRAME_CLOSE)
@@ -233,8 +206,9 @@
   void Send(const std::string& message) override {
     if (closed_)
       return;
-    server_->SendRaw(connection_->id(),
-                     WebSocket::EncodeFrameHybi17(message, 0));
+    std::string encoded;
+    encoder_->EncodeFrame(message, 0, &encoded);
+    server_->SendRaw(connection_->id(), encoded);
   }
 
  private:
@@ -243,27 +217,19 @@
                   const HttpServerRequestInfo& request,
                   size_t* pos)
       : WebSocket(server, connection),
-        op_code_(0),
-        final_(false),
-        reserved1_(false),
-        reserved2_(false),
-        reserved3_(false),
-        masked_(false),
-        payload_(0),
-        payload_length_(0),
-        frame_end_(0),
         closed_(false) {
+    std::string request_extensions =
+        request.GetHeaderValue("sec-websocket-extensions");
+    encoder_.reset(WebSocketEncoder::CreateServer(request_extensions,
+                                                  &response_extensions_));
+    if (!response_extensions_.empty()) {
+      response_extensions_ =
+          "Sec-WebSocket-Extensions: " + response_extensions_ + "\r\n";
+    }
   }
 
-  OpCode op_code_;
-  bool final_;
-  bool reserved1_;
-  bool reserved2_;
-  bool reserved3_;
-  bool masked_;
-  const char* payload_;
-  size_t payload_length_;
-  const char* frame_end_;
+  scoped_ptr<WebSocketEncoder> encoder_;
+  std::string response_extensions_;
   bool closed_;
 
   DISALLOW_COPY_AND_ASSIGN(WebSocketHybi17);
@@ -282,142 +248,12 @@
   return WebSocketHixie76::Create(server, connection, request, pos);
 }
 
-// static
-WebSocket::ParseResult WebSocket::DecodeFrameHybi17(
-    const base::StringPiece& frame,
-    bool client_frame,
-    int* bytes_consumed,
-    std::string* output) {
-  size_t data_length = frame.length();
-  if (data_length < 2)
-    return FRAME_INCOMPLETE;
-
-  const char* buffer_begin = const_cast<char*>(frame.data());
-  const char* p = buffer_begin;
-  const char* buffer_end = p + data_length;
-
-  unsigned char first_byte = *p++;
-  unsigned char second_byte = *p++;
-
-  bool final = (first_byte & kFinalBit) != 0;
-  bool reserved1 = (first_byte & kReserved1Bit) != 0;
-  bool reserved2 = (first_byte & kReserved2Bit) != 0;
-  bool reserved3 = (first_byte & kReserved3Bit) != 0;
-  int op_code = first_byte & kOpCodeMask;
-  bool masked = (second_byte & kMaskBit) != 0;
-  if (!final || reserved1 || reserved2 || reserved3)
-    return FRAME_ERROR;  // Extensions and not supported.
-
-  bool closed = false;
-  switch (op_code) {
-  case kOpCodeClose:
-    closed = true;
-    break;
-  case kOpCodeText:
-    break;
-  case kOpCodeBinary: // We don't support binary frames yet.
-  case kOpCodeContinuation: // We don't support binary frames yet.
-  case kOpCodePing: // We don't support binary frames yet.
-  case kOpCodePong: // We don't support binary frames yet.
-  default:
-    return FRAME_ERROR;
-  }
-
-  if (client_frame && !masked) // In Hybi-17 spec client MUST mask his frame.
-    return FRAME_ERROR;
-
-  uint64 payload_length64 = second_byte & kPayloadLengthMask;
-  if (payload_length64 > kMaxSingleBytePayloadLength) {
-    int extended_payload_length_size;
-    if (payload_length64 == kTwoBytePayloadLengthField)
-      extended_payload_length_size = 2;
-    else {
-      DCHECK(payload_length64 == kEightBytePayloadLengthField);
-      extended_payload_length_size = 8;
-    }
-    if (buffer_end - p < extended_payload_length_size)
-      return FRAME_INCOMPLETE;
-    payload_length64 = 0;
-    for (int i = 0; i < extended_payload_length_size; ++i) {
-      payload_length64 <<= 8;
-      payload_length64 |= static_cast<unsigned char>(*p++);
-    }
-  }
-
-  size_t actual_masking_key_length = masked ? kMaskingKeyWidthInBytes : 0;
-  static const uint64 max_payload_length = 0x7FFFFFFFFFFFFFFFull;
-  static size_t max_length = std::numeric_limits<size_t>::max();
-  if (payload_length64 > max_payload_length ||
-      payload_length64 + actual_masking_key_length > max_length) {
-    // WebSocket frame length too large.
-    return FRAME_ERROR;
-  }
-  size_t payload_length = static_cast<size_t>(payload_length64);
-
-  size_t total_length = actual_masking_key_length + payload_length;
-  if (static_cast<size_t>(buffer_end - p) < total_length)
-    return FRAME_INCOMPLETE;
-
-  if (masked) {
-    output->resize(payload_length);
-    const char* masking_key = p;
-    char* payload = const_cast<char*>(p + kMaskingKeyWidthInBytes);
-    for (size_t i = 0; i < payload_length; ++i)  // Unmask the payload.
-      (*output)[i] = payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes];
-  } else {
-    output->assign(p, p + payload_length);
-  }
-
-  size_t pos = p + actual_masking_key_length + payload_length - buffer_begin;
-  *bytes_consumed = pos;
-  return closed ? FRAME_CLOSE : FRAME_OK;
-}
-
-// static
-std::string WebSocket::EncodeFrameHybi17(const std::string& message,
-                                         int masking_key) {
-  std::vector<char> frame;
-  OpCode op_code = kOpCodeText;
-  size_t data_length = message.length();
-
-  frame.push_back(kFinalBit | op_code);
-  char mask_key_bit = masking_key != 0 ? kMaskBit : 0;
-  if (data_length <= kMaxSingleBytePayloadLength)
-    frame.push_back(data_length | mask_key_bit);
-  else if (data_length <= 0xFFFF) {
-    frame.push_back(kTwoBytePayloadLengthField | mask_key_bit);
-    frame.push_back((data_length & 0xFF00) >> 8);
-    frame.push_back(data_length & 0xFF);
-  } else {
-    frame.push_back(kEightBytePayloadLengthField | mask_key_bit);
-    char extended_payload_length[8];
-    size_t remaining = data_length;
-    // Fill the length into extended_payload_length in the network byte order.
-    for (int i = 0; i < 8; ++i) {
-      extended_payload_length[7 - i] = remaining & 0xFF;
-      remaining >>= 8;
-    }
-    frame.insert(frame.end(),
-                 extended_payload_length,
-                 extended_payload_length + 8);
-    DCHECK(!remaining);
-  }
-
-  const char* data = const_cast<char*>(message.data());
-  if (masking_key != 0) {
-    const char* mask_bytes = reinterpret_cast<char*>(&masking_key);
-    frame.insert(frame.end(), mask_bytes, mask_bytes + 4);
-    for (size_t i = 0; i < data_length; ++i)  // Mask the payload.
-      frame.push_back(data[i] ^ mask_bytes[i % kMaskingKeyWidthInBytes]);
-  } else {
-    frame.insert(frame.end(), data, data + data_length);
-  }
-  return std::string(&frame[0], frame.size());
-}
-
 WebSocket::WebSocket(HttpServer* server, HttpConnection* connection)
     : server_(server),
       connection_(connection) {
 }
 
+WebSocket::~WebSocket() {
+}
+
 }  // namespace net
diff --git a/net/server/web_socket.h b/net/server/web_socket.h
index 9b3a794..3f2c1d8 100644
--- a/net/server/web_socket.h
+++ b/net/server/web_socket.h
@@ -30,18 +30,10 @@
                                     const HttpServerRequestInfo& request,
                                     size_t* pos);
 
-  static ParseResult DecodeFrameHybi17(const base::StringPiece& frame,
-                                       bool client_frame,
-                                       int* bytes_consumed,
-                                       std::string* output);
-
-  static std::string EncodeFrameHybi17(const std::string& data,
-                                       int masking_key);
-
   virtual void Accept(const HttpServerRequestInfo& request) = 0;
   virtual ParseResult Read(std::string* message) = 0;
   virtual void Send(const std::string& message) = 0;
-  virtual ~WebSocket() {}
+  virtual ~WebSocket();
 
  protected:
   WebSocket(HttpServer* server, HttpConnection* connection);
diff --git a/net/server/web_socket_encoder.cc b/net/server/web_socket_encoder.cc
new file mode 100644
index 0000000..cb23326
--- /dev/null
+++ b/net/server/web_socket_encoder.cc
@@ -0,0 +1,364 @@
+// 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 "net/server/web_socket_encoder.h"
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "net/base/io_buffer.h"
+#include "net/websockets/websocket_extension_parser.h"
+
+namespace net {
+
+const char WebSocketEncoder::kClientExtensions[] =
+    "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits";
+
+namespace {
+
+const int kInflaterChunkSize = 16 * 1024;
+
+// Constants for hybi-10 frame format.
+
+typedef int OpCode;
+
+const OpCode kOpCodeContinuation = 0x0;
+const OpCode kOpCodeText = 0x1;
+const OpCode kOpCodeBinary = 0x2;
+const OpCode kOpCodeClose = 0x8;
+const OpCode kOpCodePing = 0x9;
+const OpCode kOpCodePong = 0xA;
+
+const unsigned char kFinalBit = 0x80;
+const unsigned char kReserved1Bit = 0x40;
+const unsigned char kReserved2Bit = 0x20;
+const unsigned char kReserved3Bit = 0x10;
+const unsigned char kOpCodeMask = 0xF;
+const unsigned char kMaskBit = 0x80;
+const unsigned char kPayloadLengthMask = 0x7F;
+
+const size_t kMaxSingleBytePayloadLength = 125;
+const size_t kTwoBytePayloadLengthField = 126;
+const size_t kEightBytePayloadLengthField = 127;
+const size_t kMaskingKeyWidthInBytes = 4;
+
+WebSocket::ParseResult DecodeFrameHybi17(const base::StringPiece& frame,
+                                         bool client_frame,
+                                         int* bytes_consumed,
+                                         std::string* output,
+                                         bool* compressed) {
+  size_t data_length = frame.length();
+  if (data_length < 2)
+    return WebSocket::FRAME_INCOMPLETE;
+
+  const char* buffer_begin = const_cast<char*>(frame.data());
+  const char* p = buffer_begin;
+  const char* buffer_end = p + data_length;
+
+  unsigned char first_byte = *p++;
+  unsigned char second_byte = *p++;
+
+  bool final = (first_byte & kFinalBit) != 0;
+  bool reserved1 = (first_byte & kReserved1Bit) != 0;
+  bool reserved2 = (first_byte & kReserved2Bit) != 0;
+  bool reserved3 = (first_byte & kReserved3Bit) != 0;
+  int op_code = first_byte & kOpCodeMask;
+  bool masked = (second_byte & kMaskBit) != 0;
+  *compressed = reserved1;
+  if (!final || reserved2 || reserved3)
+    return WebSocket::FRAME_ERROR;  // Only compression extension is supported.
+
+  bool closed = false;
+  switch (op_code) {
+    case kOpCodeClose:
+      closed = true;
+      break;
+    case kOpCodeText:
+      break;
+    case kOpCodeBinary:        // We don't support binary frames yet.
+    case kOpCodeContinuation:  // We don't support binary frames yet.
+    case kOpCodePing:          // We don't support binary frames yet.
+    case kOpCodePong:          // We don't support binary frames yet.
+    default:
+      return WebSocket::FRAME_ERROR;
+  }
+
+  if (client_frame && !masked)  // In Hybi-17 spec client MUST mask his frame.
+    return WebSocket::FRAME_ERROR;
+
+  uint64 payload_length64 = second_byte & kPayloadLengthMask;
+  if (payload_length64 > kMaxSingleBytePayloadLength) {
+    int extended_payload_length_size;
+    if (payload_length64 == kTwoBytePayloadLengthField)
+      extended_payload_length_size = 2;
+    else {
+      DCHECK(payload_length64 == kEightBytePayloadLengthField);
+      extended_payload_length_size = 8;
+    }
+    if (buffer_end - p < extended_payload_length_size)
+      return WebSocket::FRAME_INCOMPLETE;
+    payload_length64 = 0;
+    for (int i = 0; i < extended_payload_length_size; ++i) {
+      payload_length64 <<= 8;
+      payload_length64 |= static_cast<unsigned char>(*p++);
+    }
+  }
+
+  size_t actual_masking_key_length = masked ? kMaskingKeyWidthInBytes : 0;
+  static const uint64 max_payload_length = 0x7FFFFFFFFFFFFFFFull;
+  static size_t max_length = std::numeric_limits<size_t>::max();
+  if (payload_length64 > max_payload_length ||
+      payload_length64 + actual_masking_key_length > max_length) {
+    // WebSocket frame length too large.
+    return WebSocket::FRAME_ERROR;
+  }
+  size_t payload_length = static_cast<size_t>(payload_length64);
+
+  size_t total_length = actual_masking_key_length + payload_length;
+  if (static_cast<size_t>(buffer_end - p) < total_length)
+    return WebSocket::FRAME_INCOMPLETE;
+
+  if (masked) {
+    output->resize(payload_length);
+    const char* masking_key = p;
+    char* payload = const_cast<char*>(p + kMaskingKeyWidthInBytes);
+    for (size_t i = 0; i < payload_length; ++i)  // Unmask the payload.
+      (*output)[i] = payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes];
+  } else {
+    output->assign(p, p + payload_length);
+  }
+
+  size_t pos = p + actual_masking_key_length + payload_length - buffer_begin;
+  *bytes_consumed = pos;
+  return closed ? WebSocket::FRAME_CLOSE : WebSocket::FRAME_OK;
+}
+
+void EncodeFrameHybi17(const std::string& message,
+                       int masking_key,
+                       bool compressed,
+                       std::string* output) {
+  std::vector<char> frame;
+  OpCode op_code = kOpCodeText;
+  size_t data_length = message.length();
+
+  int reserved1 = compressed ? kReserved1Bit : 0;
+  frame.push_back(kFinalBit | op_code | reserved1);
+  char mask_key_bit = masking_key != 0 ? kMaskBit : 0;
+  if (data_length <= kMaxSingleBytePayloadLength)
+    frame.push_back(data_length | mask_key_bit);
+  else if (data_length <= 0xFFFF) {
+    frame.push_back(kTwoBytePayloadLengthField | mask_key_bit);
+    frame.push_back((data_length & 0xFF00) >> 8);
+    frame.push_back(data_length & 0xFF);
+  } else {
+    frame.push_back(kEightBytePayloadLengthField | mask_key_bit);
+    char extended_payload_length[8];
+    size_t remaining = data_length;
+    // Fill the length into extended_payload_length in the network byte order.
+    for (int i = 0; i < 8; ++i) {
+      extended_payload_length[7 - i] = remaining & 0xFF;
+      remaining >>= 8;
+    }
+    frame.insert(frame.end(), extended_payload_length,
+                 extended_payload_length + 8);
+    DCHECK(!remaining);
+  }
+
+  const char* data = const_cast<char*>(message.data());
+  if (masking_key != 0) {
+    const char* mask_bytes = reinterpret_cast<char*>(&masking_key);
+    frame.insert(frame.end(), mask_bytes, mask_bytes + 4);
+    for (size_t i = 0; i < data_length; ++i)  // Mask the payload.
+      frame.push_back(data[i] ^ mask_bytes[i % kMaskingKeyWidthInBytes]);
+  } else {
+    frame.insert(frame.end(), data, data + data_length);
+  }
+  *output = std::string(&frame[0], frame.size());
+}
+
+}  // anonymous namespace
+
+// static
+WebSocketEncoder* WebSocketEncoder::CreateServer(
+    const std::string& request_extensions,
+    std::string* response_extensions) {
+  bool deflate;
+  int client_window_bits;
+  int server_window_bits;
+  bool client_no_context_takeover;
+  bool server_no_context_takeover;
+  ParseExtensions(request_extensions, &deflate, &client_window_bits,
+                  &server_window_bits, &client_no_context_takeover,
+                  &server_no_context_takeover);
+
+  if (deflate) {
+    *response_extensions = base::StringPrintf(
+        "permessage-deflate; server_max_window_bits=%d; "
+        "client_max_window_bits=%d%s",
+        server_window_bits, client_window_bits,
+        server_no_context_takeover ? "; server_no_context_takeover" : "");
+    return new WebSocketEncoder(true /* is_server */, server_window_bits,
+                                client_window_bits, server_no_context_takeover);
+  } else {
+    *response_extensions = std::string();
+    return new WebSocketEncoder(true /* is_server */);
+  }
+}
+
+// static
+WebSocketEncoder* WebSocketEncoder::CreateClient(
+    const std::string& response_extensions) {
+  bool deflate;
+  int client_window_bits;
+  int server_window_bits;
+  bool client_no_context_takeover;
+  bool server_no_context_takeover;
+  ParseExtensions(response_extensions, &deflate, &client_window_bits,
+                  &server_window_bits, &client_no_context_takeover,
+                  &server_no_context_takeover);
+
+  if (deflate) {
+    return new WebSocketEncoder(false /* is_server */, client_window_bits,
+                                server_window_bits, client_no_context_takeover);
+  } else {
+    return new WebSocketEncoder(false /* is_server */);
+  }
+}
+
+// static
+void WebSocketEncoder::ParseExtensions(const std::string& extensions,
+                                       bool* deflate,
+                                       int* client_window_bits,
+                                       int* server_window_bits,
+                                       bool* client_no_context_takeover,
+                                       bool* server_no_context_takeover) {
+  *deflate = false;
+  *client_window_bits = 15;
+  *server_window_bits = 15;
+  *client_no_context_takeover = false;
+  *server_no_context_takeover = false;
+
+  if (extensions.empty())
+    return;
+
+  // TODO(dgozman): split extensions header if another extension is introduced.
+  WebSocketExtensionParser parser;
+  parser.Parse(extensions);
+  if (parser.has_error())
+    return;
+  if (parser.extension().name() != "permessage-deflate")
+    return;
+
+  const std::vector<WebSocketExtension::Parameter>& parameters =
+      parser.extension().parameters();
+  for (const auto& param : parameters) {
+    const std::string& name = param.name();
+    if (name == "client_max_window_bits" && param.HasValue()) {
+      int bits = 0;
+      if (base::StringToInt(param.value(), &bits) && bits >= 8 && bits <= 15)
+        *client_window_bits = bits;
+    }
+    if (name == "server_max_window_bits" && param.HasValue()) {
+      int bits = 0;
+      if (base::StringToInt(param.value(), &bits) && bits >= 8 && bits <= 15)
+        *server_window_bits = bits;
+    }
+    if (name == "client_no_context_takeover")
+      *client_no_context_takeover = true;
+    if (name == "server_no_context_takeover")
+      *server_no_context_takeover = true;
+  }
+  *deflate = true;
+}
+
+WebSocketEncoder::WebSocketEncoder(bool is_server) : is_server_(is_server) {
+}
+
+WebSocketEncoder::WebSocketEncoder(bool is_server,
+                                   int deflate_bits,
+                                   int inflate_bits,
+                                   bool no_context_takeover)
+    : is_server_(is_server) {
+  deflater_.reset(new WebSocketDeflater(
+      no_context_takeover ? WebSocketDeflater::DO_NOT_TAKE_OVER_CONTEXT
+                          : WebSocketDeflater::TAKE_OVER_CONTEXT));
+  inflater_.reset(
+      new WebSocketInflater(kInflaterChunkSize, kInflaterChunkSize));
+
+  if (!deflater_->Initialize(deflate_bits) ||
+      !inflater_->Initialize(inflate_bits)) {
+    // Disable deflate support.
+    deflater_.reset();
+    inflater_.reset();
+  }
+}
+
+WebSocketEncoder::~WebSocketEncoder() {
+}
+
+WebSocket::ParseResult WebSocketEncoder::DecodeFrame(
+    const base::StringPiece& frame,
+    int* bytes_consumed,
+    std::string* output) {
+  bool compressed;
+  WebSocket::ParseResult result =
+      DecodeFrameHybi17(frame, is_server_, bytes_consumed, output, &compressed);
+  if (result == WebSocket::FRAME_OK && compressed) {
+    if (!Inflate(output))
+      result = WebSocket::FRAME_ERROR;
+  }
+  return result;
+}
+
+void WebSocketEncoder::EncodeFrame(const std::string& frame,
+                                   int masking_key,
+                                   std::string* output) {
+  std::string compressed;
+  if (Deflate(frame, &compressed))
+    EncodeFrameHybi17(compressed, masking_key, true, output);
+  else
+    EncodeFrameHybi17(frame, masking_key, false, output);
+}
+
+bool WebSocketEncoder::Inflate(std::string* message) {
+  if (!inflater_)
+    return false;
+  if (!inflater_->AddBytes(message->data(), message->length()))
+    return false;
+  if (!inflater_->Finish())
+    return false;
+
+  std::vector<char> output;
+  while (inflater_->CurrentOutputSize() > 0) {
+    scoped_refptr<IOBufferWithSize> chunk =
+        inflater_->GetOutput(inflater_->CurrentOutputSize());
+    if (!chunk.get())
+      return false;
+    output.insert(output.end(), chunk->data(), chunk->data() + chunk->size());
+  }
+
+  *message =
+      output.size() ? std::string(&output[0], output.size()) : std::string();
+  return true;
+}
+
+bool WebSocketEncoder::Deflate(const std::string& message,
+                               std::string* output) {
+  if (!deflater_)
+    return false;
+  if (!deflater_->AddBytes(message.data(), message.length())) {
+    deflater_->Finish();
+    return false;
+  }
+  if (!deflater_->Finish())
+    return false;
+  scoped_refptr<IOBufferWithSize> buffer =
+      deflater_->GetOutput(deflater_->CurrentOutputSize());
+  if (!buffer.get())
+    return false;
+  *output = std::string(buffer->data(), buffer->size());
+  return true;
+}
+
+}  // namespace net
diff --git a/net/server/web_socket_encoder.h b/net/server/web_socket_encoder.h
new file mode 100644
index 0000000..c534c2f
--- /dev/null
+++ b/net/server/web_socket_encoder.h
@@ -0,0 +1,63 @@
+// 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 NET_SERVER_WEB_SOCKET_ENCODER_H_
+#define NET_SERVER_WEB_SOCKET_ENCODER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "net/server/web_socket.h"
+#include "net/websockets/websocket_deflater.h"
+#include "net/websockets/websocket_inflater.h"
+
+namespace net {
+
+class WebSocketEncoder {
+ public:
+  ~WebSocketEncoder();
+
+  static WebSocketEncoder* CreateServer(const std::string& request_extensions,
+                                        std::string* response_extensions);
+
+  static const char kClientExtensions[];
+  static WebSocketEncoder* CreateClient(const std::string& response_extensions);
+
+  WebSocket::ParseResult DecodeFrame(const base::StringPiece& frame,
+                                     int* bytes_consumed,
+                                     std::string* output);
+
+  void EncodeFrame(const std::string& frame,
+                   int masking_key,
+                   std::string* output);
+
+ private:
+  explicit WebSocketEncoder(bool is_server);
+  WebSocketEncoder(bool is_server,
+                   int deflate_bits,
+                   int inflate_bits,
+                   bool no_context_takeover);
+
+  static void ParseExtensions(const std::string& extensions,
+                              bool* deflate,
+                              int* client_window_bits,
+                              int* server_window_bits,
+                              bool* client_no_context_takeover,
+                              bool* server_no_context_takeover);
+
+  bool Inflate(std::string* message);
+  bool Deflate(const std::string& message, std::string* output);
+
+  scoped_ptr<WebSocketDeflater> deflater_;
+  scoped_ptr<WebSocketInflater> inflater_;
+  bool is_server_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebSocketEncoder);
+};
+
+}  // namespace net
+
+#endif  // NET_SERVER_WEB_SOCKET_ENCODER_H_
diff --git a/net/server/web_socket_encoder_unittest.cc b/net/server/web_socket_encoder_unittest.cc
new file mode 100644
index 0000000..b52939a
--- /dev/null
+++ b/net/server/web_socket_encoder_unittest.cc
@@ -0,0 +1,155 @@
+// 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 "net/server/web_socket_encoder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+class WebSocketEncoderTest : public testing::Test {
+ public:
+  WebSocketEncoderTest() {}
+
+  void SetUp() override {
+    std::string response_extensions;
+    server_.reset(WebSocketEncoder::CreateServer("", &response_extensions));
+    EXPECT_EQ(std::string(), response_extensions);
+    client_.reset(WebSocketEncoder::CreateClient(""));
+  }
+
+ protected:
+  scoped_ptr<WebSocketEncoder> server_;
+  scoped_ptr<WebSocketEncoder> client_;
+};
+
+class WebSocketEncoderCompressionTest : public WebSocketEncoderTest {
+ public:
+  WebSocketEncoderCompressionTest() : WebSocketEncoderTest() {}
+
+  void SetUp() override {
+    std::string response_extensions;
+    server_.reset(WebSocketEncoder::CreateServer(
+        "permessage-deflate; client_max_window_bits", &response_extensions));
+    EXPECT_EQ(
+        "permessage-deflate; server_max_window_bits=15; "
+        "client_max_window_bits=15",
+        response_extensions);
+    client_.reset(WebSocketEncoder::CreateClient(response_extensions));
+  }
+};
+
+TEST_F(WebSocketEncoderTest, ClientToServer) {
+  std::string frame("ClientToServer");
+  int mask = 123456;
+  std::string encoded;
+  int bytes_consumed;
+  std::string decoded;
+
+  client_->EncodeFrame(frame, mask, &encoded);
+  EXPECT_EQ(WebSocket::FRAME_OK,
+            server_->DecodeFrame(encoded, &bytes_consumed, &decoded));
+  EXPECT_EQ(frame, decoded);
+  EXPECT_EQ((int)encoded.length(), bytes_consumed);
+
+  std::string partial = encoded.substr(0, encoded.length() - 2);
+  EXPECT_EQ(WebSocket::FRAME_INCOMPLETE,
+            server_->DecodeFrame(partial, &bytes_consumed, &decoded));
+
+  std::string extra = encoded + "more stuff";
+  EXPECT_EQ(WebSocket::FRAME_OK,
+            server_->DecodeFrame(extra, &bytes_consumed, &decoded));
+  EXPECT_EQ(frame, decoded);
+  EXPECT_EQ((int)encoded.length(), bytes_consumed);
+
+  EXPECT_EQ(
+      WebSocket::FRAME_ERROR,
+      server_->DecodeFrame(std::string("abcde"), &bytes_consumed, &decoded));
+}
+
+TEST_F(WebSocketEncoderTest, ServerToClient) {
+  std::string frame("ServerToClient");
+  int mask = 0;
+  std::string encoded;
+  int bytes_consumed;
+  std::string decoded;
+
+  server_->EncodeFrame(frame, mask, &encoded);
+  EXPECT_EQ(WebSocket::FRAME_OK,
+            client_->DecodeFrame(encoded, &bytes_consumed, &decoded));
+  EXPECT_EQ(frame, decoded);
+  EXPECT_EQ((int)encoded.length(), bytes_consumed);
+
+  std::string partial = encoded.substr(0, encoded.length() - 2);
+  EXPECT_EQ(WebSocket::FRAME_INCOMPLETE,
+            client_->DecodeFrame(partial, &bytes_consumed, &decoded));
+
+  std::string extra = encoded + "more stuff";
+  EXPECT_EQ(WebSocket::FRAME_OK,
+            client_->DecodeFrame(extra, &bytes_consumed, &decoded));
+  EXPECT_EQ(frame, decoded);
+  EXPECT_EQ((int)encoded.length(), bytes_consumed);
+
+  EXPECT_EQ(
+      WebSocket::FRAME_ERROR,
+      client_->DecodeFrame(std::string("abcde"), &bytes_consumed, &decoded));
+}
+
+TEST_F(WebSocketEncoderCompressionTest, ClientToServer) {
+  std::string frame("CompressionCompressionCompressionCompression");
+  int mask = 654321;
+  std::string encoded;
+  int bytes_consumed;
+  std::string decoded;
+
+  client_->EncodeFrame(frame, mask, &encoded);
+  EXPECT_LT(encoded.length(), frame.length());
+  EXPECT_EQ(WebSocket::FRAME_OK,
+            server_->DecodeFrame(encoded, &bytes_consumed, &decoded));
+  EXPECT_EQ(frame, decoded);
+  EXPECT_EQ((int)encoded.length(), bytes_consumed);
+}
+
+TEST_F(WebSocketEncoderCompressionTest, ServerToClient) {
+  std::string frame("CompressionCompressionCompressionCompression");
+  int mask = 0;
+  std::string encoded;
+  int bytes_consumed;
+  std::string decoded;
+
+  server_->EncodeFrame(frame, mask, &encoded);
+  EXPECT_LT(encoded.length(), frame.length());
+  EXPECT_EQ(WebSocket::FRAME_OK,
+            client_->DecodeFrame(encoded, &bytes_consumed, &decoded));
+  EXPECT_EQ(frame, decoded);
+  EXPECT_EQ((int)encoded.length(), bytes_consumed);
+}
+
+TEST_F(WebSocketEncoderCompressionTest, LongFrame) {
+  int length = 1000000;
+  std::string temp;
+  temp.reserve(length);
+  for (int i = 0; i < length; ++i)
+    temp += (char)('a' + (i % 26));
+
+  std::string frame;
+  frame.reserve(length);
+  for (int i = 0; i < length; ++i) {
+    int64 j = i;
+    frame += temp.data()[(j * j) % length];
+  }
+
+  int mask = 0;
+  std::string encoded;
+  int bytes_consumed;
+  std::string decoded;
+
+  server_->EncodeFrame(frame, mask, &encoded);
+  EXPECT_LT(encoded.length(), frame.length());
+  EXPECT_EQ(WebSocket::FRAME_OK,
+            client_->DecodeFrame(encoded, &bytes_consumed, &decoded));
+  EXPECT_EQ(frame, decoded);
+  EXPECT_EQ((int)encoded.length(), bytes_consumed);
+}
+
+}  // namespace net
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 9e1abf4..4092365 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/stats_counters.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
@@ -865,6 +866,11 @@
 
 void ClientSocketPoolBaseHelper::OnConnectJobComplete(
     int result, ConnectJob* job) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "436634 ClientSocketPoolBaseHelper::OnConnectJobComplete"));
+
   DCHECK_NE(ERR_IO_PENDING, result);
   const std::string group_name = job->group_name();
   GroupMap::iterator group_it = group_map_.find(group_name);
diff --git a/net/socket/next_proto.cc b/net/socket/next_proto.cc
index 0e59ce7..0d1b400 100644
--- a/net/socket/next_proto.cc
+++ b/net/socket/next_proto.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "next_proto.h"
+#include "net/socket/next_proto.h"
 
 namespace net {
 
@@ -16,6 +16,8 @@
   NextProtoVector next_protos;
   next_protos.push_back(kProtoHTTP11);
   next_protos.push_back(kProtoSPDY31);
+  next_protos.push_back(kProtoSPDY4_14);
+  next_protos.push_back(kProtoSPDY4_15);
   return next_protos;
 }
 
@@ -27,6 +29,8 @@
     next_protos.push_back(kProtoQUIC1SPDY3);
   if (spdy_enabled) {
     next_protos.push_back(kProtoSPDY31);
+    next_protos.push_back(kProtoSPDY4_14);
+    next_protos.push_back(kProtoSPDY4_15);
   }
   return next_protos;
 }
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc
index a52e6a3..2ea403f 100644
--- a/net/socket/ssl_client_socket.cc
+++ b/net/socket/ssl_client_socket.cc
@@ -11,6 +11,7 @@
 #include "net/base/connection_type_histograms.h"
 #include "net/base/host_port_pair.h"
 #include "net/ssl/channel_id_service.h"
+#include "net/ssl/ssl_cipher_suite_names.h"
 #include "net/ssl/ssl_config_service.h"
 #include "net/ssl/ssl_connection_status_flags.h"
 
@@ -234,38 +235,46 @@
 }
 
 // static
+bool SSLClientSocket::HasCipherAdequateForHTTP2(
+    const std::vector<uint16>& cipher_suites) {
+  for (uint16 cipher : cipher_suites) {
+    if (IsSecureTLSCipherSuite(cipher))
+      return true;
+  }
+  return false;
+}
+
+// static
+bool SSLClientSocket::IsTLSVersionAdequateForHTTP2(
+    const SSLConfig& ssl_config) {
+  return ssl_config.version_max >= SSL_PROTOCOL_VERSION_TLS1_2;
+}
+
+// static
 std::vector<uint8_t> SSLClientSocket::SerializeNextProtos(
-    const std::vector<std::string>& next_protos) {
-  // Do a first pass to determine the total length.
-  size_t wire_length = 0;
-  for (std::vector<std::string>::const_iterator i = next_protos.begin();
-       i != next_protos.end(); ++i) {
-    if (i->size() > 255) {
-      LOG(WARNING) << "Ignoring overlong NPN/ALPN protocol: " << *i;
+    const NextProtoVector& next_protos,
+    bool can_advertise_http2) {
+  std::vector<uint8_t> wire_protos;
+  for (const NextProto next_proto : next_protos) {
+    if (!can_advertise_http2 && kProtoSPDY4MinimumVersion <= next_proto &&
+        next_proto <= kProtoSPDY4MaximumVersion) {
       continue;
     }
-    if (i->size() == 0) {
+    const std::string proto = NextProtoToString(next_proto);
+    if (proto.size() > 255) {
+      LOG(WARNING) << "Ignoring overlong NPN/ALPN protocol: " << proto;
+      continue;
+    }
+    if (proto.size() == 0) {
       LOG(WARNING) << "Ignoring empty NPN/ALPN protocol";
       continue;
     }
-    wire_length += i->size();
-    wire_length++;
+    wire_protos.push_back(proto.size());
+    for (const char ch : proto) {
+      wire_protos.push_back(static_cast<uint8_t>(ch));
+    }
   }
 
-  // Allocate memory for the result and fill it in.
-  std::vector<uint8_t> wire_protos;
-  wire_protos.reserve(wire_length);
-  for (std::vector<std::string>::const_iterator i = next_protos.begin();
-       i != next_protos.end(); i++) {
-    if (i->size() == 0 || i->size() > 255)
-      continue;
-    wire_protos.push_back(i->size());
-    wire_protos.resize(wire_protos.size() + i->size());
-    memcpy(&wire_protos[wire_protos.size() - i->size()],
-           i->data(), i->size());
-  }
-  DCHECK_EQ(wire_protos.size(), wire_length);
-
   return wire_protos;
 }
 
diff --git a/net/socket/ssl_client_socket.h b/net/socket/ssl_client_socket.h
index 11b19a1..46461df 100644
--- a/net/socket/ssl_client_socket.h
+++ b/net/socket/ssl_client_socket.h
@@ -209,10 +209,23 @@
       const SSLConfig& ssl_config,
       ChannelIDService* channel_id_service);
 
+  // Determine if there is at least one enabled cipher suite that satisfies
+  // Section 9.2 of the HTTP/2 specification.  Note that the server might still
+  // pick an inadequate cipher suite.
+  static bool HasCipherAdequateForHTTP2(
+      const std::vector<uint16>& cipher_suites);
+
+  // Determine if the TLS version required by Section 9.2 of the HTTP/2
+  // specification is enabled.  Note that the server might still pick an
+  // inadequate TLS version.
+  static bool IsTLSVersionAdequateForHTTP2(const SSLConfig& ssl_config);
+
   // Serializes |next_protos| in the wire format for ALPN: protocols are listed
-  // in order, each prefixed by a one-byte length.
+  // in order, each prefixed by a one-byte length.  Any HTTP/2 protocols in
+  // |next_protos| are ignored if |can_advertise_http2| is false.
   static std::vector<uint8_t> SerializeNextProtos(
-      const std::vector<std::string>& next_protos);
+      const NextProtoVector& next_protos,
+      bool can_advertise_http2);
 
   // For unit testing only.
   // Returns the unverified certificate chain as presented by server.
@@ -222,6 +235,7 @@
       const = 0;
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(SSLClientSocket, SerializeNextProtos);
   // For signed_cert_timestamps_received_ and stapled_ocsp_response_received_.
   FRIEND_TEST_ALL_PREFIXES(SSLClientSocketTest,
                            ConnectSignedCertTimestampsEnabledTLSExtension);
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 3651e8d..5e33e12 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -149,6 +149,14 @@
     } while (0)
 #endif
 
+#if !defined(CKM_AES_GCM)
+#define CKM_AES_GCM 0x00001087
+#endif
+
+#if !defined(CKM_NSS_CHACHA20_POLY1305)
+#define CKM_NSS_CHACHA20_POLY1305 (CKM_NSS + 26)
+#endif
+
 namespace {
 
 // SSL plaintext fragments are shorter than 16KB. Although the record layer
@@ -973,8 +981,16 @@
   SECStatus rv = SECSuccess;
 
   if (!ssl_config_.next_protos.empty()) {
+    // TODO(bnc): Check ssl_config_.disabled_cipher_suites.
+    const bool adequate_encryption =
+        PK11_TokenExists(CKM_AES_GCM) ||
+        PK11_TokenExists(CKM_NSS_CHACHA20_POLY1305);
+    const bool adequate_key_agreement = PK11_TokenExists(CKM_DH_PKCS_DERIVE) ||
+                                        PK11_TokenExists(CKM_ECDH1_DERIVE);
     std::vector<uint8_t> wire_protos =
-        SerializeNextProtos(ssl_config_.next_protos);
+        SerializeNextProtos(ssl_config_.next_protos,
+                            adequate_encryption && adequate_key_agreement &&
+                                IsTLSVersionAdequateForHTTP2(ssl_config_));
     rv = SSL_SetNextProtoNego(
         nss_fd_, wire_protos.empty() ? NULL : &wire_protos[0],
         wire_protos.size());
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 4e86c05..c78a974 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -788,8 +788,8 @@
   // disabled by default. Note that !SHA256 and !SHA384 only remove HMAC-SHA256
   // and HMAC-SHA384 cipher suites, not GCM cipher suites with SHA256 or SHA384
   // as the handshake hash.
-  std::string command("DEFAULT:!NULL:!aNULL:!IDEA:!FZA:!SRP:!SHA256:!SHA384:"
-                      "!aECDH:!AESGCM+AES256");
+  std::string command(
+      "DEFAULT:!NULL:!aNULL:!SHA256:!SHA384:!aECDH:!AESGCM+AES256:!aPSK");
   // Walk through all the installed ciphers, seeing if any need to be
   // appended to the cipher removal |command|.
   for (size_t i = 0; i < sk_SSL_CIPHER_num(ciphers); ++i) {
@@ -838,8 +838,20 @@
   }
 
   if (!ssl_config_.next_protos.empty()) {
+    // Get list of ciphers that are enabled.
+    STACK_OF(SSL_CIPHER)* enabled_ciphers = SSL_get_ciphers(ssl_);
+    DCHECK(enabled_ciphers);
+    std::vector<uint16> enabled_ciphers_vector;
+    for (size_t i = 0; i < sk_SSL_CIPHER_num(enabled_ciphers); ++i) {
+      const SSL_CIPHER* cipher = sk_SSL_CIPHER_value(enabled_ciphers, i);
+      const uint16 id = static_cast<uint16>(SSL_CIPHER_get_id(cipher));
+      enabled_ciphers_vector.push_back(id);
+    }
+
     std::vector<uint8_t> wire_protos =
-        SerializeNextProtos(ssl_config_.next_protos);
+        SerializeNextProtos(ssl_config_.next_protos,
+                            HasCipherAdequateForHTTP2(enabled_ciphers_vector) &&
+                                IsTLSVersionAdequateForHTTP2(ssl_config_));
     SSL_set_alpn_protos(ssl_, wire_protos.empty() ? NULL : &wire_protos[0],
                         wire_protos.size());
   }
@@ -1131,9 +1143,18 @@
     }
   }
 
-  if (result == OK)
+  if (result == OK) {
     RecordConnectionTypeMetrics(GetNetSSLVersion(ssl_));
 
+    if (SSL_session_reused(ssl_)) {
+      // Record whether or not the server tried to resume a session for a
+      // different version. See https://crbug.com/441456.
+      UMA_HISTOGRAM_BOOLEAN(
+          "Net.SSLSessionVersionMatch",
+          SSL_version(ssl_) == SSL_get_session(ssl_)->ssl_version);
+    }
+  }
+
   const CertStatus cert_status = server_cert_verify_result_.cert_status;
   if (transport_security_state_ &&
       (result == OK ||
@@ -1782,11 +1803,10 @@
 
   // For each protocol in server preference order, see if we support it.
   for (unsigned int i = 0; i < inlen; i += in[i] + 1) {
-    for (std::vector<std::string>::const_iterator
-             j = ssl_config_.next_protos.begin();
-         j != ssl_config_.next_protos.end(); ++j) {
-      if (in[i] == j->size() &&
-          memcmp(&in[i + 1], j->data(), in[i]) == 0) {
+    for (NextProto next_proto : ssl_config_.next_protos) {
+      const std::string proto = NextProtoToString(next_proto);
+      if (in[i] == proto.size() &&
+          memcmp(&in[i + 1], proto.data(), in[i]) == 0) {
         // We found a match.
         *out = const_cast<unsigned char*>(in) + i + 1;
         *outlen = in[i];
@@ -1800,9 +1820,9 @@
 
   // If we didn't find a protocol, we select the first one from our list.
   if (npn_status_ == kNextProtoNoOverlap) {
-    *out = reinterpret_cast<uint8*>(const_cast<char*>(
-        ssl_config_.next_protos[0].data()));
-    *outlen = ssl_config_.next_protos[0].size();
+    const std::string proto = NextProtoToString(ssl_config_.next_protos[0]);
+    *out = reinterpret_cast<uint8*>(const_cast<char*>(proto.data()));
+    *outlen = proto.size();
   }
 
   npn_proto_.assign(reinterpret_cast<const char*>(*out), *outlen);
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 16e03f7..d14f1fd 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -2351,6 +2351,33 @@
   SSLClientSocket::ClearSessionCache();
 }
 
+TEST(SSLClientSocket, SerializeNextProtos) {
+  NextProtoVector next_protos;
+  next_protos.push_back(kProtoHTTP11);
+  next_protos.push_back(kProtoSPDY31);
+  static std::vector<uint8_t> serialized =
+      SSLClientSocket::SerializeNextProtos(next_protos, true);
+  ASSERT_EQ(18u, serialized.size());
+  EXPECT_EQ(8, serialized[0]);  // length("http/1.1")
+  EXPECT_EQ('h', serialized[1]);
+  EXPECT_EQ('t', serialized[2]);
+  EXPECT_EQ('t', serialized[3]);
+  EXPECT_EQ('p', serialized[4]);
+  EXPECT_EQ('/', serialized[5]);
+  EXPECT_EQ('1', serialized[6]);
+  EXPECT_EQ('.', serialized[7]);
+  EXPECT_EQ('1', serialized[8]);
+  EXPECT_EQ(8, serialized[9]);  // length("spdy/3.1")
+  EXPECT_EQ('s', serialized[10]);
+  EXPECT_EQ('p', serialized[11]);
+  EXPECT_EQ('d', serialized[12]);
+  EXPECT_EQ('y', serialized[13]);
+  EXPECT_EQ('/', serialized[14]);
+  EXPECT_EQ('3', serialized[15]);
+  EXPECT_EQ('.', serialized[16]);
+  EXPECT_EQ('1', serialized[17]);
+}
+
 // Test that the server certificates are properly retrieved from the underlying
 // SSL stack.
 TEST_F(SSLClientSocketTest, VerifyServerChainProperlyOrdered) {
@@ -2889,7 +2916,7 @@
       SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
   server_options.enable_npn = true;
   SSLConfig client_config;
-  client_config.next_protos.push_back("http/1.1");
+  client_config.next_protos.push_back(kProtoHTTP11);
   monitor_handshake_callback_ = true;
   fail_handshake_after_false_start_ = true;
   ASSERT_NO_FATAL_FAILURE(TestFalseStart(server_options, client_config, true));
@@ -2904,7 +2931,7 @@
       SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
   server_options.enable_npn = true;
   SSLConfig client_config;
-  client_config.next_protos.push_back("http/1.1");
+  client_config.next_protos.push_back(kProtoHTTP11);
   monitor_handshake_callback_ = true;
   ASSERT_NO_FATAL_FAILURE(TestFalseStart(server_options, client_config, true));
   ASSERT_TRUE(ran_handshake_completion_callback_);
@@ -2918,7 +2945,7 @@
       SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
   server_options.enable_npn = true;
   SSLConfig client_config;
-  client_config.next_protos.push_back("http/1.1");
+  client_config.next_protos.push_back(kProtoHTTP11);
   ASSERT_NO_FATAL_FAILURE(
       TestFalseStart(server_options, client_config, true));
 }
@@ -2941,7 +2968,7 @@
       SpawnedTestServer::SSLOptions::KEY_EXCHANGE_RSA;
   server_options.enable_npn = true;
   SSLConfig client_config;
-  client_config.next_protos.push_back("http/1.1");
+  client_config.next_protos.push_back(kProtoHTTP11);
   ASSERT_NO_FATAL_FAILURE(
       TestFalseStart(server_options, client_config, false));
 }
@@ -2954,7 +2981,7 @@
       SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
   server_options.enable_npn = true;
   SSLConfig client_config;
-  client_config.next_protos.push_back("http/1.1");
+  client_config.next_protos.push_back(kProtoHTTP11);
 
   // Let a full handshake complete with False Start.
   ASSERT_NO_FATAL_FAILURE(
@@ -2987,7 +3014,7 @@
   ASSERT_TRUE(StartTestServer(server_options));
 
   SSLConfig client_config;
-  client_config.next_protos.push_back("http/1.1");
+  client_config.next_protos.push_back(kProtoHTTP11);
 
   // Start a handshake up to the server Finished message.
   TestCompletionCallback callback;
diff --git a/net/socket/transport_client_socket_pool.h b/net/socket/transport_client_socket_pool.h
index bcc369f..2deb947 100644
--- a/net/socket/transport_client_socket_pool.h
+++ b/net/socket/transport_client_socket_pool.h
@@ -326,6 +326,12 @@
           "436634 TransportConnectJobHelper::OnIOComplete"));
 
   result = this->DoLoop(job, result);
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "436634 TransportConnectJobHelper::OnIOComplete1"));
+
   if (result != ERR_IO_PENDING)
     job->NotifyDelegateOfCompletion(result);  // Deletes |job| and |this|
 }
diff --git a/net/socket/websocket_transport_client_socket_pool.cc b/net/socket/websocket_transport_client_socket_pool.cc
index 15ec028..ec83529 100644
--- a/net/socket/websocket_transport_client_socket_pool.cc
+++ b/net/socket/websocket_transport_client_socket_pool.cc
@@ -9,6 +9,7 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "base/values.h"
@@ -630,6 +631,11 @@
 WebSocketTransportClientSocketPool::ConnectJobDelegate::OnConnectJobComplete(
     int result,
     ConnectJob* job) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/436634 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "436634 WebSocket...::ConnectJobDelegate::OnConnectJobComplete"));
+
   owner_->OnConnectJobComplete(result,
                                static_cast<WebSocketTransportConnectJob*>(job));
 }
diff --git a/net/ssl/client_cert_store.h b/net/ssl/client_cert_store.h
index fe050e5..b1172de 100644
--- a/net/ssl/client_cert_store.h
+++ b/net/ssl/client_cert_store.h
@@ -14,8 +14,10 @@
 
 class SSLCertRequestInfo;
 
-// The caller is expected to keep the ClientCertStore alive until the callback
-// supplied to GetClientCerts has been run.
+// A handle to a client certificate store to query matching certificates when a
+// server requests client auth. Note that there may be multiple ClientCertStore
+// objects corresponding to the same platform certificate store; each request
+// gets its own uniquely owned handle.
 class NET_EXPORT ClientCertStore {
  public:
   virtual ~ClientCertStore() {}
@@ -23,8 +25,8 @@
   // Get client certs matching the |cert_request_info|. On completion, the
   // results will be stored in |selected_certs| and the |callback| will be run.
   // The |callback| may be called sychronously. The caller must ensure the
-  // ClientCertStore and the |selected_certs| object remain alive until the
-  // callback has been run.
+  // ClientCertStore, |cert_request_info|, and |selected_certs| remain alive
+  // until the callback has been run.
   virtual void GetClientCerts(const SSLCertRequestInfo& cert_request_info,
                               CertificateList* selected_certs,
                               const base::Closure& callback) = 0;
diff --git a/net/ssl/ssl_config.h b/net/ssl/ssl_config.h
index 5a0c0fa..2cbc995 100644
--- a/net/ssl/ssl_config.h
+++ b/net/ssl/ssl_config.h
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "net/base/net_export.h"
 #include "net/cert/x509_certificate.h"
+#include "net/socket/next_proto.h"
 
 namespace net {
 
@@ -155,7 +156,7 @@
   // Protocol Negotiation, but there is no overlap between the server's and
   // client's protocol sets, then the first protocol in this list will be
   // requested by the client.
-  std::vector<std::string> next_protos;
+  NextProtoVector next_protos;
 
   scoped_refptr<X509Certificate> client_cert;
 };
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc
index 97b5d84..ac7d3bc 100644
--- a/net/test/embedded_test_server/embedded_test_server.cc
+++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -49,8 +49,15 @@
   // This is a test-only server. Ignore I/O thread restrictions.
   base::ThreadRestrictions::ScopedAllowIO allow_io;
 
+  std::string relative_url(request.relative_url);
+  // A proxy request will have an absolute path. Simulate the proxy by stripping
+  // the scheme, host, and port.
+  GURL relative_gurl(relative_url);
+  if (relative_gurl.is_valid())
+    relative_url = relative_gurl.PathForRequest();
+
   // Trim the first byte ('/').
-  std::string request_path(request.relative_url.substr(1));
+  std::string request_path = relative_url.substr(1);
 
   // Remove the query string if present.
   size_t query_pos = request_path.find('?');
diff --git a/net/test/spawned_test_server/local_test_server.cc b/net/test/spawned_test_server/local_test_server.cc
index c85e05a..309c69c 100644
--- a/net/test/spawned_test_server/local_test_server.cc
+++ b/net/test/spawned_test_server/local_test_server.cc
@@ -121,18 +121,17 @@
 bool LocalTestServer::Stop() {
   CleanUpWhenStoppingServer();
 
-  if (!process_handle_)
+  if (!process_.IsValid())
     return true;
 
   // First check if the process has already terminated.
-  bool ret = base::WaitForSingleProcess(process_handle_, base::TimeDelta());
+  bool ret = base::WaitForSingleProcess(process_.Handle(), base::TimeDelta());
   if (!ret) {
-    ret = base::KillProcess(process_handle_, 1, true);
+    ret = base::KillProcess(process_.Handle(), 1, true);
   }
 
   if (ret) {
-    base::CloseProcessHandle(process_handle_);
-    process_handle_ = base::kNullProcessHandle;
+    process_.Close();
   } else {
     VLOG(1) << "Kill failed?";
   }
@@ -149,7 +148,6 @@
   // number out over a pipe that this TestServer object will read from. Once
   // that is complete, the host port pair will contain the actual port.
   DCHECK(!GetPort());
-  process_handle_ = base::kNullProcessHandle;
 
   base::FilePath src_dir;
   if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir))
diff --git a/net/test/spawned_test_server/local_test_server.h b/net/test/spawned_test_server/local_test_server.h
index 37b1185..785d726 100644
--- a/net/test/spawned_test_server/local_test_server.h
+++ b/net/test/spawned_test_server/local_test_server.h
@@ -9,7 +9,7 @@
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
-#include "base/process/process_handle.h"
+#include "base/process/process.h"
 #include "net/test/spawned_test_server/base_test_server.h"
 
 #if defined(OS_WIN)
@@ -92,8 +92,8 @@
   // Waits for the server to start. Returns true on success.
   bool WaitToStart() WARN_UNUSED_RESULT;
 
-  // Handle of the Python process running the test server.
-  base::ProcessHandle process_handle_;
+  // The Python process running the test server.
+  base::Process process_;
 
 #if defined(OS_WIN)
   // The pipe file handle we read from.
diff --git a/net/test/spawned_test_server/local_test_server_posix.cc b/net/test/spawned_test_server/local_test_server_posix.cc
index 0edbedf..c770152 100644
--- a/net/test/spawned_test_server/local_test_server_posix.cc
+++ b/net/test/spawned_test_server/local_test_server_posix.cc
@@ -139,7 +139,8 @@
   base::LaunchOptions options;
 
   options.fds_to_remap = &map_write_fd;
-  if (!base::LaunchProcess(python_command, options, &process_handle_)) {
+  process_ = base::LaunchProcess(python_command, options);
+  if (!process_.IsValid()) {
     LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString();
     return false;
   }
diff --git a/net/test/spawned_test_server/local_test_server_win.cc b/net/test/spawned_test_server/local_test_server_win.cc
index 412e4e1..5eb5aaf 100644
--- a/net/test/spawned_test_server/local_test_server_win.cc
+++ b/net/test/spawned_test_server/local_test_server_win.cc
@@ -176,7 +176,8 @@
 
   base::LaunchOptions launch_options;
   launch_options.inherit_handles = true;
-  if (!base::LaunchProcess(python_command, launch_options, &process_handle_)) {
+  process_ = base::LaunchProcess(python_command, launch_options);
+  if (!process_.IsValid()) {
     LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString();
     return false;
   }
diff --git a/net/test/url_request/url_request_mock_data_job.cc b/net/test/url_request/url_request_mock_data_job.cc
new file mode 100644
index 0000000..54c174c
--- /dev/null
+++ b/net/test/url_request/url_request_mock_data_job.cc
@@ -0,0 +1,165 @@
+// 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 "net/test/url_request/url_request_mock_data_job.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/base/io_buffer.h"
+#include "net/base/url_util.h"
+#include "net/http/http_request_headers.h"
+#include "net/url_request/url_request_filter.h"
+
+namespace net {
+namespace {
+
+const char kMockHostname[] = "mock.data";
+
+// Gets the data from URL of the form:
+// scheme://kMockHostname/?data=abc&repeat_count=nnn.
+std::string GetDataFromRequest(const net::URLRequest& request) {
+  std::string value;
+  if (!GetValueForKeyInQuery(request.url(), "data", &value))
+    return "default_data";
+  return value;
+}
+
+// Gets the numeric repeat count from URL of the form:
+// scheme://kMockHostname/?data=abc&repeat_count=nnn.
+int GetRepeatCountFromRequest(const net::URLRequest& request) {
+  std::string value;
+  if (!GetValueForKeyInQuery(request.url(), "repeat", &value))
+    return 1;
+
+  int repeat_count;
+  if (!base::StringToInt(value, &repeat_count))
+    return 1;
+
+  DCHECK_GT(repeat_count, 0);
+
+  return repeat_count;
+}
+
+GURL GetMockUrl(const std::string& scheme,
+                const std::string& hostname,
+                const std::string& data,
+                int data_repeat_count) {
+  DCHECK_GT(data_repeat_count, 0);
+  std::string url(scheme + "://" + hostname + "/");
+  url.append("?data=");
+  url.append(data);
+  url.append("&repeat=");
+  url.append(base::IntToString(data_repeat_count));
+  return GURL(url);
+}
+
+class MockJobInterceptor : public net::URLRequestInterceptor {
+ public:
+  MockJobInterceptor() {}
+  ~MockJobInterceptor() override {}
+
+  // net::URLRequestInterceptor implementation
+  net::URLRequestJob* MaybeInterceptRequest(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const override {
+    return new URLRequestMockDataJob(request, network_delegate,
+                                     GetDataFromRequest(*request),
+                                     GetRepeatCountFromRequest(*request));
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockJobInterceptor);
+};
+
+}  // namespace
+
+URLRequestMockDataJob::URLRequestMockDataJob(URLRequest* request,
+                                             NetworkDelegate* network_delegate,
+                                             const std::string& data,
+                                             int data_repeat_count)
+    : URLRequestJob(request, network_delegate),
+      data_offset_(0),
+      weak_factory_(this) {
+  DCHECK_GT(data_repeat_count, 0);
+  for (int i = 0; i < data_repeat_count; ++i) {
+    data_.append(data);
+  }
+}
+
+void URLRequestMockDataJob::Start() {
+  // Start reading asynchronously so that all error reporting and data
+  // callbacks happen as they would for network requests.
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestMockDataJob::StartAsync,
+                            weak_factory_.GetWeakPtr()));
+}
+
+URLRequestMockDataJob::~URLRequestMockDataJob() {
+}
+
+bool URLRequestMockDataJob::ReadRawData(IOBuffer* buf,
+                                        int buf_size,
+                                        int* bytes_read) {
+  DCHECK(bytes_read);
+  *bytes_read = static_cast<int>(
+      std::min(static_cast<size_t>(buf_size), data_.length() - data_offset_));
+  memcpy(buf->data(), data_.c_str() + data_offset_, *bytes_read);
+  data_offset_ += *bytes_read;
+  return true;
+}
+
+void URLRequestMockDataJob::StartAsync() {
+  if (!request_)
+    return;
+
+  set_expected_content_size(data_.length());
+  NotifyHeadersComplete();
+}
+
+// static
+void URLRequestMockDataJob::AddUrlHandler() {
+  return AddUrlHandlerForHostname(kMockHostname);
+}
+
+// static
+void URLRequestMockDataJob::AddUrlHandlerForHostname(
+    const std::string& hostname) {
+  // Add |hostname| to net::URLRequestFilter for HTTP and HTTPS.
+  net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance();
+  filter->AddHostnameInterceptor("http", hostname,
+                                 make_scoped_ptr(new MockJobInterceptor()));
+  filter->AddHostnameInterceptor("https", hostname,
+                                 make_scoped_ptr(new MockJobInterceptor()));
+}
+
+// static
+GURL URLRequestMockDataJob::GetMockHttpUrl(const std::string& data,
+                                           int repeat_count) {
+  return GetMockHttpUrlForHostname(kMockHostname, data, repeat_count);
+}
+
+// static
+GURL URLRequestMockDataJob::GetMockHttpsUrl(const std::string& data,
+                                            int repeat_count) {
+  return GetMockHttpsUrlForHostname(kMockHostname, data, repeat_count);
+}
+
+// static
+GURL URLRequestMockDataJob::GetMockHttpUrlForHostname(
+    const std::string& hostname,
+    const std::string& data,
+    int repeat_count) {
+  return GetMockUrl("http", hostname, data, repeat_count);
+}
+
+// static
+GURL URLRequestMockDataJob::GetMockHttpsUrlForHostname(
+    const std::string& hostname,
+    const std::string& data,
+    int repeat_count) {
+  return GetMockUrl("https", hostname, data, repeat_count);
+}
+
+}  // namespace net
diff --git a/net/test/url_request/url_request_mock_data_job.h b/net/test/url_request/url_request_mock_data_job.h
new file mode 100644
index 0000000..5bdfa23
--- /dev/null
+++ b/net/test/url_request/url_request_mock_data_job.h
@@ -0,0 +1,60 @@
+// 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 NET_URL_REQUEST_URL_REQUEST_MOCK_DATA_JOB_H_
+#define NET_URL_REQUEST_URL_REQUEST_MOCK_DATA_JOB_H_
+
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "net/base/net_export.h"
+#include "net/url_request/url_request_job.h"
+
+namespace net {
+
+class URLRequest;
+
+// Mock data job, which synchronously returns data repeated multiple times.
+class URLRequestMockDataJob : public URLRequestJob {
+ public:
+  URLRequestMockDataJob(URLRequest* request,
+                        NetworkDelegate* network_delegate,
+                        const std::string& data,
+                        int data_repeat_count);
+
+  void Start() override;
+  bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
+
+  // Adds the testing URLs to the URLRequestFilter.
+  static void AddUrlHandler();
+  static void AddUrlHandlerForHostname(const std::string& hostname);
+
+  // Given data and repeat cound, constructs a mock URL that will return that
+  // data repeated |repeat_count| times when started.  |data| must be safe for
+  // URL.
+  static GURL GetMockHttpUrl(const std::string& data, int repeat_count);
+  static GURL GetMockHttpsUrl(const std::string& data, int repeat_count);
+
+  // URLRequestFailedJob must be added as a handler for |hostname| for
+  // the returned URL to return |net_error|.
+  static GURL GetMockHttpUrlForHostname(const std::string& hostname,
+                                        const std::string& data,
+                                        int repeat_count);
+  static GURL GetMockHttpsUrlForHostname(const std::string& hostname,
+                                         const std::string& data,
+                                         int repeat_count);
+
+ private:
+  ~URLRequestMockDataJob() override;
+
+  void StartAsync();
+
+  std::string data_;
+  size_t data_offset_;
+  base::WeakPtrFactory<URLRequestMockDataJob> weak_factory_;
+};
+
+}  // namespace net
+
+#endif  // NET_URL_REQUEST_URL_REQUEST_SIMPLE_JOB_H_
diff --git a/net/tools/crash_cache/crash_cache.cc b/net/tools/crash_cache/crash_cache.cc
index d548c79..9ec15bb 100644
--- a/net/tools/crash_cache/crash_cache.cc
+++ b/net/tools/crash_cache/crash_cache.cc
@@ -17,7 +17,6 @@
 #include "base/path_service.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
-#include "base/process/process_handle.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -50,15 +49,15 @@
   base::CommandLine cmdline(exe);
   cmdline.AppendArg(base::IntToString(action));
 
-  base::ProcessHandle handle;
-  if (!base::LaunchProcess(cmdline, base::LaunchOptions(), &handle)) {
+  base::Process process = base::LaunchProcess(cmdline, base::LaunchOptions());
+  if (!process.IsValid()) {
     printf("Unable to run test %d\n", action);
     return GENERIC;
   }
 
   int exit_code;
 
-  if (!base::WaitForExitCode(handle, &exit_code)) {
+  if (!process.WaitForExit(&exit_code)) {
     printf("Unable to get return code, test %d\n", action);
     return GENERIC;
   }
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index 3cd8cf4..2deb0f5 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -97,18 +97,32 @@
     filtered_read_buffer_ = buf;
     filtered_read_buffer_len_ = buf_size;
 
+    // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+    tracked_objects::ScopedTracker tracking_profile2(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 URLRequestJob::Read2"));
+
     if (ReadFilteredData(bytes_read)) {
       rv = true;   // We have data to return.
 
       // It is fine to call DoneReading even if ReadFilteredData receives 0
       // bytes from the net, but we avoid making that call if we know for
       // sure that's the case (ReadRawDataHelper path).
+      // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is
+      // fixed.
+      tracked_objects::ScopedTracker tracking_profile3(
+          FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 URLRequestJob::Read3"));
+
       if (*bytes_read == 0)
         DoneReading();
     } else {
       rv = false;  // Error, or a new IO is pending.
     }
   }
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile4(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 URLRequestJob::Read4"));
+
   if (rv && *bytes_read == 0)
     NotifyDone(URLRequestStatus());
   return rv;
@@ -487,6 +501,10 @@
 }
 
 void URLRequestJob::NotifyReadComplete(int bytes_read) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION("URLRequestJob::NotifyReadComplete"));
+
   if (!request_ || !request_->has_delegate())
     return;  // The request was destroyed, so there is no more work to do.
 
@@ -801,6 +819,11 @@
 
 bool URLRequestJob::ReadRawDataHelper(IOBuffer* buf, int buf_size,
                                       int* bytes_read) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "423948 URLRequestJob::ReadRawDataHelper"));
+
   DCHECK(!request_->status().is_io_pending());
   DCHECK(raw_read_buffer_.get() == NULL);
 
diff --git a/services/surfaces/surfaces_impl.cc b/services/surfaces/surfaces_impl.cc
index df91bf8..eccdd75 100644
--- a/services/surfaces/surfaces_impl.cc
+++ b/services/surfaces/surfaces_impl.cc
@@ -19,7 +19,7 @@
 namespace surfaces {
 
 namespace {
-void CallCallback(const mojo::Closure& callback) {
+void CallCallback(const mojo::Closure& callback, bool frame_drawn) {
   callback.Run();
 }
 }
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index bd039e3..07b47d2 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -257,10 +257,6 @@
 #   define SK_SUPPORT_LEGACY_PUBLIC_IMAGEINFO_FIELDS
 #endif
 
-#ifndef    SK_SUPPORT_LEGACY_PICTURE_CLONE
-#   define SK_SUPPORT_LEGACY_PICTURE_CLONE
-#endif
-
 #ifndef    SK_IGNORE_ETC1_SUPPORT
 #   define SK_IGNORE_ETC1_SUPPORT
 #endif
@@ -269,24 +265,14 @@
 #   define SK_IGNORE_GPU_DITHER
 #endif
 
-#ifndef    SK_LEGACY_PICTURE_SIZE_API
-#   define SK_LEGACY_PICTURE_SIZE_API
-#endif
-
 #ifndef    SK_LEGACY_PICTURE_DRAW_API
 #   define SK_LEGACY_PICTURE_DRAW_API
 #endif
 
-
-// Turns SkPicture::clone() into a simple "return SkRef(this);" as a way to
-// test the threadsafety of SkPicture playback.
-#define SK_PICTURE_CLONE_NOOP 1
-
-// Turns on new (nicer, hopefully faster) SkPicture backend.
-#define SK_PICTURE_USE_SK_RECORD 1
-
-// Run a few optimization passes over the SkRecord after recording.
-#define SK_PICTURE_OPTIMIZE_SK_RECORD 1
+// If this goes well, we can have Skia respect DYNAMIC_ANNOTATIONS_ENABLED directly.
+#if DYNAMIC_ANNOTATIONS_ENABLED
+#    define SK_DYNAMIC_ANNOTATIONS_ENABLED 1
+#endif
 
 // ===== End Chrome-specific definitions =====
 
diff --git a/skia/ext/pixel_ref_utils.cc b/skia/ext/pixel_ref_utils.cc
index 324adbd..777c253 100644
--- a/skia/ext/pixel_ref_utils.cc
+++ b/skia/ext/pixel_ref_utils.cc
@@ -351,15 +351,17 @@
   pixel_refs->clear();
   DiscardablePixelRefSet pixel_ref_set(pixel_refs);
 
+  SkRect picture_bounds = picture->cullRect();
+  SkIRect picture_ibounds = picture_bounds.roundOut();
   SkBitmap empty_bitmap;
-  empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture->width(), picture->height()));
+  empty_bitmap.setInfo(SkImageInfo::MakeUnknown(picture_ibounds.width(),
+                                                picture_ibounds.height()));
 
   GatherPixelRefDevice device(empty_bitmap, &pixel_ref_set);
   SkNoSaveLayerCanvas canvas(&device);
 
-  canvas.clipRect(SkRect::MakeWH(picture->width(), picture->height()),
-                  SkRegion::kIntersect_Op,
-                  false);
+  // Draw the picture pinned against our top/left corner.
+  canvas.translate(-picture_bounds.left(), -picture_bounds.top());
   canvas.drawPicture(picture);
 }
 
diff --git a/skia/ext/skia_utils_mac.mm b/skia/ext/skia_utils_mac.mm
index dd8f560..9e552eb 100644
--- a/skia/ext/skia_utils_mac.mm
+++ b/skia/ext/skia_utils_mac.mm
@@ -376,16 +376,9 @@
     if (!bitmap_.extractSubset(&subset, bounds)) {
         return;
     }
-    // Neutralize the global matrix by concatenating the inverse. In the
-    // future, Skia may provide some mechanism to set the device portion of
-    // the matrix to identity without clobbering any hosting matrix (e.g., the
-    // picture's matrix).
-    const SkMatrix& skMatrix = canvas_->getTotalMatrix();
-    SkMatrix inverse;
-    if (!skMatrix.invert(&inverse))
-      return;
+    subset.setImmutable();  // Prevents a defensive copy inside Skia.
     canvas_->save();
-    canvas_->concat(inverse);
+    canvas_->setMatrix(SkMatrix::I());  // Reset back to device space.
     canvas_->translate(bounds.x() + bitmapOffset_.x(),
                        bounds.y() + bitmapOffset_.y());
     canvas_->scale(1.f / bitmapScaleFactor_, 1.f / bitmapScaleFactor_);
diff --git a/sky/engine/core/rendering/RenderBlock.cpp b/sky/engine/core/rendering/RenderBlock.cpp
index e4f0aef..1c66659 100644
--- a/sky/engine/core/rendering/RenderBlock.cpp
+++ b/sky/engine/core/rendering/RenderBlock.cpp
@@ -49,7 +49,6 @@
 #include "sky/engine/core/rendering/style/RenderStyle.h"
 #include "sky/engine/platform/geometry/FloatQuad.h"
 #include "sky/engine/platform/geometry/TransformState.h"
-#include "sky/engine/platform/graphics/GraphicsContextCullSaver.h"
 #include "sky/engine/platform/graphics/GraphicsContextStateSaver.h"
 #include "sky/engine/wtf/StdLibExtras.h"
 #include "sky/engine/wtf/TemporaryChange.h"
@@ -597,13 +596,6 @@
 
     bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, contentsClipBehavior);
     {
-        GraphicsContextCullSaver cullSaver(*paintInfo.context);
-        // Cull if we have more than one child and we didn't already clip.
-        bool shouldCull = document().settings()->containerCullingEnabled() && !pushedClip && !isDocumentElement()
-            && firstChild() && lastChild() && firstChild() != lastChild();
-        if (shouldCull)
-            cullSaver.cull(overflowBox);
-
         paintObject(paintInfo, adjustedPaintOffset);
     }
     if (pushedClip)
diff --git a/sky/engine/platform/graphics/GraphicsContext.cpp b/sky/engine/platform/graphics/GraphicsContext.cpp
index 8f17728..2a7fb35 100644
--- a/sky/engine/platform/graphics/GraphicsContext.cpp
+++ b/sky/engine/platform/graphics/GraphicsContext.cpp
@@ -1471,25 +1471,6 @@
     m_canvas->clipRRect(rect, op, aa == AntiAliased);
 }
 
-void GraphicsContext::beginCull(const FloatRect& rect)
-{
-    if (contextDisabled())
-        return;
-
-    realizeCanvasSave();
-    m_canvas->pushCull(rect);
-}
-
-void GraphicsContext::endCull()
-{
-    if (contextDisabled())
-        return;
-
-    realizeCanvasSave();
-
-    m_canvas->popCull();
-}
-
 void GraphicsContext::rotate(float angleInRadians)
 {
     if (contextDisabled())
diff --git a/sky/engine/platform/graphics/GraphicsContext.h b/sky/engine/platform/graphics/GraphicsContext.h
index 6f59a2f..782fa23 100644
--- a/sky/engine/platform/graphics/GraphicsContext.h
+++ b/sky/engine/platform/graphics/GraphicsContext.h
@@ -325,9 +325,6 @@
     void beginLayer(float opacity, CompositeOperator, const FloatRect* = 0, ColorFilter = ColorFilterNone, ImageFilter* = 0);
     void endLayer();
 
-    void beginCull(const FloatRect&);
-    void endCull();
-
     // Instead of being dispatched to the active canvas, draw commands following beginRecording()
     // are stored in a display list that can be replayed at a later time.
     void beginRecording(const FloatRect& bounds);
diff --git a/sky/engine/platform/graphics/GraphicsContextCullSaver.h b/sky/engine/platform/graphics/GraphicsContextCullSaver.h
deleted file mode 100644
index 7ea99f4..0000000
--- a/sky/engine/platform/graphics/GraphicsContextCullSaver.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef GraphicsContextCullSaver_h
-#define GraphicsContextCullSaver_h
-
-#include "sky/engine/platform/graphics/GraphicsContext.h"
-
-namespace blink {
-
-class FloatRect;
-
-class GraphicsContextCullSaver {
-    WTF_MAKE_FAST_ALLOCATED;
-public:
-    GraphicsContextCullSaver(GraphicsContext& context)
-        : m_context(context)
-        , m_cullApplied(false)
-    {
-    }
-
-    GraphicsContextCullSaver(GraphicsContext& context, const FloatRect& rect)
-        : m_context(context)
-        , m_cullApplied(true)
-    {
-        context.beginCull(rect);
-    }
-
-    ~GraphicsContextCullSaver()
-    {
-        if (m_cullApplied)
-            m_context.endCull();
-    }
-
-    void cull(const FloatRect& rect)
-    {
-        ASSERT(!m_cullApplied);
-        m_context.beginCull(rect);
-        m_cullApplied = true;
-    }
-
-private:
-    GraphicsContext& m_context;
-    bool m_cullApplied;
-};
-
-} // namespace blink
-
-#endif // GraphicsContextCullSaver_h
diff --git a/sky/engine/platform/graphics/GraphicsContextRecorder.cpp b/sky/engine/platform/graphics/GraphicsContextRecorder.cpp
index 6b8851b..05d82f6 100644
--- a/sky/engine/platform/graphics/GraphicsContextRecorder.cpp
+++ b/sky/engine/platform/graphics/GraphicsContextRecorder.cpp
@@ -100,10 +100,9 @@
 
 PassOwnPtr<Vector<char> > GraphicsContextSnapshot::replay(unsigned fromStep, unsigned toStep, double scale) const
 {
-    int width = ceil(scale * m_picture->width());
-    int height = ceil(scale * m_picture->height());
+    const SkIRect bounds = m_picture->cullRect().roundOut();
     SkBitmap bitmap;
-    bitmap.allocPixels(SkImageInfo::MakeN32Premul(width, height));
+    bitmap.allocPixels(SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()));
     {
         ReplayingCanvas canvas(bitmap, fromStep, toStep);
         canvas.scale(scale, scale);
@@ -122,8 +121,9 @@
 {
     OwnPtr<GraphicsContextSnapshot::Timings> timings = adoptPtr(new GraphicsContextSnapshot::Timings());
     timings->reserveCapacity(minRepeatCount);
+    const SkIRect bounds = m_picture->cullRect().roundOut();
     SkBitmap bitmap;
-    bitmap.allocPixels(SkImageInfo::MakeN32Premul(m_picture->width(), m_picture->height()));
+    bitmap.allocPixels(SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()));
     OwnPtr<ProfilingCanvas> canvas = adoptPtr(new ProfilingCanvas(bitmap));
 
     double now = WTF::monotonicallyIncreasingTime();
@@ -144,7 +144,8 @@
 
 PassRefPtr<JSONArray> GraphicsContextSnapshot::snapshotCommandLog() const
 {
-    LoggingCanvas canvas(m_picture->width(), m_picture->height());
+    const SkIRect bounds = m_picture->cullRect().roundOut();
+    LoggingCanvas canvas(bounds.width(), bounds.height());
     m_picture->draw(&canvas);
     return canvas.log();
 }
diff --git a/sky/engine/platform/graphics/InterceptingCanvas.h b/sky/engine/platform/graphics/InterceptingCanvas.h
index a3e9ba5..32e50a4 100644
--- a/sky/engine/platform/graphics/InterceptingCanvas.h
+++ b/sky/engine/platform/graphics/InterceptingCanvas.h
@@ -48,7 +48,6 @@
     virtual void drawPath(const SkPath&, const SkPaint&) override = 0;
     virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint* = 0) override = 0;
     virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, DrawBitmapRectFlags) override = 0;
-    virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&, const SkPaint* = 0) override = 0;
     virtual void drawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override = 0;
     virtual void drawSprite(const SkBitmap&, int left, int top, const SkPaint* = 0) override = 0;
     virtual void drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[],
@@ -63,8 +62,6 @@
     virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint&) override = 0;
     virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint&) override = 0;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath&, const SkMatrix*, const SkPaint&) override = 0;
-    virtual void onPushCull(const SkRect& cullRect) override = 0;
-    virtual void onPopCull() override = 0;
     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override = 0;
     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override = 0;
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override = 0;
diff --git a/sky/engine/platform/graphics/LoggingCanvas.cpp b/sky/engine/platform/graphics/LoggingCanvas.cpp
index 18adab9..8cb941f 100644
--- a/sky/engine/platform/graphics/LoggingCanvas.cpp
+++ b/sky/engine/platform/graphics/LoggingCanvas.cpp
@@ -160,16 +160,6 @@
     this->SkCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags);
 }
 
-void LoggingCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, const SkPaint* paint)
-{
-    AutoLogger logger(this);
-    RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmapMatrix");
-    params->setObject("bitmap", objectForSkBitmap(bitmap));
-    params->setArray("matrix", arrayForSkMatrix(m));
-    params->setObject("paint", objectForSkPaint(*paint));
-    this->SkCanvas::drawBitmapMatrix(bitmap, m, paint);
-}
-
 void LoggingCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint)
 {
     AutoLogger logger(this);
@@ -288,21 +278,6 @@
     this->SkCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint);
 }
 
-void LoggingCanvas::onPushCull(const SkRect& cullRect)
-{
-    AutoLogger logger(this);
-    RefPtr<JSONObject> params = logger.logItemWithParams("pushCull");
-    params->setObject("cullRect", objectForSkRect(cullRect));
-    this->SkCanvas::onPushCull(cullRect);
-}
-
-void LoggingCanvas::onPopCull()
-{
-    AutoLogger logger(this);
-    logger.logItem("popCull");
-    this->SkCanvas::onPopCull();
-}
-
 void LoggingCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle style)
 {
     AutoLogger logger(this);
@@ -461,9 +436,10 @@
 
 PassRefPtr<JSONObject> LoggingCanvas::objectForSkPicture(const SkPicture& picture)
 {
+    const SkIRect bounds = picture.cullRect().roundOut();
     RefPtr<JSONObject> pictureItem = JSONObject::create();
-    pictureItem->setNumber("width", picture.width());
-    pictureItem->setNumber("height", picture.height());
+    pictureItem->setNumber("width", bounds.width());
+    pictureItem->setNumber("height", bounds.height());
     return pictureItem.release();
 }
 
diff --git a/sky/engine/platform/graphics/LoggingCanvas.h b/sky/engine/platform/graphics/LoggingCanvas.h
index 3483015..6abb7a3 100644
--- a/sky/engine/platform/graphics/LoggingCanvas.h
+++ b/sky/engine/platform/graphics/LoggingCanvas.h
@@ -49,7 +49,6 @@
     virtual void drawPath(const SkPath&, const SkPaint&) override;
     virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint* = 0) override;
     virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, DrawBitmapRectFlags) override;
-    virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&, const SkPaint* = 0) override;
     virtual void drawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override;
     virtual void drawSprite(const SkBitmap&, int left, int top, const SkPaint* = 0) override;
     virtual void drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[],
@@ -64,8 +63,6 @@
     virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint&) override;
     virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint&) override;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath&, const SkMatrix*, const SkPaint&) override;
-    virtual void onPushCull(const SkRect& cullRect) override;
-    virtual void onPopCull() override;
     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
diff --git a/sky/engine/platform/graphics/ProfilingCanvas.cpp b/sky/engine/platform/graphics/ProfilingCanvas.cpp
index 2940339..728a5c0 100644
--- a/sky/engine/platform/graphics/ProfilingCanvas.cpp
+++ b/sky/engine/platform/graphics/ProfilingCanvas.cpp
@@ -118,12 +118,6 @@
     this->SkCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags);
 }
 
-void ProfilingCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, const SkPaint* paint)
-{
-    AutoStamper stamper(this);
-    this->SkCanvas::drawBitmapMatrix(bitmap, m, paint);
-}
-
 void ProfilingCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint)
 {
     AutoStamper stamper(this);
@@ -197,18 +191,6 @@
     this->SkCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint);
 }
 
-void ProfilingCanvas::onPushCull(const SkRect& cullRect)
-{
-    AutoStamper stamper(this);
-    this->SkCanvas::onPushCull(cullRect);
-}
-
-void ProfilingCanvas::onPopCull()
-{
-    AutoStamper stamper(this);
-    this->SkCanvas::onPopCull();
-}
-
 void ProfilingCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle)
 {
     AutoStamper stamper(this);
diff --git a/sky/engine/platform/graphics/ProfilingCanvas.h b/sky/engine/platform/graphics/ProfilingCanvas.h
index b390ab4..4ec11f2 100644
--- a/sky/engine/platform/graphics/ProfilingCanvas.h
+++ b/sky/engine/platform/graphics/ProfilingCanvas.h
@@ -49,7 +49,6 @@
     virtual void drawPath(const SkPath&, const SkPaint&) override;
     virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint* = 0) override;
     virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, DrawBitmapRectFlags) override;
-    virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&, const SkPaint* = 0) override;
     virtual void drawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override;
     virtual void drawSprite(const SkBitmap&, int left, int top, const SkPaint* = 0) override;
     virtual void drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[],
@@ -64,8 +63,6 @@
     virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint&) override;
     virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint&) override;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath&, const SkMatrix*, const SkPaint&) override;
-    virtual void onPushCull(const SkRect& cullRect) override;
-    virtual void onPopCull() override;
     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
diff --git a/sky/engine/platform/graphics/ReplayingCanvas.cpp b/sky/engine/platform/graphics/ReplayingCanvas.cpp
index 3c13a10..dbb2d19 100644
--- a/sky/engine/platform/graphics/ReplayingCanvas.cpp
+++ b/sky/engine/platform/graphics/ReplayingCanvas.cpp
@@ -132,12 +132,6 @@
     this->SkCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags);
 }
 
-void ReplayingCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, const SkPaint* paint)
-{
-    AutoReplayer replayer(this);
-    this->SkCanvas::drawBitmapMatrix(bitmap, m, paint);
-}
-
 void ReplayingCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint)
 {
     AutoReplayer replayer(this);
@@ -211,18 +205,6 @@
     this->SkCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint);
 }
 
-void ReplayingCanvas::onPushCull(const SkRect& cullRect)
-{
-    AutoReplayer replayer(this);
-    this->SkCanvas::onPushCull(cullRect);
-}
-
-void ReplayingCanvas::onPopCull()
-{
-    AutoReplayer replayer(this);
-    this->SkCanvas::onPopCull();
-}
-
 void ReplayingCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle)
 {
     AutoReplayer replayer(this);
diff --git a/sky/engine/platform/graphics/ReplayingCanvas.h b/sky/engine/platform/graphics/ReplayingCanvas.h
index a8e9541..4939db6 100644
--- a/sky/engine/platform/graphics/ReplayingCanvas.h
+++ b/sky/engine/platform/graphics/ReplayingCanvas.h
@@ -51,7 +51,6 @@
     virtual void drawPath(const SkPath&, const SkPaint&) override;
     virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint* = 0) override;
     virtual void drawBitmapRectToRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*, DrawBitmapRectFlags) override;
-    virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&, const SkPaint* = 0) override;
     virtual void drawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, const SkPaint*) override;
     virtual void drawSprite(const SkBitmap&, int left, int top, const SkPaint* = 0) override;
     virtual void drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[],
@@ -66,8 +65,6 @@
     virtual void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint&) override;
     virtual void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint&) override;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath&, const SkMatrix*, const SkPaint&) override;
-    virtual void onPushCull(const SkRect& cullRect) override;
-    virtual void onPopCull() override;
     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 0927e93..42cc7c7 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -362,71 +362,5 @@
       { "test": "content_unittests", "args": ["--enable-browser-side-navigation"] },
       { "test": "content_browsertests", "args": ["--enable-browser-side-navigation"] }
     ]
-  },
-  "Linux ChromeOS MSan Tests": {
-    "gtest_tests": [
-      "accessibility_unittests",
-      "app_list_unittests",
-      "app_shell_browsertests",
-      "aura_unittests",
-      "base_unittests",
-      "cacheinvalidation_unittests",
-      "cast_unittests",
-      "cc_unittests",
-      "chromedriver_unittests",
-      "components_unittests",
-      "content_browsertests",
-      "content_unittests",
-      "crypto_unittests",
-      "dbus_unittests",
-      "device_unittests",
-      "display_unittests",
-      "events_unittests",
-      "extensions_unittests",
-      "gcm_unit_tests",
-      "gfx_unittests",
-      "google_apis_unittests",
-      "gpu_unittests",
-      "interactive_ui_tests",
-      "ipc_mojo_unittests",
-      "ipc_tests",
-      "jingle_unittests",
-      "media_unittests",
-      "mojo_common_unittests",
-      "mojo_public_bindings_unittests",
-      "mojo_public_environment_unittests",
-      "mojo_public_system_unittests",
-      "mojo_public_utility_unittests",
-      "mojo_system_unittests",
-      "nacl_loader_unittests",
-      "net_unittests",
-      "ppapi_unittests",
-      "printing_unittests",
-      "remoting_unittests",
-      "sandbox_linux_unittests",
-      "sql_unittests",
-      "sync_unit_tests",
-      "ui_base_unittests",
-      "ui_touch_selection_unittests",
-      "unit_tests",
-      "url_unittests",
-      "views_unittests",
-      "wm_unittests"
-    ]
-  },
-  "Linux ChromeOS MSan Browser (1)": {
-    "gtest_tests": [
-      {"test": "browser_tests", "shard_index": 0, "total_shards": 3}
-    ]
-  },
-  "Linux ChromeOS MSan Browser (2)": {
-    "gtest_tests": [
-      {"test": "browser_tests", "shard_index": 1, "total_shards": 3}
-    ]
-  },
-  "Linux ChromeOS MSan Browser (3)": {
-    "gtest_tests": [
-      {"test": "browser_tests", "shard_index": 2, "total_shards": 3}
-    ]
   }
 }
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 39bfb16..d9f5f96 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -1,8 +1,18 @@
 {
   "Linux Tests": {
     "gtest_tests": [
-      "accessibility_unittests",
-      "app_list_unittests",
+      {
+        "test": "accessibility_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
+      {
+        "test": "app_list_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "app_shell_browsertests",
       "app_shell_unittests",
       "aura_unittests",
@@ -41,10 +51,20 @@
       "dbus_unittests",
       "device_unittests",
       "display_unittests",
-      "events_unittests",
+      {
+        "test": "events_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "extensions_unittests",
       "gcm_unit_tests",
-      "gfx_unittests",
+      {
+        "test": "gfx_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "google_apis_unittests",
       "gpu_unittests",
       {
@@ -75,7 +95,12 @@
       "remoting_unittests",
       "sandbox_linux_unittests",
       "sql_unittests",
-      "ui_base_unittests",
+      {
+        "test": "ui_base_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "ui_touch_selection_unittests",
       {
         "test": "sync_integration_tests",
@@ -111,8 +136,18 @@
   },
   "Linux Tests (dbg)(1)(32)": {
     "gtest_tests": [
-      "accessibility_unittests",
-      "app_list_unittests",
+      {
+        "test": "accessibility_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
+      {
+        "test": "app_list_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "app_shell_browsertests",
       "app_shell_unittests",
       "aura_unittests",
@@ -151,10 +186,20 @@
       "dbus_unittests",
       "device_unittests",
       "display_unittests",
-      "events_unittests",
+      {
+        "test": "events_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "extensions_unittests",
       "gcm_unit_tests",
-      "gfx_unittests",
+      {
+        "test": "gfx_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "google_apis_unittests",
       "gpu_unittests",
       {
@@ -185,7 +230,12 @@
       "remoting_unittests",
       "sandbox_linux_unittests",
       "sql_unittests",
-      "ui_base_unittests",
+      {
+        "test": "ui_base_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "ui_touch_selection_unittests",
       {
         "test": "sync_integration_tests",
@@ -213,8 +263,18 @@
   },
   "Linux Tests (dbg)(1)": {
     "gtest_tests": [
-      "accessibility_unittests",
-      "app_list_unittests",
+      {
+        "test": "accessibility_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
+      {
+        "test": "app_list_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "app_shell_browsertests",
       "app_shell_unittests",
       "aura_unittests",
@@ -253,10 +313,20 @@
       "dbus_unittests",
       "device_unittests",
       "display_unittests",
-      "events_unittests",
+      {
+        "test": "events_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "extensions_unittests",
       "gcm_unit_tests",
-      "gfx_unittests",
+      {
+        "test": "gfx_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "google_apis_unittests",
       "gpu_unittests",
       {
@@ -291,7 +361,12 @@
         "args": ["--test-launcher-print-test-stdio=always"]
       },
       "sql_unittests",
-      "ui_base_unittests",
+      {
+        "test": "ui_base_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "ui_touch_selection_unittests",
       {
         "test": "sync_integration_tests",
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 0ea46e9..8a20416 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -1,8 +1,18 @@
 {
   "Mac10.6 Tests": {
     "gtest_tests": [
-      "accessibility_unittests",
-      "app_list_unittests",
+      {
+        "test": "accessibility_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
+      {
+        "test": "app_list_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       {
         "test": "base_unittests",
         "swarming": {
@@ -36,7 +46,12 @@
       "crypto_unittests",
       "extensions_unittests",
       "gcm_unit_tests",
-      "gfx_unittests",
+      {
+        "test": "gfx_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "gpu_unittests",
       "google_apis_unittests",
       {
@@ -48,7 +63,12 @@
       "ipc_tests",
       "jingle_unittests",
       "media_unittests",
-      "message_center_unittests",
+      {
+        "test": "message_center_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "mojo_common_unittests",
       "mojo_public_bindings_unittests",
       "mojo_public_environment_unittests",
@@ -73,7 +93,12 @@
         }
       },
       "sync_unit_tests",
-      "ui_base_unittests",
+      {
+        "test": "ui_base_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       {
         "test": "unit_tests",
         "swarming": {
@@ -99,8 +124,18 @@
   },
   "Mac10.8 Tests": {
     "gtest_tests": [
-      "accessibility_unittests",
-      "app_list_unittests",
+      {
+        "test": "accessibility_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
+      {
+        "test": "app_list_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       {
         "test": "base_unittests",
         "swarming": {
@@ -134,7 +169,12 @@
       "crypto_unittests",
       "extensions_unittests",
       "gcm_unit_tests",
-      "gfx_unittests",
+      {
+        "test": "gfx_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "gpu_unittests",
       "google_apis_unittests",
       {
@@ -146,7 +186,12 @@
       "ipc_tests",
       "jingle_unittests",
       "media_unittests",
-      "message_center_unittests",
+      {
+        "test": "message_center_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "mojo_common_unittests",
       "mojo_public_bindings_unittests",
       "mojo_public_environment_unittests",
@@ -171,7 +216,12 @@
         }
       },
       "sync_unit_tests",
-      "ui_base_unittests",
+      {
+        "test": "ui_base_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       {
         "test": "unit_tests",
         "swarming": {
@@ -197,8 +247,18 @@
   },
   "Mac10.9 Tests": {
     "gtest_tests": [
-      "accessibility_unittests",
-      "app_list_unittests",
+      {
+        "test": "accessibility_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
+      {
+        "test": "app_list_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       {
         "test": "base_unittests",
         "swarming": {
@@ -232,7 +292,12 @@
       "crypto_unittests",
       "extensions_unittests",
       "gcm_unit_tests",
-      "gfx_unittests",
+      {
+        "test": "gfx_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "gpu_unittests",
       "google_apis_unittests",
       {
@@ -244,7 +309,12 @@
       "ipc_tests",
       "jingle_unittests",
       "media_unittests",
-      "message_center_unittests",
+      {
+        "test": "message_center_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "mojo_common_unittests",
       "mojo_public_bindings_unittests",
       "mojo_public_environment_unittests",
@@ -269,7 +339,12 @@
         }
       },
       "sync_unit_tests",
-      "ui_base_unittests",
+      {
+        "test": "ui_base_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       {
         "test": "unit_tests",
         "swarming": {
@@ -295,8 +370,18 @@
   },
   "Mac10.9 Tests (dbg)": {
     "gtest_tests": [
-      "accessibility_unittests",
-      "app_list_unittests",
+      {
+        "test": "accessibility_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
+      {
+        "test": "app_list_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       {
         "test": "base_unittests",
         "swarming": {
@@ -330,7 +415,12 @@
       "crypto_unittests",
       "extensions_unittests",
       "gcm_unit_tests",
-      "gfx_unittests",
+      {
+        "test": "gfx_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "gpu_unittests",
       "google_apis_unittests",
       {
@@ -343,7 +433,12 @@
       "ipc_tests",
       "jingle_unittests",
       "media_unittests",
-      "message_center_unittests",
+      {
+        "test": "message_center_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       "mojo_common_unittests",
       "mojo_public_bindings_unittests",
       "mojo_public_environment_unittests",
@@ -368,7 +463,12 @@
         }
       },
       "sync_unit_tests",
-      "ui_base_unittests",
+      {
+        "test": "ui_base_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        }
+      },
       {
         "test": "unit_tests",
         "swarming": {
diff --git a/testing/buildbot/chromium.memory.fyi.json b/testing/buildbot/chromium.memory.fyi.json
index 1db2fb5..3852f7a 100644
--- a/testing/buildbot/chromium.memory.fyi.json
+++ b/testing/buildbot/chromium.memory.fyi.json
@@ -64,5 +64,70 @@
     "gtest_tests": [
       {"test": "browser_tests", "shard_index": 2, "total_shards": 3}
     ]
+  },
+  "Linux ChromeOS MSan Tests": {
+    "gtest_tests": [
+      "accessibility_unittests",
+      "app_list_unittests",
+      "app_shell_browsertests",
+      "aura_unittests",
+      "base_unittests",
+      "cacheinvalidation_unittests",
+      "cast_unittests",
+      "cc_unittests",
+      "chromedriver_unittests",
+      "components_unittests",
+      "content_browsertests",
+      "content_unittests",
+      "crypto_unittests",
+      "dbus_unittests",
+      "device_unittests",
+      "display_unittests",
+      "events_unittests",
+      "extensions_unittests",
+      "gcm_unit_tests",
+      "gfx_unittests",
+      "google_apis_unittests",
+      "gpu_unittests",
+      "interactive_ui_tests",
+      "ipc_mojo_unittests",
+      "ipc_tests",
+      "jingle_unittests",
+      "media_unittests",
+      "mojo_common_unittests",
+      "mojo_public_bindings_unittests",
+      "mojo_public_environment_unittests",
+      "mojo_public_system_unittests",
+      "mojo_public_utility_unittests",
+      "mojo_system_unittests",
+      "nacl_loader_unittests",
+      "net_unittests",
+      "ppapi_unittests",
+      "printing_unittests",
+      "remoting_unittests",
+      "sandbox_linux_unittests",
+      "sql_unittests",
+      "sync_unit_tests",
+      "ui_base_unittests",
+      "unit_tests",
+      "url_unittests",
+      "views_unittests",
+      "wm_unittests"
+    ]
+  },
+  "Linux ChromeOS MSan Browser (1)": {
+    "gtest_tests": [
+      {"test": "browser_tests", "shard_index": 0, "total_shards": 3}
+    ]
+  },
+  "Linux ChromeOS MSan Browser (2)": {
+    "gtest_tests": [
+      {"test": "browser_tests", "shard_index": 1, "total_shards": 3}
+    ]
+  },
+  "Linux ChromeOS MSan Browser (3)": {
+    "gtest_tests": [
+      {"test": "browser_tests", "shard_index": 2, "total_shards": 3}
+    ]
   }
 }
diff --git a/testing/buildbot/chromium_trybot.json b/testing/buildbot/chromium_trybot.json
index 9a0e4af..7925d5d 100644
--- a/testing/buildbot/chromium_trybot.json
+++ b/testing/buildbot/chromium_trybot.json
@@ -3,12 +3,22 @@
     "all"
   ],
   "gtest_tests": [
-    "accessibility_unittests",
+    {
+      "test": "accessibility_unittests",
+      "swarming": {
+        "can_use_on_swarming_builders": true
+      }
+    },
     {
       "test": "app_installer_unittests",
       "platforms": ["win"]
     },
-    "app_list_unittests",
+    {
+      "test": "app_list_unittests",
+      "swarming": {
+        "can_use_on_swarming_builders": true
+      }
+    },
     {
       "test": "ash_unittests",
       "chromium_configs": [
@@ -84,13 +94,23 @@
       "platforms": ["linux"]
     },
     "device_unittests",
-    "events_unittests",
+    {
+      "test": "events_unittests",
+      "swarming": {
+        "can_use_on_swarming_builders": true
+      }
+    },
     {
       "test": "extensions_unittests",
       "platforms": ["win", "mac", "linux"]
     },
     "gcm_unit_tests",
-    "gfx_unittests",
+    {
+      "test": "gfx_unittests",
+      "swarming": {
+        "can_use_on_swarming_builders": true
+      }
+    },
     "google_apis_unittests",
     "gpu_unittests",
     {
@@ -116,7 +136,12 @@
     },
     "media_perftests",
     "media_unittests",
-    "message_center_unittests",
+    {
+      "test": "message_center_unittests",
+      "swarming": {
+        "can_use_on_swarming_builders": true
+      }
+    },
     "mojo_common_unittests",
     "mojo_public_bindings_unittests",
     "mojo_public_environment_unittests",
@@ -157,7 +182,12 @@
       }
     },
     "sync_unit_tests",
-    "ui_base_unittests",
+    {
+      "test": "ui_base_unittests",
+      "swarming": {
+        "can_use_on_swarming_builders": true
+      }
+    },
     "ui_touch_selection_unittests",
     {
       "test": "unit_tests",
diff --git a/third_party/cython/rules.gni b/third_party/cython/rules.gni
index 53125fe..5cfea1a 100644
--- a/third_party/cython/rules.gni
+++ b/third_party/cython/rules.gni
@@ -2,34 +2,37 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-template("python_binary_module_sources") {
+template("python_binary_source_set") {
   # Only available on linux for now.
   assert(is_linux)
-  assert(defined(invoker.sources))
+  assert(defined(invoker.cython_sources) || defined(invoker.sources))
 
-  cython_root = "//third_party/cython"
-  cython_script = "$cython_root/src/cython.py"
-  cython_output = "${target_out_dir}/${target_name}.cc"
-
-  generator_target_name = target_name + "_cython_compiler"
   config_name = target_name + "_python_config"
 
   target_visibility = [ ":$target_name" ]
 
-  action(generator_target_name) {
-    visibility = target_visibility
-    script = cython_script
-    sources = invoker.sources
-    outputs = [
-      cython_output,
-    ]
-    args = [
-             "--cplus",
-             "-I",
-             rebase_path("//", root_build_dir),
-             "-o",
-             rebase_path(cython_output, root_build_dir),
-           ] + rebase_path(sources, root_build_dir)
+  if (defined(invoker.cython_sources)) {
+    generator_target_name = target_name + "_cython_compiler"
+
+    cython_root = "//third_party/cython"
+    cython_script = "$cython_root/src/cython.py"
+    cython_output = "${target_out_dir}/${target_name}.cc"
+
+    action(generator_target_name) {
+      visibility = target_visibility
+      script = cython_script
+      sources = invoker.cython_sources
+      outputs = [
+        cython_output,
+      ]
+      args = [
+               "--cplus",
+               "-I",
+               rebase_path("//", root_build_dir),
+               "-o",
+               rebase_path(cython_output, root_build_dir),
+             ] + rebase_path(sources, root_build_dir)
+    }
   }
 
   config(config_name) {
@@ -45,35 +48,40 @@
   }
 
   source_set(target_name) {
-    deps = [
-      ":$generator_target_name",
-    ]
     if (defined(invoker.visibility)) {
       visibility = invoker.visibility
     }
+    sources = []
+    if (defined(invoker.cython_sources)) {
+      sources += [ cython_output ]
+    }
+    if (defined(invoker.sources)) {
+      sources += invoker.sources
+    }
+    if (defined(invoker.configs)) {
+      configs += invoker.configs
+    }
+    all_dependent_configs = [ ":$config_name" ]
+    deps = []
+    if (defined(invoker.cython_sources)) {
+      deps += [ ":$generator_target_name" ]
+    }
     if (defined(invoker.deps)) {
       deps += invoker.deps
     }
     if (defined(invoker.datadeps)) {
       datadeps = invoker.datadeps
     }
-    sources = [
-      cython_output,
-    ]
-    if (defined(invoker.additional_sources)) {
-      sources += invoker.additional_sources
-    }
-    if (defined(invoker.configs)) {
-      configs += invoker.configs
-    }
-    all_dependent_configs = [ ":$config_name" ]
   }
 }
 
 template("python_binary_module") {
   # Only available on linux for now.
   assert(is_linux)
-  assert(defined(invoker.sources))
+
+  has_sources = defined(invoker.cython_sources) || defined(invoker.sources)
+
+  assert(has_sources || defined(invoker.deps))
   assert(defined(invoker.python_base_module))
 
   sources_target_name = target_name + "_cython_sources"
@@ -91,31 +99,42 @@
     ":$target_name",
   ]
 
-  python_binary_module_sources(sources_target_name) {
-    visibility = target_visibility
-    sources = invoker.sources
-    if (defined(invoker.configs)) {
-      configs = invoker.configs
+  if (has_sources) {
+    python_binary_source_set(sources_target_name) {
+      visibility = target_visibility
+      if (defined(invoker.cython_sources)) {
+        cython_sources = invoker.cython_sources
+      }
+      if (defined(invoker.sources)) {
+        sources = invoker.sources
+      }
+      if (defined(invoker.configs)) {
+        configs = invoker.configs
+      }
+      if (defined(invoker.deps)) {
+        deps = invoker.deps
+      }
+      if (defined(invoker.datadeps)) {
+        datadeps = invoker.datadeps
+      }
     }
   }
 
   shared_library(shared_library_name) {
     visibility = target_visibility
-    deps = [
-      ":$sources_target_name",
-    ]
+    if (defined(invoker.configs)) {
+      configs += invoker.configs
+    }
+    deps = []
+    if (has_sources) {
+      deps += [ ":$sources_target_name" ]
+    }
     if (defined(invoker.deps)) {
       deps += invoker.deps
     }
     if (defined(invoker.datadeps)) {
       datadeps = invoker.datadeps
     }
-    if (defined(invoker.additional_sources)) {
-      sources = invoker.additional_sources
-    }
-    if (defined(invoker.configs)) {
-      configs += invoker.configs
-    }
   }
 
   copy(target_name) {
diff --git a/third_party/mesa/mesa.gyp b/third_party/mesa/mesa.gyp
index 056eb40..3db0d4c 100644
--- a/third_party/mesa/mesa.gyp
+++ b/third_party/mesa/mesa.gyp
@@ -132,6 +132,7 @@
       'variables': {
         'clang_warning_flags': [
           '-Wno-tautological-constant-out-of-range-compare',
+          '-Wno-mismatched-tags',  # Fixed upstream.
         ],
         'clang_warning_flags_unset': [
           # Don't warn about string->bool used in asserts.
@@ -269,6 +270,8 @@
       'variables': {
         'clang_warning_flags': [
           '-Wno-tautological-constant-out-of-range-compare',
+          '-Wno-absolute-value',  # Fires on st_atom_array.c, might be a bug
+          '-Wno-mismatched-tags',  # Fixed upstream.
         ],
         'clang_warning_flags_unset': [
           # Don't warn about string->bool used in asserts.
diff --git a/tools/clang/blink_gc_plugin/CMakeLists.txt b/tools/clang/blink_gc_plugin/CMakeLists.txt
index 85ce4a9..c511edf 100644
--- a/tools/clang/blink_gc_plugin/CMakeLists.txt
+++ b/tools/clang/blink_gc_plugin/CMakeLists.txt
@@ -1,6 +1,6 @@
 # This line is read by update.sh and other scripts in tools/clang/scripts
 # Note: The spaces are significant.
-set(LIBRARYNAME BlinkGCPlugin_12)
+set(LIBRARYNAME BlinkGCPlugin_14)
 
 add_llvm_loadable_module("lib${LIBRARYNAME}"
                          BlinkGCPlugin.cpp
diff --git a/tools/clang/plugins/tests/overridden_methods.txt b/tools/clang/plugins/tests/overridden_methods.txt
index 199876b..3ee0333 100644
--- a/tools/clang/plugins/tests/overridden_methods.txt
+++ b/tools/clang/plugins/tests/overridden_methods.txt
@@ -11,14 +11,14 @@
   virtual void SomeConstMethod() const {}
                                       ^
                                        override
-./overridden_methods.h:58:53: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
+./overridden_methods.h:58:55: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
   virtual void SomeMethodWithExceptionSpec() throw() {}
-                                                    ^
-                                                     override
-./overridden_methods.h:61:67: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
+                                                      ^
+                                                       override
+./overridden_methods.h:61:69: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
   virtual void SomeConstMethodWithExceptionSpec() const throw(int) {}
-                                                                  ^
-                                                                   override
+                                                                    ^
+                                                                     override
 ./overridden_methods.h:63:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
   virtual void SomeNonPureBaseMethod() {}
                                       ^
@@ -43,14 +43,14 @@
   virtual void SomeConstMethod() const {}
                                       ^
                                        override
-overridden_methods.cpp:34:53: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
+overridden_methods.cpp:34:55: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
   virtual void SomeMethodWithExceptionSpec() throw() {}
-                                                    ^
-                                                     override
-overridden_methods.cpp:37:67: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
+                                                      ^
+                                                       override
+overridden_methods.cpp:37:69: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
   virtual void SomeConstMethodWithExceptionSpec() const throw(int) {}
-                                                                  ^
-                                                                   override
+                                                                    ^
+                                                                     override
 overridden_methods.cpp:39:39: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
   virtual void SomeNonPureBaseMethod() {}
                                       ^
diff --git a/tools/clang/plugins/tests/test.sh b/tools/clang/plugins/tests/test.sh
index 9f63f7a..63aa872 100755
--- a/tools/clang/plugins/tests/test.sh
+++ b/tools/clang/plugins/tests/test.sh
@@ -34,6 +34,7 @@
   fi
 
   local output="$("${CLANG_PATH}" -fsyntax-only -Wno-c++11-extensions \
+      -Wno-inconsistent-missing-override \
       -Xclang -load -Xclang "${PLUGIN_PATH}" \
       -Xclang -add-plugin -Xclang find-bad-constructs ${flags} ${1} 2>&1)"
   local diffout="$(echo "${output}" | diff - "${2}")"
diff --git a/tools/clang/scripts/package.sh b/tools/clang/scripts/package.sh
index f00abb4..e0c0fcc 100755
--- a/tools/clang/scripts/package.sh
+++ b/tools/clang/scripts/package.sh
@@ -87,7 +87,7 @@
     ${extra_flags} 2>&1 | tee -a buildlog.txt
 
 R=$("${LLVM_BIN_DIR}/clang" --version | \
-     sed -ne 's/clang version .*(\([0-9]*\))/\1/p')
+     sed -ne 's/clang version .*(trunk \([0-9]*\))/\1/p')
 
 PDIR=clang-$R
 rm -rf $PDIR
diff --git a/tools/clang/scripts/repackage.sh b/tools/clang/scripts/repackage.sh
index c92447a..e19ab7e 100755
--- a/tools/clang/scripts/repackage.sh
+++ b/tools/clang/scripts/repackage.sh
@@ -30,7 +30,7 @@
 "$THIS_DIR"/package.sh $@
 
 R=$("${LLVM_BIN_DIR}/clang" --version | \
-     sed -ne 's/clang version .*(\([0-9]*\))/\1/p')
+     sed -ne 's/clang version .*(trunk \([0-9]*\))/\1/p')
 PDIR=clang-$R
 
 if [ ! -f "$PDIR.tgz" ]; then
diff --git a/tools/clang/scripts/update.sh b/tools/clang/scripts/update.sh
index ad534ad..b585440 100755
--- a/tools/clang/scripts/update.sh
+++ b/tools/clang/scripts/update.sh
@@ -8,7 +8,7 @@
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://code.google.com/p/chromium/wiki/UpdatingClang
 # Reverting problematic clang rolls is safe, though.
-CLANG_REVISION=218707
+CLANG_REVISION=223109
 
 THIS_DIR="$(dirname "${0}")"
 LLVM_DIR="${THIS_DIR}/../../../third_party/llvm"
@@ -238,8 +238,15 @@
       "${LLVM_DIR}/test/DebugInfo/gmlt.ll" \
       "${LLVM_DIR}/lib/CodeGen/SpillPlacement.cpp" \
       "${LLVM_DIR}/lib/CodeGen/SpillPlacement.h" \
+      "${LLVM_DIR}/lib/Transforms/Instrumentation/MemorySanitizer.cpp" \
+      "${CLANG_DIR}/test/Driver/env.c" \
+      "${CLANG_DIR}/lib/Frontend/InitPreprocessor.cpp" \
+      "${CLANG_DIR}/test/Frontend/exceptions.c" \
+      "${CLANG_DIR}/test/Preprocessor/predefined-exceptions.m" \
+      "${LLVM_DIR}/test/Bindings/Go/go.test" \
       ; do
   if [[ -e "${i}" ]]; then
+    rm -f "${i}"  # For unversioned files.
     svn revert "${i}"
   fi;
 done
@@ -317,179 +324,143 @@
 patch -p0
 popd
 
-# Apply r218742: test: XFAIL the non-darwin gmlt test on darwin
-# Back-ported becase the test was renamed.
+# Apply r223211: "Revert r222997."
 pushd "${LLVM_DIR}"
 cat << 'EOF' |
---- a/test/DebugInfo/gmlt.ll
-+++ b/test/DebugInfo/gmlt.ll
-@@ -1,2 +1,5 @@
- ; REQUIRES: object-emission
- ; RUN: %llc_dwarf -O0 -filetype=obj < %S/Inputs/gmlt.ll | llvm-dwarfdump - | FileCheck %S/Inputs/gmlt.ll
-+
-+; There's a darwin specific test in X86/gmlt, so it's okay to XFAIL this here.
-+; XFAIL: darwin
+--- a/lib/Transforms/Instrumentation/MemorySanitizer.cpp
++++ b/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+@@ -921,8 +921,6 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
+             Value *OriginPtr =
+                 getOriginPtrForArgument(&FArg, EntryIRB, ArgOffset);
+             setOrigin(A, EntryIRB.CreateLoad(OriginPtr));
+-          } else {
+-            setOrigin(A, getCleanOrigin());
+           }
+         }
+         ArgOffset += RoundUpToAlignment(Size, kShadowTLSAlignment);
+@@ -942,13 +940,15 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
+   /// \brief Get the origin for a value.
+   Value *getOrigin(Value *V) {
+     if (!MS.TrackOrigins) return nullptr;
+-    if (!PropagateShadow) return getCleanOrigin();
+-    if (isa<Constant>(V)) return getCleanOrigin();
+-    assert((isa<Instruction>(V) || isa<Argument>(V)) &&
+-           "Unexpected value type in getOrigin()");
+-    Value *Origin = OriginMap[V];
+-    assert(Origin && "Missing origin");
+-    return Origin;
++    if (isa<Instruction>(V) || isa<Argument>(V)) {
++      Value *Origin = OriginMap[V];
++      if (!Origin) {
++        DEBUG(dbgs() << "NO ORIGIN: " << *V << "\n");
++        Origin = getCleanOrigin();
++      }
++      return Origin;
++    }
++    return getCleanOrigin();
+   }
+ 
+   /// \brief Get the origin for i-th argument of the instruction I.
+@@ -1088,7 +1088,6 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
+     IRB.CreateStore(getCleanShadow(&I), ShadowPtr);
+ 
+     setShadow(&I, getCleanShadow(&I));
+-    setOrigin(&I, getCleanOrigin());
+   }
+ 
+   void visitAtomicRMWInst(AtomicRMWInst &I) {
 EOF
 patch -p1
 popd
 
-# Apply r218921; fixes spill placement compile-time regression.
-pushd "${LLVM_DIR}"
+# Apply r223219: "Preserve LD_LIBRARY_PATH when using the 'env' command"
+pushd "${CLANG_DIR}"
 cat << 'EOF' |
---- a/lib/CodeGen/SpillPlacement.cpp
-+++ b/lib/CodeGen/SpillPlacement.cpp
-@@ -61,27 +61,6 @@ void SpillPlacement::getAnalysisUsage(AnalysisUsage &AU) const {
-   MachineFunctionPass::getAnalysisUsage(AU);
- }
- 
--namespace {
--static ManagedStatic<BlockFrequency> Threshold;
--}
--
--/// Decision threshold. A node gets the output value 0 if the weighted sum of
--/// its inputs falls in the open interval (-Threshold;Threshold).
--static BlockFrequency getThreshold() { return *Threshold; }
--
--/// \brief Set the threshold for a given entry frequency.
--///
--/// Set the threshold relative to \c Entry.  Since the threshold is used as a
--/// bound on the open interval (-Threshold;Threshold), 1 is the minimum
--/// threshold.
--static void setThreshold(const BlockFrequency &Entry) {
--  // Apparently 2 is a good threshold when Entry==2^14, but we need to scale
--  // it.  Divide by 2^13, rounding as appropriate.
--  uint64_t Freq = Entry.getFrequency();
--  uint64_t Scaled = (Freq >> 13) + bool(Freq & (1 << 12));
--  *Threshold = std::max(UINT64_C(1), Scaled);
--}
--
- /// Node - Each edge bundle corresponds to a Hopfield node.
- ///
- /// The node contains precomputed frequency data that only depends on the CFG,
-@@ -127,9 +106,9 @@ struct SpillPlacement::Node {
- 
-   /// clear - Reset per-query data, but preserve frequencies that only depend on
-   // the CFG.
--  void clear() {
-+  void clear(const BlockFrequency &Threshold) {
-     BiasN = BiasP = Value = 0;
--    SumLinkWeights = getThreshold();
-+    SumLinkWeights = Threshold;
-     Links.clear();
-   }
- 
-@@ -167,7 +146,7 @@ struct SpillPlacement::Node {
- 
-   /// update - Recompute Value from Bias and Links. Return true when node
-   /// preference changes.
--  bool update(const Node nodes[]) {
-+  bool update(const Node nodes[], const BlockFrequency &Threshold) {
-     // Compute the weighted sum of inputs.
-     BlockFrequency SumN = BiasN;
-     BlockFrequency SumP = BiasP;
-@@ -187,9 +166,9 @@ struct SpillPlacement::Node {
-     //  2. It helps tame rounding errors when the links nominally sum to 0.
-     //
-     bool Before = preferReg();
--    if (SumN >= SumP + getThreshold())
-+    if (SumN >= SumP + Threshold)
-       Value = -1;
--    else if (SumP >= SumN + getThreshold())
-+    else if (SumP >= SumN + Threshold)
-       Value = 1;
-     else
-       Value = 0;
-@@ -228,7 +207,7 @@ void SpillPlacement::activate(unsigned n) {
-   if (ActiveNodes->test(n))
-     return;
-   ActiveNodes->set(n);
--  nodes[n].clear();
-+  nodes[n].clear(Threshold);
- 
-   // Very large bundles usually come from big switches, indirect branches,
-   // landing pads, or loops with many 'continue' statements. It is difficult to
-@@ -245,6 +224,18 @@ void SpillPlacement::activate(unsigned n) {
-   }
- }
- 
-+/// \brief Set the threshold for a given entry frequency.
-+///
-+/// Set the threshold relative to \c Entry.  Since the threshold is used as a
-+/// bound on the open interval (-Threshold;Threshold), 1 is the minimum
-+/// threshold.
-+void SpillPlacement::setThreshold(const BlockFrequency &Entry) {
-+  // Apparently 2 is a good threshold when Entry==2^14, but we need to scale
-+  // it.  Divide by 2^13, rounding as appropriate.
-+  uint64_t Freq = Entry.getFrequency();
-+  uint64_t Scaled = (Freq >> 13) + bool(Freq & (1 << 12));
-+  Threshold = std::max(UINT64_C(1), Scaled);
-+}
- 
- /// addConstraints - Compute node biases and weights from a set of constraints.
- /// Set a bit in NodeMask for each active node.
-@@ -311,7 +302,7 @@ bool SpillPlacement::scanActiveBundles() {
-   Linked.clear();
-   RecentPositive.clear();
-   for (int n = ActiveNodes->find_first(); n>=0; n = ActiveNodes->find_next(n)) {
--    nodes[n].update(nodes);
-+    nodes[n].update(nodes, Threshold);
-     // A node that must spill, or a node without any links is not going to
-     // change its value ever again, so exclude it from iterations.
-     if (nodes[n].mustSpill())
-@@ -331,7 +322,7 @@ void SpillPlacement::iterate() {
-   // First update the recently positive nodes. They have likely received new
-   // negative bias that will turn them off.
-   while (!RecentPositive.empty())
--    nodes[RecentPositive.pop_back_val()].update(nodes);
-+    nodes[RecentPositive.pop_back_val()].update(nodes, Threshold);
- 
-   if (Linked.empty())
-     return;
-@@ -350,7 +341,7 @@ void SpillPlacement::iterate() {
-            iteration == 0 ? Linked.rbegin() : std::next(Linked.rbegin()),
-            E = Linked.rend(); I != E; ++I) {
-       unsigned n = *I;
--      if (nodes[n].update(nodes)) {
-+      if (nodes[n].update(nodes, Threshold)) {
-         Changed = true;
-         if (nodes[n].preferReg())
-           RecentPositive.push_back(n);
-@@ -364,7 +355,7 @@ void SpillPlacement::iterate() {
-     for (SmallVectorImpl<unsigned>::const_iterator I =
-            std::next(Linked.begin()), E = Linked.end(); I != E; ++I) {
-       unsigned n = *I;
--      if (nodes[n].update(nodes)) {
-+      if (nodes[n].update(nodes, Threshold)) {
-         Changed = true;
-         if (nodes[n].preferReg())
-           RecentPositive.push_back(n);
-diff --git a/lib/CodeGen/SpillPlacement.h b/lib/CodeGen/SpillPlacement.h
-index 03cf5cd..622361e 100644
---- a/lib/CodeGen/SpillPlacement.h
-+++ b/lib/CodeGen/SpillPlacement.h
-@@ -62,6 +62,10 @@ class SpillPlacement : public MachineFunctionPass {
-   // Block frequencies are computed once. Indexed by block number.
-   SmallVector<BlockFrequency, 8> BlockFrequencies;
- 
-+  /// Decision threshold. A node gets the output value 0 if the weighted sum of
-+  /// its inputs falls in the open interval (-Threshold;Threshold).
-+  BlockFrequency Threshold;
-+
- public:
-   static char ID; // Pass identification, replacement for typeid.
- 
-@@ -152,6 +156,7 @@ private:
-   void releaseMemory() override;
- 
-   void activate(unsigned);
-+  void setThreshold(const BlockFrequency &Entry);
- };
- 
- } // end namespace llvm
+--- a/test/Driver/env.c
++++ b/test/Driver/env.c
+@@ -5,12 +5,14 @@
+ // REQUIRES: shell
+ //
+ // The PATH variable is heavily used when trying to find a linker.
+-// RUN: env -i LC_ALL=C %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
++// RUN: env -i LC_ALL=C LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
++// RUN:   %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+ // RUN:     --target=i386-unknown-linux \
+ // RUN:     --sysroot=%S/Inputs/basic_linux_tree \
+ // RUN:   | FileCheck --check-prefix=CHECK-LD-32 %s
+ //
+-// RUN: env -i LC_ALL=C PATH="" %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
++// RUN: env -i LC_ALL=C PATH="" LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
++// RUN:   %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+ // RUN:     --target=i386-unknown-linux \
+ // RUN:     --sysroot=%S/Inputs/basic_linux_tree \
+ // RUN:   | FileCheck --check-prefix=CHECK-LD-32 %s
 EOF
 patch -p1
 popd
 
+# Revert r220714: "Frontend: Define __EXCEPTIONS if -fexceptions is passed"
+pushd "${CLANG_DIR}"
+cat << 'EOF' |
+--- a/lib/Frontend/InitPreprocessor.cpp
++++ b/lib/Frontend/InitPreprocessor.cpp
+@@ -566,7 +566,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
+     Builder.defineMacro("__BLOCKS__");
+   }
+ 
+-  if (!LangOpts.MSVCCompat && LangOpts.Exceptions)
++  if (!LangOpts.MSVCCompat && LangOpts.CXXExceptions)
+     Builder.defineMacro("__EXCEPTIONS");
+   if (!LangOpts.MSVCCompat && LangOpts.RTTI)
+     Builder.defineMacro("__GXX_RTTI");
+diff --git a/test/Frontend/exceptions.c b/test/Frontend/exceptions.c
+index 981b5b9..4bbaaa3 100644
+--- a/test/Frontend/exceptions.c
++++ b/test/Frontend/exceptions.c
+@@ -1,9 +1,6 @@
+-// RUN: %clang_cc1 -fms-compatibility -fexceptions -fcxx-exceptions -DMS_MODE -verify %s
++// RUN: %clang_cc1 -fms-compatibility -fexceptions -fcxx-exceptions -verify %s
+ // expected-no-diagnostics
+ 
+-// RUN: %clang_cc1 -fms-compatibility -fexceptions -verify %s
+-// expected-no-diagnostics
+-
+-#if defined(MS_MODE) && defined(__EXCEPTIONS)
++#if defined(__EXCEPTIONS)
+ #error __EXCEPTIONS should not be defined.
+ #endif
+diff --git a/test/Preprocessor/predefined-exceptions.m b/test/Preprocessor/predefined-exceptions.m
+index 0791075..c13f429 100644
+--- a/test/Preprocessor/predefined-exceptions.m
++++ b/test/Preprocessor/predefined-exceptions.m
+@@ -1,6 +1,6 @@
+ // RUN: %clang_cc1 -x objective-c -fobjc-exceptions -fexceptions -E -dM %s | FileCheck -check-prefix=CHECK-OBJC-NOCXX %s 
+ // CHECK-OBJC-NOCXX: #define OBJC_ZEROCOST_EXCEPTIONS 1
+-// CHECK-OBJC-NOCXX: #define __EXCEPTIONS 1
++// CHECK-OBJC-NOCXX-NOT: #define __EXCEPTIONS 1
+ 
+ // RUN: %clang_cc1 -x objective-c++ -fobjc-exceptions -fexceptions -fcxx-exceptions -E -dM %s | FileCheck -check-prefix=CHECK-OBJC-CXX %s 
+ // CHECK-OBJC-CXX: #define OBJC_ZEROCOST_EXCEPTIONS 1
+EOF
+patch -p1
+popd
+
+# This Go bindings test doesn't work after the bootstrap build on Linux. (PR21552)
+pushd "${LLVM_DIR}"
+cat << 'EOF' |
+Index: test/Bindings/Go/go.test
+===================================================================
+--- test/Bindings/Go/go.test    (revision 223109)
++++ test/Bindings/Go/go.test    (working copy)
+@@ -1,3 +1,3 @@
+-; RUN: llvm-go test llvm.org/llvm/bindings/go/llvm
++; RUN: true
+ 
+ ; REQUIRES: shell
+EOF
+patch -p0
+popd
+
 
 # Echo all commands.
 set -x
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index 677cb63..e43c605 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -362,9 +362,6 @@
   def TestExtensions(self):
     return self.SimpleTest("extensions", "extensions_unittests")
 
-  def TestFFmpeg(self):
-    return self.SimpleTest("chrome", "ffmpeg_unittests")
-
   def TestFFmpegRegressions(self):
     return self.SimpleTest("chrome", "ffmpeg_regression_tests")
 
@@ -678,7 +675,6 @@
     "display": TestDisplay,      "display_unittests": TestDisplay,
     "events": TestEvents,        "events_unittests": TestEvents,
     "extensions": TestExtensions, "extensions_unittests": TestExtensions,
-    "ffmpeg": TestFFmpeg,        "ffmpeg_unittests": TestFFmpeg,
     "ffmpeg_regression_tests": TestFFmpegRegressions,
     "gcm": TestGCM,              "gcm_unit_tests": TestGCM,
     "gin": TestGin,              "gin_unittests": TestGin,
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index 4310d8a..4a6b5a9 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -669,3 +669,15 @@
 content.dll!content::RenderFrameProxy::OnDeleteProxy
 content.dll!content::RenderFrameProxy::OnMessageReceived
 content.dll!content::MessageRouter::RouteMessage
+
+HANDLE LEAK
+name=http://crbug.com/441785
+system call NtCreateSection
+*!CreateFileMappingW
+*!base::SharedMemory::Create
+*!base::SharedMemory::CreateAnonymous
+*!content::ChildThread::AllocateSharedMemory
+*!content::ChildSharedBitmapManager::AllocateSharedMemoryBitmap
+*!content::ChildSharedBitmapManager::AllocateSharedBitmap
+*!cc::ResourceProvider::CreateBitmap
+*!cc::ResourceProvider::Create*Resource
diff --git a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt
index 14cbe8b..3fd0cf4 100644
--- a/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt
+++ b/tools/valgrind/gtest_exclude/content_browsertests.gtest-drmemory_win32.txt
@@ -17,6 +17,7 @@
 RenderViewImplTest.ReloadWhileSwappedOut
 RenderViewImplTest.SendSwapOutACK
 RenderViewImplTest.StaleNavigationsIgnored
+RenderFrameHostManagerTest.RestoreFileAccessForHistoryNavigation
 ResourceFetcherTests.ResourceFetcher404
 ResourceFetcherTests.ResourceFetcherDidFail
 ResourceFetcherTests.ResourceFetcherDownload
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 3f1ea1b..ad58793 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -3533,3 +3533,11 @@
    ...
    fun:_ZN3gpu22InProcessCommandBuffer21InitializeOnGpuThreadERKNS0_27InitializeOnGpuThreadParamsE
 }
+{
+   bug_441333
+   Memcheck:Uninitialized
+   fun:av_packet_unpack_dictionary
+   fun:add_metadata_from_side_data
+   fun:avcodec_decode_*
+   fun:avcodec_decode_*
+}
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 58297e6..7fd7fe9 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -108,7 +108,7 @@
       draw_on_compositing_end_(false),
       swap_state_(SWAP_NONE),
       layer_animator_collection_(this),
-      schedule_draw_factory_(this) {
+      weak_ptr_factory_(this) {
   root_web_layer_ = cc::Layer::Create();
 
   CommandLine* command_line = CommandLine::ForCurrentProcess();
@@ -210,10 +210,27 @@
     defer_draw_scheduling_ = true;
     task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&Compositor::Draw, schedule_draw_factory_.GetWeakPtr()));
+        base::Bind(&Compositor::Draw, weak_ptr_factory_.GetWeakPtr()));
   }
 }
 
+void Compositor::DidInitializeOutputSurface() {
+  num_failed_recreate_attempts_ = 0;
+}
+
+void Compositor::DidFailToInitializeOutputSurface() {
+  num_failed_recreate_attempts_++;
+
+  // Tolerate a certain number of recreation failures to work around races
+  // in the output-surface-lost machinery.
+  if (num_failed_recreate_attempts_ >= MAX_OUTPUT_SURFACE_RETRIES)
+    LOG(FATAL) << "Failed to create a fallback OutputSurface.";
+
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE, base::Bind(&Compositor::RequestNewOutputSurface,
+                            weak_ptr_factory_.GetWeakPtr()));
+}
+
 void Compositor::SetRootLayer(Layer* root_layer) {
   if (root_layer_ == root_layer)
     return;
@@ -367,9 +384,11 @@
   disable_schedule_composite_ = false;
 }
 
-void Compositor::RequestNewOutputSurface(bool fallback) {
-  host_->SetOutputSurface(
-      context_factory_->CreateOutputSurface(this, fallback));
+void Compositor::RequestNewOutputSurface() {
+  bool fallback =
+      num_failed_recreate_attempts_ >= OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK;
+  context_factory_->CreateOutputSurface(weak_ptr_factory_.GetWeakPtr().get(),
+                                        fallback);
 }
 
 void Compositor::DidCommit() {
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index a937886..d679551 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -73,7 +73,7 @@
       Compositor* compositor, bool software_fallback) = 0;
 
   // Creates a reflector that copies the content of the |mirrored_compositor|
-  // onto |mirroing_layer|.
+  // onto |mirroring_layer|.
   virtual scoped_refptr<Reflector> CreateReflector(
       Compositor* mirrored_compositor,
       Layer* mirroring_layer) = 0;
@@ -249,8 +249,9 @@
   void ApplyViewportDeltas(const gfx::Vector2d& scroll_delta,
                            float page_scale,
                            float top_controls_delta) override {}
-  void RequestNewOutputSurface(bool fallback) override;
-  void DidInitializeOutputSurface() override {}
+  void RequestNewOutputSurface() override;
+  void DidInitializeOutputSurface() override;
+  void DidFailToInitializeOutputSurface() override;
   void WillCommit() override {}
   void DidCommit() override;
   void DidCommitAndDrawFrame() override;
@@ -286,6 +287,10 @@
   friend class base::RefCounted<Compositor>;
   friend class CompositorLock;
 
+  enum {
+    OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK = 4,
+    MAX_OUTPUT_SURFACE_RETRIES = 5,
+  };
   // Called by CompositorLock.
   void UnlockCompositor();
 
@@ -323,6 +328,8 @@
   int last_started_frame_;
   int last_ended_frame_;
 
+  int num_failed_recreate_attempts_;
+
   bool disable_schedule_composite_;
 
   CompositorLock* compositor_lock_;
@@ -338,7 +345,7 @@
 
   LayerAnimatorCollection layer_animator_collection_;
 
-  base::WeakPtrFactory<Compositor> schedule_draw_factory_;
+  base::WeakPtrFactory<Compositor> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(Compositor);
 };
diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc
index e358069..4cfcf73 100644
--- a/ui/gl/gl_context.cc
+++ b/ui/gl/gl_context.cc
@@ -52,7 +52,10 @@
   return flag_.IsSet();
 }
 
-GLContext::GLContext(GLShareGroup* share_group) : share_group_(share_group) {
+GLContext::GLContext(GLShareGroup* share_group) :
+    share_group_(share_group),
+    swap_interval_(1),
+    force_swap_interval_zero_(false) {
   if (!share_group_.get())
     share_group_ = new GLShareGroup;
 
@@ -178,6 +181,16 @@
   state_restorer_ = make_scoped_ptr(state_restorer);
 }
 
+void GLContext::SetSwapInterval(int interval) {
+  swap_interval_ = interval;
+  OnSetSwapInterval(force_swap_interval_zero_ ? 0 : swap_interval_);
+}
+
+void GLContext::ForceSwapIntervalZero(bool force) {
+  force_swap_interval_zero_ = force;
+  OnSetSwapInterval(force_swap_interval_zero_ ? 0 : swap_interval_);
+}
+
 bool GLContext::WasAllocatedUsingRobustnessExtension() {
   return false;
 }
diff --git a/ui/gl/gl_context.h b/ui/gl/gl_context.h
index cdebd68..62cabcd 100644
--- a/ui/gl/gl_context.h
+++ b/ui/gl/gl_context.h
@@ -76,7 +76,11 @@
   void SetGLStateRestorer(GLStateRestorer* state_restorer);
 
   // Set swap interval. This context must be current.
-  virtual void SetSwapInterval(int interval) = 0;
+  void SetSwapInterval(int interval);
+
+  // Forces the swap interval to zero (no vsync) regardless of any future values
+  // passed to SetSwapInterval.
+  void ForceSwapIntervalZero(bool force);
 
   // Returns space separated list of extensions. The context must be current.
   virtual std::string GetExtensions();
@@ -169,6 +173,8 @@
   // Returns the last real (non-virtual) GLContext made current.
   static GLContext* GetRealCurrent();
 
+  virtual void OnSetSwapInterval(int interval) = 0;
+
  private:
   friend class base::RefCounted<GLContext>;
 
@@ -182,6 +188,9 @@
 
   std::vector<scoped_refptr<FlushEvent> > flush_events_;
 
+  int swap_interval_;
+  bool force_swap_interval_zero_;
+
   DISALLOW_COPY_AND_ASSIGN(GLContext);
 };
 
diff --git a/ui/gl/gl_context_android.cc b/ui/gl/gl_context_android.cc
index 7f9cf2d..76b9238 100644
--- a/ui/gl/gl_context_android.cc
+++ b/ui/gl/gl_context_android.cc
@@ -33,7 +33,7 @@
   virtual void ReleaseCurrent(GLSurface* surface) override {}
   virtual bool IsCurrent(GLSurface* surface) override { return true; }
   virtual void* GetHandle() override { return NULL; }
-  virtual void SetSwapInterval(int interval) override {}
+  virtual void OnSetSwapInterval(int interval) override {}
   virtual std::string GetExtensions() override;
 
  protected:
diff --git a/ui/gl/gl_context_cgl.cc b/ui/gl/gl_context_cgl.cc
index 277780a..723e97e 100644
--- a/ui/gl/gl_context_cgl.cc
+++ b/ui/gl/gl_context_cgl.cc
@@ -238,7 +238,7 @@
   return context_;
 }
 
-void GLContextCGL::SetSwapInterval(int interval) {
+void GLContextCGL::OnSetSwapInterval(int interval) {
   DCHECK(IsCurrent(NULL));
 }
 
diff --git a/ui/gl/gl_context_cgl.h b/ui/gl/gl_context_cgl.h
index 456ea08..88813b3 100644
--- a/ui/gl/gl_context_cgl.h
+++ b/ui/gl/gl_context_cgl.h
@@ -26,7 +26,7 @@
   void ReleaseCurrent(GLSurface* surface) override;
   bool IsCurrent(GLSurface* surface) override;
   void* GetHandle() override;
-  void SetSwapInterval(int interval) override;
+  void OnSetSwapInterval(int interval) override;
   bool GetTotalGpuMemory(size_t* bytes) override;
   void SetSafeToForceGpuSwitch() override;
   bool ForceGpuSwitchIfNeeded() override;
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc
index 733ad8d..5dd1aaf 100644
--- a/ui/gl/gl_context_egl.cc
+++ b/ui/gl/gl_context_egl.cc
@@ -172,7 +172,7 @@
   return context_;
 }
 
-void GLContextEGL::SetSwapInterval(int interval) {
+void GLContextEGL::OnSetSwapInterval(int interval) {
   DCHECK(IsCurrent(NULL) && GLSurface::GetCurrent());
 
   // This is a surfaceless context. eglSwapInterval doesn't take any effect in
diff --git a/ui/gl/gl_context_egl.h b/ui/gl/gl_context_egl.h
index 9f071e2..99a4481 100644
--- a/ui/gl/gl_context_egl.h
+++ b/ui/gl/gl_context_egl.h
@@ -31,7 +31,7 @@
   void ReleaseCurrent(GLSurface* surface) override;
   bool IsCurrent(GLSurface* surface) override;
   void* GetHandle() override;
-  void SetSwapInterval(int interval) override;
+  void OnSetSwapInterval(int interval) override;
   std::string GetExtensions() override;
   bool WasAllocatedUsingRobustnessExtension() override;
   bool GetTotalGpuMemory(size_t* bytes) override;
diff --git a/ui/gl/gl_context_glx.cc b/ui/gl/gl_context_glx.cc
index 9b6cfb4..a16daf3 100644
--- a/ui/gl/gl_context_glx.cc
+++ b/ui/gl/gl_context_glx.cc
@@ -163,7 +163,7 @@
   return context_;
 }
 
-void GLContextGLX::SetSwapInterval(int interval) {
+void GLContextGLX::OnSetSwapInterval(int interval) {
   DCHECK(IsCurrent(NULL));
   if (HasExtension("GLX_EXT_swap_control") &&
       g_driver_glx.fn.glXSwapIntervalEXTFn) {
diff --git a/ui/gl/gl_context_glx.h b/ui/gl/gl_context_glx.h
index fe3d754..6973542 100644
--- a/ui/gl/gl_context_glx.h
+++ b/ui/gl/gl_context_glx.h
@@ -31,7 +31,7 @@
   void ReleaseCurrent(GLSurface* surface) override;
   bool IsCurrent(GLSurface* surface) override;
   void* GetHandle() override;
-  void SetSwapInterval(int interval) override;
+  void OnSetSwapInterval(int interval) override;
   std::string GetExtensions() override;
   bool GetTotalGpuMemory(size_t* bytes) override;
   bool WasAllocatedUsingRobustnessExtension() override;
diff --git a/ui/gl/gl_context_osmesa.cc b/ui/gl/gl_context_osmesa.cc
index 524fe42..d41a493 100644
--- a/ui/gl/gl_context_osmesa.cc
+++ b/ui/gl/gl_context_osmesa.cc
@@ -123,7 +123,7 @@
   return context_;
 }
 
-void GLContextOSMesa::SetSwapInterval(int interval) {
+void GLContextOSMesa::OnSetSwapInterval(int interval) {
   DCHECK(IsCurrent(NULL));
 }
 
diff --git a/ui/gl/gl_context_osmesa.h b/ui/gl/gl_context_osmesa.h
index 0ae32db..9ce37d7 100644
--- a/ui/gl/gl_context_osmesa.h
+++ b/ui/gl/gl_context_osmesa.h
@@ -29,7 +29,7 @@
   void ReleaseCurrent(GLSurface* surface) override;
   bool IsCurrent(GLSurface* surface) override;
   void* GetHandle() override;
-  void SetSwapInterval(int interval) override;
+  void OnSetSwapInterval(int interval) override;
 
  protected:
   ~GLContextOSMesa() override;
diff --git a/ui/gl/gl_context_stub.cc b/ui/gl/gl_context_stub.cc
index faf957b..ff3a85d 100644
--- a/ui/gl/gl_context_stub.cc
+++ b/ui/gl/gl_context_stub.cc
@@ -33,7 +33,7 @@
   return NULL;
 }
 
-void GLContextStub::SetSwapInterval(int interval) {
+void GLContextStub::OnSetSwapInterval(int interval) {
 }
 
 std::string GLContextStub::GetExtensions() {
diff --git a/ui/gl/gl_context_stub.h b/ui/gl/gl_context_stub.h
index 1a7eb24..b4eef93 100644
--- a/ui/gl/gl_context_stub.h
+++ b/ui/gl/gl_context_stub.h
@@ -22,7 +22,7 @@
   void ReleaseCurrent(GLSurface* surface) override;
   bool IsCurrent(GLSurface* surface) override;
   void* GetHandle() override;
-  void SetSwapInterval(int interval) override;
+  void OnSetSwapInterval(int interval) override;
   std::string GetExtensions() override;
   std::string GetGLRenderer() override;
 
diff --git a/ui/gl/gl_context_wgl.cc b/ui/gl/gl_context_wgl.cc
index abe47e4..2f34cd3 100644
--- a/ui/gl/gl_context_wgl.cc
+++ b/ui/gl/gl_context_wgl.cc
@@ -131,7 +131,7 @@
   return context_;
 }
 
-void GLContextWGL::SetSwapInterval(int interval) {
+void GLContextWGL::OnSetSwapInterval(int interval) {
   DCHECK(IsCurrent(NULL));
   if (gfx::g_driver_wgl.ext.b_WGL_EXT_swap_control) {
     wglSwapIntervalEXT(interval);
diff --git a/ui/gl/gl_context_wgl.h b/ui/gl/gl_context_wgl.h
index 13a274b..d97e568 100644
--- a/ui/gl/gl_context_wgl.h
+++ b/ui/gl/gl_context_wgl.h
@@ -28,7 +28,7 @@
   virtual void ReleaseCurrent(GLSurface* surface);
   virtual bool IsCurrent(GLSurface* surface);
   virtual void* GetHandle();
-  virtual void SetSwapInterval(int interval);
+  virtual void OnSetSwapInterval(int interval);
   virtual std::string GetExtensions();
 
  private:
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index 00e224d..1d5598e 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -200,6 +200,9 @@
   return true;
 }
 
+void GLSurface::NotifyWasBound() {
+}
+
 bool GLSurface::SetBackbufferAllocation(bool allocated) {
   return true;
 }
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 1351638..c218267 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -88,6 +88,10 @@
   // on error.
   virtual bool OnMakeCurrent(GLContext* context);
 
+  // Called when the surface is bound as the current framebuffer for the
+  // current context.
+  virtual void NotifyWasBound();
+
   // Used for explicit buffer management.
   virtual bool SetBackbufferAllocation(bool allocated);
   virtual void SetFrontbufferAllocation(bool allocated);
diff --git a/ui/gl/gl_switches.cc b/ui/gl/gl_switches.cc
index 936daf6..479ff69 100644
--- a/ui/gl/gl_switches.cc
+++ b/ui/gl/gl_switches.cc
@@ -58,10 +58,6 @@
 // On Windows only: use the WARP software rasterizer in the GPU process.
 const char kUseWarp[] = "use-warp";
 
-// Include ANGLE's intermediate representation (AST) output in shader
-// compilation info logs.
-const char kGLShaderIntermOutput[] = "gl-shader-interm-output";
-
 // Disables GL drawing operations which produce pixel output. With this
 // the GL output will not be correct but tests will run faster.
 const char kDisableGLDrawingForTests[] = "disable-gl-drawing-for-tests";
@@ -82,7 +78,6 @@
   kDisableGLDrawingForTests,
   kOverrideUseGLWithOSMesaForTests,
   kUseWarp,
-  kGLShaderIntermOutput
 };
 const int kGLSwitchesCopiedFromGpuProcessHostNumSwitches =
     arraysize(kGLSwitchesCopiedFromGpuProcessHost);
diff --git a/ui/gl/gl_switches.h b/ui/gl/gl_switches.h
index 115ee36..ce27df0 100644
--- a/ui/gl/gl_switches.h
+++ b/ui/gl/gl_switches.h
@@ -37,8 +37,6 @@
 GL_EXPORT extern const char kUseGpuInTests[];
 GL_EXPORT extern const char kUseWarp[];
 
-GL_EXPORT extern const char kGLShaderIntermOutput[];
-
 // These flags are used by the test harness code, not passed in by users.
 GL_EXPORT extern const char kDisableGLDrawingForTests[];
 GL_EXPORT extern const char kOverrideUseGLWithOSMesaForTests[];