Import Cobalt 12.81256
diff --git a/src/base/base.gyp b/src/base/base.gyp
index e7e004c..d9c7764 100644
--- a/src/base/base.gyp
+++ b/src/base/base.gyp
@@ -325,7 +325,10 @@
         },
       ],
       'msvs_disabled_warnings': [
-        4800,  # forcing value to bool 'true' or 'false' (performance warning)
+        # forcing value to bool 'true' or 'false' (performance warning)
+        4800,
+        # Destructor is explicitly deleted.
+        4624,
       ],
     },
     {
diff --git a/src/base/base.gypi b/src/base/base.gypi
index 8f39243..dc08b0c 100644
--- a/src/base/base.gypi
+++ b/src/base/base.gypi
@@ -329,9 +329,6 @@
         'include_dirs': [
           '<(DEPTH)',
         ],
-        'msvs_disabled_warnings': [
-          4018,
-        ],
       }],
     ],
   },
diff --git a/src/base/file_path_unittest.cc b/src/base/file_path_unittest.cc
index b61d5d2..42f1dcb 100644
--- a/src/base/file_path_unittest.cc
+++ b/src/base/file_path_unittest.cc
@@ -1110,7 +1110,7 @@
 TEST_F(FilePathTest, FromUTF8Unsafe_And_AsUTF8Unsafe) {
   const struct UTF8TestData cases[] = {
     { FPL("foo.txt"), "foo.txt" },
-#if !defined(__LB_SHELL__)
+#if !defined(STARBOARD)
     // "aeo" with accents. Use http://0xcc.net/jsescape/ to decode them.
     { FPL("\u00E0\u00E8\u00F2.txt"), "\xC3\xA0\xC3\xA8\xC3\xB2.txt" },
     // Full-width "ABC".
diff --git a/src/base/observer_list_unittest.cc b/src/base/observer_list_unittest.cc
index baa8f3a..7e16b47 100644
--- a/src/base/observer_list_unittest.cc
+++ b/src/base/observer_list_unittest.cc
@@ -122,7 +122,7 @@
     //LOG(ERROR) << "Loop 0x" << std::hex << loop_ << " done. " <<
     //    count_observes_ << ", " << count_addtask_;
     delete loop_;
-    loop_ = reinterpret_cast<MessageLoop*>(0xdeadbeef);
+    loop_ = reinterpret_cast<MessageLoop*>(static_cast<size_t>(0xdeadbeef));
     delete this;
   }
 
diff --git a/src/base/string_number_conversions_unittest.cc b/src/base/string_number_conversions_unittest.cc
index 0bb33b5..cec6c7c 100644
--- a/src/base/string_number_conversions_unittest.cc
+++ b/src/base/string_number_conversions_unittest.cc
@@ -36,8 +36,9 @@
 #define DEFINE_INTEGRAL_TO_STRING_TEST(Name, CppType)                         \
   {                                                                           \
     static const CppType kValuesToTest[] = {                                  \
-        0, static_cast<CppType>(-1), 42, std::numeric_limits<CppType>::min(), \
-        std::numeric_limits<CppType>::max()};                                 \
+        0, 1, 42,                                                             \
+        static_cast<CppType>(std::numeric_limits<CppType>::min()),            \
+        static_cast<CppType>(std::numeric_limits<CppType>::max())};           \
     for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValuesToTest); ++i) {            \
       CppType value = static_cast<CppType>(kValuesToTest[i]);                 \
       std::ostringstream oss;                                                 \
@@ -112,7 +113,7 @@
       {"blah42", 0},                                                         \
       {"42blah", 42},                                                        \
       {"blah42blah", 0},                                                     \
-      {"-73.15", -73},                                                       \
+      {"-73.15", static_cast<CppType>(-73)},                                                       \
       {"+98.6", 98},                                                         \
       {"--123", 0},                                                          \
       {"++123", 0},                                                          \
@@ -206,14 +207,14 @@
     {"7fffffff", INT_MAX, true},
     {"80000000", INT_MIN, true},
     {"ffffffff", -1, true},
-    {"DeadBeef", 0xdeadbeef, true},
+    {"DeadBeef", static_cast<int>(0xdeadbeef), true},
     {"0x42", 66, true},
     {"-0x42", -66, true},
     {"+0x42", 66, true},
     {"0x7fffffff", INT_MAX, true},
     {"0x80000000", INT_MIN, true},
     {"0xffffffff", -1, true},
-    {"0XDeadBeef", 0xdeadbeef, true},
+    {"0XDeadBeef", static_cast<int>(0xdeadbeef), true},
     {"0x0f", 15, true},
     {"0f", 15, true},
     {" 45", 0x45, false},
diff --git a/src/base/third_party/nspr/prcpucfg_starboard.h b/src/base/third_party/nspr/prcpucfg_starboard.h
index 2113b0f..f443065 100644
--- a/src/base/third_party/nspr/prcpucfg_starboard.h
+++ b/src/base/third_party/nspr/prcpucfg_starboard.h
@@ -97,11 +97,24 @@
 #define PR_BYTES_PER_DWORD_LOG2  3
 
 #elif SB_IS(ARCH_X86) && SB_IS(64_BIT)
+
+#if defined(_WIN32)
+// WIN32 defines long as 4 bytes.
+#define PR_BYTES_PER_LONG   4
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_ALIGN_OF_LONG    4
+#else
+#define PR_BYTES_PER_LONG   8
+#define PR_BITS_PER_LONG    64
+#define PR_BITS_PER_LONG_LOG2   6
+#define PR_ALIGN_OF_LONG    8
+#endif  // defined(_WIN32)
+
 #define PR_BYTES_PER_BYTE   1
 #define PR_BYTES_PER_SHORT  2
 #define PR_BYTES_PER_INT    4
 #define PR_BYTES_PER_INT64  8
-#define PR_BYTES_PER_LONG   8
 #define PR_BYTES_PER_FLOAT  4
 #define PR_BYTES_PER_DOUBLE 8
 #define PR_BYTES_PER_WORD   8
@@ -111,7 +124,6 @@
 #define PR_BITS_PER_SHORT   16
 #define PR_BITS_PER_INT     32
 #define PR_BITS_PER_INT64   64
-#define PR_BITS_PER_LONG    64
 #define PR_BITS_PER_FLOAT   32
 #define PR_BITS_PER_DOUBLE  64
 #define PR_BITS_PER_WORD    64
@@ -120,14 +132,12 @@
 #define PR_BITS_PER_SHORT_LOG2  4
 #define PR_BITS_PER_INT_LOG2    5
 #define PR_BITS_PER_INT64_LOG2  6
-#define PR_BITS_PER_LONG_LOG2   6
 #define PR_BITS_PER_FLOAT_LOG2  5
 #define PR_BITS_PER_DOUBLE_LOG2 6
 #define PR_BITS_PER_WORD_LOG2   6
 
 #define PR_ALIGN_OF_SHORT   2
 #define PR_ALIGN_OF_INT     4
-#define PR_ALIGN_OF_LONG    8
 #define PR_ALIGN_OF_INT64   8
 #define PR_ALIGN_OF_FLOAT   4
 #define PR_ALIGN_OF_DOUBLE  8
diff --git a/src/build/common.gypi b/src/build/common.gypi
index c72e66b..e41bd74 100644
--- a/src/build/common.gypi
+++ b/src/build/common.gypi
@@ -53,9 +53,6 @@
       # The system root for cross-compiles. Default: none.
       'sysroot%': '',
 
-      # Use libjpeg-turbo as the JPEG codec used by Chromium.
-      'use_libjpeg_turbo%': 1,
-
       # Use system libjpeg. Note that the system's libjepg will be used even if
       # use_libjpeg_turbo is set.
       'use_system_libjpeg%': 0,
@@ -120,17 +117,12 @@
     'tsan%': '<(tsan)',
     'clang_type_profiler%': '<(clang_type_profiler)',
     'order_profiling%': '<(order_profiling)',
-    'use_libjpeg_turbo%': '<(use_libjpeg_turbo)',
     'use_system_libjpeg%': '<(use_system_libjpeg)',
     'android_build_type%': '<(android_build_type)',
 
     # Use system protobuf instead of bundled one.
     'use_system_protobuf%': 0,
 
-    # Whether proprietary audio/video codecs are assumed to be included with
-    # this build (only meaningful if branding!=Chrome).
-    'proprietary_codecs%': 0,
-
     # TODO(sgk): eliminate this if possible.
     # It would be nicer to support this via a setting in 'target_defaults'
     # in chrome/app/locales/locales.gypi overriding the setting in the
@@ -229,8 +221,6 @@
         # to specify the output directory for Ant in the Android build.
         'ant_build_out': '`cd <(PRODUCT_DIR) && pwd -P`',
 
-        'proprietary_codecs%': '<(proprietary_codecs)',
-
         # Disable Native Client.
         'disable_nacl%': 1,
 
@@ -245,13 +235,6 @@
         'android_build_type%': '<(android_build_type)',
       }],  # target_arch=="android"
 
-      ['use_system_libjpeg==1 or use_libjpeg_turbo==0', {
-        # Configuration for using the system libjeg is here.
-        'libjpeg_gyp_path': '../third_party/libjpeg/libjpeg.gyp',
-      }, {
-        'libjpeg_gyp_path': '../third_party/libjpeg_turbo/libjpeg.gyp',
-      }],
-
       ['asan==1 and OS!="win"', {
         'clang%': 1,
       }],
@@ -399,9 +382,6 @@
       ['profiling==1', {
         'defines': ['ENABLE_PROFILING=1'],
       }],
-      ['proprietary_codecs==1', {
-        'defines': ['USE_PROPRIETARY_CODECS'],
-      }],
       ['dcheck_always_on!=0', {
         'defines': ['DCHECK_ALWAYS_ON=1'],
       }],  # dcheck_always_on!=0
diff --git a/src/build/filename_rules.gypi b/src/build/filename_rules.gypi
index 6ae44dc..13b4735 100644
--- a/src/build/filename_rules.gypi
+++ b/src/build/filename_rules.gypi
@@ -41,16 +41,6 @@
         ['exclude', '(^|/)android/'],
       ],
     }],
-    ['OS=="lb_shell"', {
-      'sources/': [
-        # Re-include things in media/audio and media/filters
-        ['include', 'audio/shell_.*<(target_arch)'],
-        ['include', 'filters/shell_.*<(target_arch)'],
-        # Re-include things in lbshell
-        ['include', 'lbshell/src/platform/<(target_arch)'],
-        ['include', 'lbshell/src/platform/<(actual_target_arch)'],
-      ],
-    }],
     ['(OS=="win" and >(nacl_untrusted_build)==0) or OS=="lb_shell" or OS=="starboard"', {
       'sources/': [
         ['exclude', '_posix(_unittest)?\\.(h|cc)$'],
diff --git a/src/cobalt/CHANGELOG.md b/src/cobalt/CHANGELOG.md
index 57b1de8..1cbd099 100644
--- a/src/cobalt/CHANGELOG.md
+++ b/src/cobalt/CHANGELOG.md
@@ -49,7 +49,9 @@
 
    Cobalt now supports the page visibility API, and will signal visibility and
    focus changes to the web app as the process transitions between Starboard
-   lifecycle states.
+   lifecycle states. See the
+   new [Application Lifecycle Integration](doc/lifecycle.md) document for more
+   details.
 
  - **Opus Support**
 
@@ -81,4 +83,10 @@
 
    Decode targets with the format `kSbDecodeTargetFormat1PlaneUYVY` will now
    be rendered by Cobalt.  This will allow decoders that produce YUV 422 UYVY
-   video frames to now efficiently support 360 video.
\ No newline at end of file
+   video frames to now efficiently support 360 video.
+
+ - **Preload Support**
+
+   Support for preloading an application with no graphics resources. See the
+   new [Application Lifecycle Integration](doc/lifecycle.md) guide for more
+   details.
diff --git a/src/cobalt/audio/audio_node_input_output_test.cc b/src/cobalt/audio/audio_node_input_output_test.cc
index 8a69ac3..d167bd9 100644
--- a/src/cobalt/audio/audio_node_input_output_test.cc
+++ b/src/cobalt/audio/audio_node_input_output_test.cc
@@ -39,6 +39,8 @@
  public:
   explicit AudioDestinationNodeMock(AudioContext* context)
       : AudioNode(context) {
+    AudioLock::AutoLock lock(audio_lock());
+
     AddInput(new AudioNodeInput(this));
   }
 
@@ -51,6 +53,8 @@
 
   // From AudioDevice::RenderCallback.
   void FillAudioBus(ShellAudioBus* audio_bus, bool* silence) OVERRIDE {
+    AudioLock::AutoLock lock(audio_lock());
+
     // Destination node only has one input.
     Input(0)->FillAudioBus(audio_bus, silence);
   }
@@ -61,15 +65,17 @@
     scoped_array<uint8> src_data,
     const AudioNodeChannelInterpretation& interpretation,
     ShellAudioBus* audio_bus, bool* silence) {
-  scoped_refptr<AudioBufferSourceNode> source(new AudioBufferSourceNode(NULL));
+  scoped_refptr<AudioContext> audio_context(new AudioContext());
+  scoped_refptr<AudioBufferSourceNode> source(
+      audio_context->CreateBufferSource());
   scoped_refptr<AudioBuffer> buffer(
       new AudioBuffer(NULL, 44100, static_cast<int32>(num_of_frames),
                       static_cast<int32>(num_of_src_channel), src_data.Pass(),
-                      GetPreferredOutputSampleType()));
+                      kSampleTypeFloat32));
   source->set_buffer(buffer);
 
   scoped_refptr<AudioDestinationNodeMock> destination(
-      new AudioDestinationNodeMock(NULL));
+      new AudioDestinationNodeMock(audio_context.get()));
   destination->set_channel_interpretation(interpretation);
   source->Connect(destination, 0, 0, NULL);
   source->Start(0, 0, NULL);
@@ -77,7 +83,12 @@
   destination->FillAudioBus(audio_bus, silence);
 }
 
-TEST(AudioNodeInputOutputTest, StereoToStereoSpeakersLayoutTest) {
+class AudioNodeInputOutputTest : public ::testing::Test {
+ protected:
+  MessageLoop message_loop_;
+};
+
+TEST_F(AudioNodeInputOutputTest, StereoToStereoSpeakersLayoutTest) {
   size_t num_of_src_channel = 2;
   size_t num_of_dest_channel = 2;
   size_t num_of_frames = 25;
@@ -119,7 +130,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, StereoToStereoDiscreteLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, StereoToStereoDiscreteLayoutTest) {
   size_t num_of_src_channel = 2;
   size_t num_of_dest_channel = 2;
   size_t num_of_frames = 25;
@@ -161,7 +172,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, MonoToStereoSpeakersLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, MonoToStereoSpeakersLayoutTest) {
   size_t num_of_src_channel = 1;
   size_t num_of_dest_channel = 2;
   size_t num_of_frames = 25;
@@ -197,7 +208,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, MonoToStereoDiscreteLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, MonoToStereoDiscreteLayoutTest) {
   size_t num_of_src_channel = 1;
   size_t num_of_dest_channel = 2;
   size_t num_of_frames = 25;
@@ -233,7 +244,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, QuadToStereoSpeakersLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, QuadToStereoSpeakersLayoutTest) {
   size_t num_of_src_channel = 4;
   size_t num_of_dest_channel = 2;
   size_t num_of_frames = 25;
@@ -275,7 +286,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, QuadToStereoDiscreteLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, QuadToStereoDiscreteLayoutTest) {
   size_t num_of_src_channel = 4;
   size_t num_of_dest_channel = 2;
   size_t num_of_frames = 25;
@@ -317,7 +328,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, FivePointOneToStereoSpeakersLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, FivePointOneToStereoSpeakersLayoutTest) {
   size_t num_of_src_channel = 6;
   size_t num_of_dest_channel = 2;
   size_t num_of_frames = 10;
@@ -359,7 +370,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, FivePointOneToStereoDiscreteLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, FivePointOneToStereoDiscreteLayoutTest) {
   size_t num_of_src_channel = 6;
   size_t num_of_dest_channel = 2;
   size_t num_of_frames = 10;
@@ -401,7 +412,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, StereoToMonoSpeakersLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, StereoToMonoSpeakersLayoutTest) {
   size_t num_of_src_channel = 2;
   size_t num_of_dest_channel = 1;
   size_t num_of_frames = 25;
@@ -439,7 +450,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, StereoToMonoDiscreteLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, StereoToMonoDiscreteLayoutTest) {
   size_t num_of_src_channel = 2;
   size_t num_of_dest_channel = 1;
   size_t num_of_frames = 25;
@@ -477,7 +488,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, QuadToMonoSpeakersLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, QuadToMonoSpeakersLayoutTest) {
   size_t num_of_src_channel = 4;
   size_t num_of_dest_channel = 1;
   size_t num_of_frames = 25;
@@ -515,7 +526,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, QuadToMonoDiscreteLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, QuadToMonoDiscreteLayoutTest) {
   size_t num_of_src_channel = 4;
   size_t num_of_dest_channel = 1;
   size_t num_of_frames = 25;
@@ -553,7 +564,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, FivePointOneToMonoSpeakersLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, FivePointOneToMonoSpeakersLayoutTest) {
   size_t num_of_src_channel = 6;
   size_t num_of_dest_channel = 1;
   size_t num_of_frames = 10;
@@ -591,7 +602,7 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, FivePointOneToMonoDiscreteLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, FivePointOneToMonoDiscreteLayoutTest) {
   size_t num_of_src_channel = 6;
   size_t num_of_dest_channel = 1;
   size_t num_of_frames = 10;
@@ -629,7 +640,9 @@
   }
 }
 
-TEST(AudioNodeInputOutputTest, MultipleInputNodesLayoutTest) {
+TEST_F(AudioNodeInputOutputTest, MultipleInputNodesLayoutTest) {
+  scoped_refptr<AudioContext> audio_context(new AudioContext());
+
   size_t num_of_src_channel = 2;
   size_t num_of_dest_channel = 2;
   AudioNodeChannelInterpretation interpretation =
@@ -646,11 +659,11 @@
   uint8* src_buffer_1 = src_data_1.get();
   memcpy(src_buffer_1, src_data_in_float_1, 200 * sizeof(uint8));
   scoped_refptr<AudioBufferSourceNode> source_1(
-      new AudioBufferSourceNode(NULL));
+      audio_context->CreateBufferSource());
   scoped_refptr<AudioBuffer> buffer_1(
       new AudioBuffer(NULL, 44100, static_cast<int32>(num_of_frames_1),
                       static_cast<int32>(num_of_src_channel), src_data_1.Pass(),
-                      GetPreferredOutputSampleType()));
+                      kSampleTypeFloat32));
   source_1->set_buffer(buffer_1);
 
   size_t num_of_frames_2 = 50;
@@ -664,15 +677,15 @@
   uint8* src_buffer_2 = src_data_2.get();
   memcpy(src_buffer_2, src_data_in_float_2, 400 * sizeof(uint8));
   scoped_refptr<AudioBufferSourceNode> source_2(
-      new AudioBufferSourceNode(NULL));
+      audio_context->CreateBufferSource());
   scoped_refptr<AudioBuffer> buffer_2(
       new AudioBuffer(NULL, 44100, static_cast<int32>(num_of_frames_2),
                       static_cast<int32>(num_of_src_channel), src_data_2.Pass(),
-                      GetPreferredOutputSampleType()));
+                      kSampleTypeFloat32));
   source_2->set_buffer(buffer_2);
 
   scoped_refptr<AudioDestinationNodeMock> destination(
-      new AudioDestinationNodeMock(NULL));
+      new AudioDestinationNodeMock(audio_context.get()));
   destination->set_channel_interpretation(interpretation);
   source_1->Connect(destination, 0, 0, NULL);
   source_2->Connect(destination, 0, 0, NULL);
diff --git a/src/cobalt/base/application_state.h b/src/cobalt/base/application_state.h
index a7fbc19..b1a0a21 100644
--- a/src/cobalt/base/application_state.h
+++ b/src/cobalt/base/application_state.h
@@ -17,6 +17,8 @@
 #ifndef COBALT_BASE_APPLICATION_STATE_H_
 #define COBALT_BASE_APPLICATION_STATE_H_
 
+#include "base/logging.h"
+
 namespace base {
 
 // Application states that Cobalt can be in, as derived from Starboard lifecycle
@@ -49,6 +51,25 @@
   kApplicationStateSuspended,
 };
 
+// Returns a human-readable string for the given |state|.
+static inline const char *GetApplicationStateString(ApplicationState state) {
+  switch (state) {
+    case kApplicationStatePaused:
+      return "kApplicationStatePaused";
+    case kApplicationStatePreloading:
+      return "kApplicationStatePreloading";
+    case kApplicationStateStarted:
+      return "kApplicationStateStarted";
+    case kApplicationStateStopped:
+      return "kApplicationStateStopped";
+    case kApplicationStateSuspended:
+      return "kApplicationStateSuspended";
+  }
+
+  NOTREACHED() << "state = " << state;
+  return "INVALID_APPLICATION_STATE";
+}
+
 }  // namespace base
 
 #endif  // COBALT_BASE_APPLICATION_STATE_H_
diff --git a/src/cobalt/base/event_dispatcher.h b/src/cobalt/base/event_dispatcher.h
index 45179e4..a131042 100644
--- a/src/cobalt/base/event_dispatcher.h
+++ b/src/cobalt/base/event_dispatcher.h
@@ -40,11 +40,11 @@
   void DispatchEvent(scoped_ptr<Event> event) const;
 
   // Register a callback to be notified about Events of the given type.
-  // May be called from any thread.
+  // May be called from any thread, but not from a dispatched event.
   void AddEventCallback(TypeId type, const EventCallback& cb);
 
   // De-register the given callback from subsequent notifications.
-  // May be called from any thread.
+  // May be called from any thread, but not from a dispatched event.
   void RemoveEventCallback(TypeId type, const EventCallback& cb);
 
  private:
diff --git a/src/cobalt/base/tokens.h b/src/cobalt/base/tokens.h
index 079661b..35d8e57 100644
--- a/src/cobalt/base/tokens.h
+++ b/src/cobalt/base/tokens.h
@@ -99,6 +99,7 @@
     MacroOpWithNameOnly(removals)                                    \
     MacroOpWithNameOnly(removesourcebuffer)                          \
     MacroOpWithNameOnly(removetrack)                                 \
+    MacroOpWithNameOnly(resize)                                      \
     MacroOpWithNameOnly(result)                                      \
     MacroOpWithNameOnly(resume)                                      \
     MacroOpWithNameOnly(securitypolicyviolation)                     \
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_anonymous_indexed_getter_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_anonymous_indexed_getter_interface.cc
index 4fedd30..6f7ac05 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_anonymous_indexed_getter_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_anonymous_indexed_getter_interface.cc
@@ -275,6 +275,11 @@
 bool get_length(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsAnonymousIndexedGetterInterface::PrototypeClass(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_anonymous_named_indexed_getter_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_anonymous_named_indexed_getter_interface.cc
index e2bbf8b..9afcce7 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_anonymous_named_indexed_getter_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_anonymous_named_indexed_getter_interface.cc
@@ -372,6 +372,11 @@
 bool get_length(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsAnonymousNamedIndexedGetterInterface::PrototypeClass(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_arbitrary_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_arbitrary_interface.cc
index 34b1625..de68231 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_arbitrary_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_arbitrary_interface.cc
@@ -181,6 +181,11 @@
 bool get_arbitraryProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsArbitraryInterface::PrototypeClass(context);
@@ -224,6 +229,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_base_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_base_interface.cc
index ae10c81..954072a 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_base_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_base_interface.cc
@@ -181,6 +181,11 @@
 bool get_baseAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsBaseInterface::PrototypeClass(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_boolean_type_test_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_boolean_type_test_interface.cc
index 9eef1ad..64e9741 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_boolean_type_test_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_boolean_type_test_interface.cc
@@ -180,6 +180,11 @@
 bool get_booleanProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsBooleanTypeTestInterface::PrototypeClass(context);
@@ -223,6 +228,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_function_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_function_interface.cc
index d4dd89a..3cf816e 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_function_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_function_interface.cc
@@ -184,6 +184,11 @@
 bool get_callbackAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsCallbackFunctionInterface::PrototypeClass(context);
@@ -227,6 +232,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -274,6 +284,11 @@
 bool get_nullableCallbackAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsCallbackFunctionInterface::PrototypeClass(context);
@@ -317,6 +332,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc
index 19ff19e..c5622f7 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc
@@ -184,6 +184,11 @@
 bool get_callbackAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsCallbackInterfaceInterface::PrototypeClass(context);
@@ -227,6 +232,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_conditional_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_conditional_interface.cc
index 7d8ae8d..ae18a41 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_conditional_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_conditional_interface.cc
@@ -183,6 +183,11 @@
 bool get_enabledAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsConditionalInterface::PrototypeClass(context);
@@ -226,6 +231,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -275,6 +285,11 @@
 bool get_disabledAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsConditionalInterface::PrototypeClass(context);
@@ -318,6 +333,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_constants_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_constants_interface.cc
index 12749e6..cd9cc40 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_constants_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_constants_interface.cc
@@ -124,6 +124,11 @@
   COMPILE_ASSERT(ConstantsInterface::kIntegerConstant == 5,
                  ValueForConstantsInterface_kIntegerConstantDoesNotMatchIDL);
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   MozjsExceptionState exception_state(context);
   JS::RootedValue result_value(context);
@@ -140,6 +145,11 @@
       "The value for ConstantsInterface::kDoubleConstant does not match "
       "the value in the interface definition.";
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   MozjsExceptionState exception_state(context);
   JS::RootedValue result_value(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_constructor_with_arguments_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_constructor_with_arguments_interface.cc
index a309c05..416a407 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_constructor_with_arguments_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_constructor_with_arguments_interface.cc
@@ -181,6 +181,11 @@
 bool get_longArg(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsConstructorWithArgumentsInterface::PrototypeClass(context);
@@ -224,6 +229,11 @@
 bool get_booleanArg(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsConstructorWithArgumentsInterface::PrototypeClass(context);
@@ -267,6 +277,11 @@
 bool get_stringArg(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsConstructorWithArgumentsInterface::PrototypeClass(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_derived_getter_setter_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_derived_getter_setter_interface.cc
index 0574f01..f855b8d 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_derived_getter_setter_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_derived_getter_setter_interface.cc
@@ -376,6 +376,11 @@
 bool get_length(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDerivedGetterSetterInterface::PrototypeClass(context);
@@ -419,6 +424,11 @@
 bool get_propertyOnDerivedClass(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDerivedGetterSetterInterface::PrototypeClass(context);
@@ -462,6 +472,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_derived_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_derived_interface.cc
index 82deddc..e04680b 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_derived_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_derived_interface.cc
@@ -185,6 +185,11 @@
 bool get_derivedAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDerivedInterface::PrototypeClass(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc
index ac2592b..1b865a6 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc
@@ -184,6 +184,11 @@
 bool get_dictionarySequence(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDictionaryInterface::PrototypeClass(context);
@@ -227,6 +232,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_disabled_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_disabled_interface.cc
index dba9f4e..f08fc6a 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_disabled_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_disabled_interface.cc
@@ -182,6 +182,11 @@
 bool get_disabledProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDisabledInterface::PrototypeClass(context);
@@ -225,6 +230,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dom_string_test_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dom_string_test_interface.cc
index f26ffc4..2f4b7f8 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dom_string_test_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dom_string_test_interface.cc
@@ -180,6 +180,11 @@
 bool get_property(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDOMStringTestInterface::PrototypeClass(context);
@@ -223,6 +228,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -270,6 +280,11 @@
 bool get_readOnlyProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDOMStringTestInterface::PrototypeClass(context);
@@ -313,6 +328,11 @@
 bool get_readOnlyTokenProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDOMStringTestInterface::PrototypeClass(context);
@@ -356,6 +376,11 @@
 bool get_nullIsEmptyProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDOMStringTestInterface::PrototypeClass(context);
@@ -399,6 +424,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -446,6 +476,11 @@
 bool get_undefinedIsEmptyProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDOMStringTestInterface::PrototypeClass(context);
@@ -489,6 +524,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -536,6 +576,11 @@
 bool get_nullableUndefinedIsEmptyProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsDOMStringTestInterface::PrototypeClass(context);
@@ -579,6 +624,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_enumeration_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_enumeration_interface.cc
index 1b4b7c3..299c539 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_enumeration_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_enumeration_interface.cc
@@ -183,6 +183,11 @@
 bool get_enumProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsEnumerationInterface::PrototypeClass(context);
@@ -226,6 +231,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_exception_object_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_exception_object_interface.cc
index f6bb0dd..5030193 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_exception_object_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_exception_object_interface.cc
@@ -181,6 +181,11 @@
 bool get_error(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsExceptionObjectInterface::PrototypeClass(context);
@@ -224,6 +229,11 @@
 bool get_message(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsExceptionObjectInterface::PrototypeClass(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_exceptions_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_exceptions_interface.cc
index 64559ee..8b3aff7 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_exceptions_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_exceptions_interface.cc
@@ -181,6 +181,11 @@
 bool get_attributeThrowsException(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsExceptionsInterface::PrototypeClass(context);
@@ -224,6 +229,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_extended_idl_attributes_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_extended_idl_attributes_interface.cc
index 4789a3a..41a46d6 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_extended_idl_attributes_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_extended_idl_attributes_interface.cc
@@ -180,6 +180,11 @@
 bool get_default(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsExtendedIDLAttributesInterface::PrototypeClass(context);
@@ -223,6 +228,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc
index f597106..e854293 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_garbage_collection_test_interface.cc
@@ -185,6 +185,11 @@
 bool get_previous(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsGarbageCollectionTestInterface::PrototypeClass(context);
@@ -228,6 +233,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -275,6 +285,11 @@
 bool get_next(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsGarbageCollectionTestInterface::PrototypeClass(context);
@@ -318,6 +333,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_indexed_getter_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_indexed_getter_interface.cc
index 6effd9d..7957be4 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_indexed_getter_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_indexed_getter_interface.cc
@@ -290,6 +290,11 @@
 bool get_length(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsIndexedGetterInterface::PrototypeClass(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_unsupported_properties.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_unsupported_properties.cc
index 024a736..c9d71d7 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_unsupported_properties.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_unsupported_properties.cc
@@ -180,6 +180,11 @@
 bool get_supportedAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsInterfaceWithUnsupportedProperties::PrototypeClass(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_indexed_getter_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_indexed_getter_interface.cc
index 513dd5a..3874d45 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_indexed_getter_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_indexed_getter_interface.cc
@@ -372,6 +372,11 @@
 bool get_length(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNamedIndexedGetterInterface::PrototypeClass(context);
@@ -415,6 +420,11 @@
 bool get_propertyOnBaseClass(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNamedIndexedGetterInterface::PrototypeClass(context);
@@ -458,6 +468,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nested_put_forwards_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nested_put_forwards_interface.cc
index 243e148..f73f3c5 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nested_put_forwards_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nested_put_forwards_interface.cc
@@ -184,6 +184,11 @@
 bool get_nestedForwardingAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNestedPutForwardsInterface::PrototypeClass(context);
@@ -227,6 +232,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nullable_types_test_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nullable_types_test_interface.cc
index 8e96f5a..9fc4e54 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nullable_types_test_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nullable_types_test_interface.cc
@@ -184,6 +184,11 @@
 bool get_nullableBooleanProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNullableTypesTestInterface::PrototypeClass(context);
@@ -227,6 +232,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -274,6 +284,11 @@
 bool get_nullableNumericProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNullableTypesTestInterface::PrototypeClass(context);
@@ -317,6 +332,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -364,6 +384,11 @@
 bool get_nullableStringProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNullableTypesTestInterface::PrototypeClass(context);
@@ -407,6 +432,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -454,6 +484,11 @@
 bool get_nullableObjectProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNullableTypesTestInterface::PrototypeClass(context);
@@ -497,6 +532,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_numeric_types_test_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_numeric_types_test_interface.cc
index a06e9d8..c335147 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_numeric_types_test_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_numeric_types_test_interface.cc
@@ -180,6 +180,11 @@
 bool get_byteProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -223,6 +228,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -270,6 +280,11 @@
 bool get_byteClampProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -313,6 +328,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -360,6 +380,11 @@
 bool get_octetProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -403,6 +428,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -450,6 +480,11 @@
 bool get_octetClampProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -493,6 +528,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -540,6 +580,11 @@
 bool get_shortProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -583,6 +628,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -630,6 +680,11 @@
 bool get_shortClampProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -673,6 +728,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -720,6 +780,11 @@
 bool get_unsignedShortProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -763,6 +828,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -810,6 +880,11 @@
 bool get_unsignedShortClampProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -853,6 +928,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -900,6 +980,11 @@
 bool get_longProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -943,6 +1028,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -990,6 +1080,11 @@
 bool get_longClampProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -1033,6 +1128,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -1080,6 +1180,11 @@
 bool get_unsignedLongProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -1123,6 +1228,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -1170,6 +1280,11 @@
 bool get_unsignedLongClampProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -1213,6 +1328,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -1260,6 +1380,11 @@
 bool get_longLongProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -1303,6 +1428,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -1350,6 +1480,11 @@
 bool get_longLongClampProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -1393,6 +1528,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -1440,6 +1580,11 @@
 bool get_unsignedLongLongProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -1483,6 +1628,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -1530,6 +1680,11 @@
 bool get_unsignedLongLongClampProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -1573,6 +1728,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -1620,6 +1780,11 @@
 bool get_doubleProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -1663,6 +1828,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -1710,6 +1880,11 @@
 bool get_unrestrictedDoubleProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsNumericTypesTestInterface::PrototypeClass(context);
@@ -1753,6 +1928,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc
index d80da47..af0e29b 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc
@@ -192,6 +192,11 @@
 bool get_arbitraryObject(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsObjectTypeBindingsInterface::PrototypeClass(context);
@@ -235,6 +240,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -282,6 +292,11 @@
 bool get_baseInterface(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsObjectTypeBindingsInterface::PrototypeClass(context);
@@ -325,6 +340,11 @@
 bool get_derivedInterface(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsObjectTypeBindingsInterface::PrototypeClass(context);
@@ -368,6 +388,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -415,6 +440,11 @@
 bool get_objectProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsObjectTypeBindingsInterface::PrototypeClass(context);
@@ -458,6 +488,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_put_forwards_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_put_forwards_interface.cc
index a4bbd60..f25d3fb 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_put_forwards_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_put_forwards_interface.cc
@@ -184,6 +184,11 @@
 bool get_forwardingAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsPutForwardsInterface::PrototypeClass(context);
@@ -227,6 +232,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -287,6 +297,11 @@
   MozjsExceptionState exception_state(context);
   JS::RootedValue result_value(context);
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   if (!exception_state.is_exception_set()) {
@@ -304,6 +319,11 @@
   JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   MozjsExceptionState exception_state(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_static_properties_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_static_properties_interface.cc
index c51a115..8526725 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_static_properties_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_static_properties_interface.cc
@@ -186,6 +186,11 @@
   MozjsExceptionState exception_state(context);
   JS::RootedValue result_value(context);
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   if (!exception_state.is_exception_set()) {
@@ -203,6 +208,11 @@
   JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   MozjsExceptionState exception_state(context);
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_attribute_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_attribute_interface.cc
index e861ff7..480fab8 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_attribute_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_attribute_interface.cc
@@ -180,6 +180,11 @@
 bool get_theStringifierAttribute(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsStringifierAttributeInterface::PrototypeClass(context);
@@ -223,6 +228,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc
index a9026b2..7908828 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc
@@ -188,6 +188,11 @@
 bool get_unionProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsUnionTypesInterface::PrototypeClass(context);
@@ -231,6 +236,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -278,6 +288,11 @@
 bool get_unionWithNullableMemberProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsUnionTypesInterface::PrototypeClass(context);
@@ -321,6 +336,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -368,6 +388,11 @@
 bool get_nullableUnionProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsUnionTypesInterface::PrototypeClass(context);
@@ -411,6 +436,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -458,6 +488,11 @@
 bool get_unionBaseProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsUnionTypesInterface::PrototypeClass(context);
@@ -501,6 +536,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc
index f0b91a4..949d54e 100644
--- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc
+++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc
@@ -385,6 +385,11 @@
 bool get_windowProperty(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsWindow::PrototypeClass(context);
@@ -428,6 +433,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
@@ -475,6 +485,11 @@
 bool get_window(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsWindow::PrototypeClass(context);
@@ -518,6 +533,11 @@
 bool get_onEvent(
     JSContext* context, unsigned argc, JS::Value* vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   const JSClass* proto_class =
       MozjsWindow::PrototypeClass(context);
@@ -561,6 +581,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
   const JSClass* proto_class =
diff --git a/src/cobalt/bindings/mozjs45/templates/interface.cc.template b/src/cobalt/bindings/mozjs45/templates/interface.cc.template
index 00e5080..aa7bbf0 100644
--- a/src/cobalt/bindings/mozjs45/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs45/templates/interface.cc.template
@@ -336,6 +336,11 @@
       "the value in the interface definition.";
 {% endif %}
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   MozjsExceptionState exception_state(context);
   JS::RootedValue result_value(context);
@@ -416,8 +421,12 @@
 {% if attribute.is_constructor_attribute %}
 bool get_{{attribute.idl_name}}(
     JSContext* context, unsigned argc, JS::Value* vp) {
-
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
   JS::RootedObject global_object(
     context, JS_GetGlobalForObject(context, object));
@@ -438,6 +447,11 @@
     JSContext* context, unsigned argc, JS::Value* vp) {
 {% endif %}
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 {% if not attribute.is_static %}
 {{ check_if_object_implements_interface() }}
@@ -463,6 +477,11 @@
 {% endif %}
 
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  if (!args.thisv().isObject()) {
+    MozjsExceptionState exception(context);
+    exception.SetSimpleException(script::kTypeError, "Invalid this.");
+    return false;
+  }
   JS::RootedObject object(context, &args.thisv().toObject());
 
 {% if attribute.is_static %}
diff --git a/src/cobalt/bindings/testing/getter_setter_test.cc b/src/cobalt/bindings/testing/getter_setter_test.cc
index 1db2969..137643d 100644
--- a/src/cobalt/bindings/testing/getter_setter_test.cc
+++ b/src/cobalt/bindings/testing/getter_setter_test.cc
@@ -450,6 +450,42 @@
   EXPECT_STREQ("true", result.c_str());
 }
 
+TEST_F(DerivedGetterSetterBindingsTest,
+       GetterCanHandleAllJavaScriptValueTypes) {
+  const char* script = R"EOF(
+      const getter = Object.getOwnPropertyDescriptor(
+          ArbitraryInterface.prototype, "arbitraryProperty").get;
+      [null, undefined, false, 0, "", {}, Symbol("")]
+        .map(value => {
+          try { getter.call(value); }
+          catch (ex) { return ex.toString().startsWith("TypeError"); }
+          return false;
+        })
+        .every(result => result);
+  )EOF";
+  std::string result;
+  EXPECT_TRUE(EvaluateScript(script, &result));
+  EXPECT_STREQ("true", result.c_str());
+}
+
+TEST_F(DerivedGetterSetterBindingsTest,
+       SetterCanHandleAllJavaScriptValueTypes) {
+  const char* script = R"EOF(
+      const setter = Object.getOwnPropertyDescriptor(
+          ArbitraryInterface.prototype, "arbitraryProperty").set;
+      [null, undefined, false, 0, "", {}, Symbol("")]
+        .map(value => {
+          try { setter.call(value); }
+          catch (ex) { return ex.toString().startsWith("TypeError"); }
+          return false;
+        })
+        .every(result => result);
+  )EOF";
+  std::string result;
+  EXPECT_TRUE(EvaluateScript(script, &result));
+  EXPECT_STREQ("true", result.c_str());
+}
+
 }  // namespace testing
 }  // namespace bindings
 }  // namespace cobalt
diff --git a/src/cobalt/bindings/testing/interface_object_test.cc b/src/cobalt/bindings/testing/interface_object_test.cc
index 19e6126..1096554 100644
--- a/src/cobalt/bindings/testing/interface_object_test.cc
+++ b/src/cobalt/bindings/testing/interface_object_test.cc
@@ -109,6 +109,22 @@
   EXPECT_STREQ("false", result.c_str());
 }
 
+TEST_F(InterfaceObjectTest, FunctionCanHandleAllJavaScriptValueTypes) {
+  const char* script = R"EOF(
+      const f = ArbitraryInterface.prototype.ArbitraryFunction;
+      [null, undefined, false, 0, "", {}, Symbol("")]
+        .map(value => {
+          try { f.call(value); }
+          catch (ex) { return ex.toString().startsWith("TypeError"); }
+          return false;
+        })
+        .every(result => result);
+  )EOF";
+  std::string result;
+  EXPECT_TRUE(EvaluateScript(script, &result));
+  EXPECT_STREQ("true", result.c_str());
+}
+
 }  // namespace testing
 }  // namespace bindings
 }  // namespace cobalt
diff --git a/src/cobalt/bindings/testing/numeric_type_bindings_test.cc b/src/cobalt/bindings/testing/numeric_type_bindings_test.cc
index f6620f0..1f2ea29 100644
--- a/src/cobalt/bindings/testing/numeric_type_bindings_test.cc
+++ b/src/cobalt/bindings/testing/numeric_type_bindings_test.cc
@@ -328,7 +328,7 @@
   if (TypeParam::min_value() < 0) {
     expected_result = StringPrintf("-%" PRIu64 "", kRangeBound);
     EXPECT_CALL(this->test_mock(), MockReturnValueOperation())
-        .WillOnce(Return(-kRangeBound));
+        .WillOnce(Return(-static_cast<int64_t>(kRangeBound)));
     EXPECT_TRUE(this->EvaluateScript(script, &result));
     EXPECT_STREQ(expected_result.c_str(), result.c_str());
   }
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index 4948758..3d88ac6 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -29,6 +29,7 @@
 #include "base/string_util.h"
 #include "base/time.h"
 #include "build/build_config.h"
+#include "cobalt/base/accessibility_settings_changed_event.h"
 #include "cobalt/base/application_event.h"
 #include "cobalt/base/cobalt_paths.h"
 #include "cobalt/base/deep_link_event.h"
@@ -47,16 +48,10 @@
 #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 #include "cobalt/storage/savegame_fake.h"
 #endif
+#include "cobalt/system_window/input_event.h"
 #include "cobalt/trace_event/scoped_trace_to_file.h"
 #include "googleurl/src/gurl.h"
-#if defined(__LB_SHELL__)
-#if !defined(__LB_SHELL__FOR_RELEASE__)
-#include "lbshell/src/lb_memory_manager.h"
-#endif  // defined(__LB_SHELL__FOR_RELEASE__)
-#include "lbshell/src/lb_memory_pages.h"
-#endif  // defined(__LB_SHELL__)
 #include "starboard/configuration.h"
-#include "starboard/log.h"
 
 namespace cobalt {
 namespace browser {
@@ -606,11 +601,6 @@
       base::Bind(&Application::OnNetworkEvent, base::Unretained(this));
   event_dispatcher_.AddEventCallback(network::NetworkEvent::TypeId(),
                                      network_event_callback_);
-  application_event_callback_ =
-      base::Bind(&Application::OnApplicationEvent, base::Unretained(this));
-  event_dispatcher_.AddEventCallback(base::ApplicationEvent::TypeId(),
-                                     application_event_callback_);
-
   deep_link_event_callback_ =
       base::Bind(&Application::OnDeepLinkEvent, base::Unretained(this));
   event_dispatcher_.AddEventCallback(base::DeepLinkEvent::TypeId(),
@@ -666,8 +656,6 @@
   // Unregister event callbacks.
   event_dispatcher_.RemoveEventCallback(network::NetworkEvent::TypeId(),
                                         network_event_callback_);
-  event_dispatcher_.RemoveEventCallback(base::ApplicationEvent::TypeId(),
-                                        application_event_callback_);
   event_dispatcher_.RemoveEventCallback(
       base::DeepLinkEvent::TypeId(), deep_link_event_callback_);
 
@@ -686,9 +674,7 @@
     return;
   }
 
-  event_dispatcher_.DispatchEvent(make_scoped_ptr<base::Event>(
-      new base::ApplicationEvent(kSbEventTypeStart)));
-  app_status_ = kRunningAppStatus;
+  OnApplicationEvent(kSbEventTypeStart);
 }
 
 void Application::Quit() {
@@ -706,6 +692,47 @@
   app_status_ = kQuitAppStatus;
 }
 
+void Application::HandleStarboardEvent(const SbEvent* starboard_event) {
+  DCHECK(starboard_event);
+
+  // Forward input events to |SystemWindow|.
+  if (starboard_event->type == kSbEventTypeInput) {
+    system_window::HandleInputEvent(starboard_event);
+    return;
+  }
+
+  // Create a Cobalt event from the Starboard event, if recognized.
+  switch (starboard_event->type) {
+    case kSbEventTypePause:
+    case kSbEventTypeUnpause:
+    case kSbEventTypeSuspend:
+    case kSbEventTypeResume:
+      OnApplicationEvent(starboard_event->type);
+      break;
+    case kSbEventTypeNetworkConnect:
+      DispatchEventInternal(
+          new network::NetworkEvent(network::NetworkEvent::kConnection));
+      break;
+    case kSbEventTypeNetworkDisconnect:
+      DispatchEventInternal(
+          new network::NetworkEvent(network::NetworkEvent::kDisconnection));
+      break;
+    case kSbEventTypeLink: {
+      const char* link = static_cast<const char*>(starboard_event->data);
+      DispatchEventInternal(new base::DeepLinkEvent(link));
+      break;
+    }
+#if SB_API_VERSION >= 4
+    case kSbEventTypeAccessiblitySettingsChanged:
+      DispatchEventInternal(new base::AccessibilitySettingsChangedEvent());
+      break;
+#endif  // SB_API_VERSION >= 4
+    default:
+      DLOG(WARNING) << "Unhandled Starboard event of type: "
+                    << starboard_event->type;
+  }
+}
+
 void Application::OnNetworkEvent(const base::Event* event) {
   TRACE_EVENT0("cobalt::browser", "Application::OnNetworkEvent()");
   DCHECK(network_event_thread_checker_.CalledOnValidThread());
@@ -727,37 +754,53 @@
   }
 }
 
-void Application::OnApplicationEvent(const base::Event* event) {
+void Application::OnApplicationEvent(SbEventType event_type) {
   TRACE_EVENT0("cobalt::browser", "Application::OnApplicationEvent()");
   DCHECK(application_event_thread_checker_.CalledOnValidThread());
-  const base::ApplicationEvent* app_event =
-      base::polymorphic_downcast<const base::ApplicationEvent*>(event);
-  if (app_event->type() == kSbEventTypeStop) {
-    DLOG(INFO) << "Got quit event.";
-    app_status_ = kWillQuitAppStatus;
-    Quit();
-  } else if (app_event->type() == kSbEventTypePause) {
-    DLOG(INFO) << "Got pause event.";
-    app_status_ = kPausedAppStatus;
-    ++app_pause_count_;
-    browser_module_->Pause();
-  } else if (app_event->type() == kSbEventTypeUnpause) {
-    DLOG(INFO) << "Got unpause event.";
-    app_status_ = kRunningAppStatus;
-    ++app_unpause_count_;
-    browser_module_->Unpause();
-  } else if (app_event->type() == kSbEventTypeSuspend) {
-    DLOG(INFO) << "Got suspend event.";
-    app_status_ = kSuspendedAppStatus;
-    ++app_suspend_count_;
-    browser_module_->Suspend();
-    DLOG(INFO) << "Finished suspending.";
-  } else if (app_event->type() == kSbEventTypeResume) {
-    DLOG(INFO) << "Got resume event.";
-    app_status_ = kPausedAppStatus;
-    ++app_resume_count_;
-    browser_module_->Resume();
-    DLOG(INFO) << "Finished resuming.";
+  switch (event_type) {
+    case kSbEventTypeStop:
+      DLOG(INFO) << "Got quit event.";
+      app_status_ = kWillQuitAppStatus;
+      Quit();
+      DLOG(INFO) << "Finished quitting.";
+      break;
+    case kSbEventTypeStart:
+      DLOG(INFO) << "Got start event.";
+      app_status_ = kRunningAppStatus;
+      browser_module_->Start();
+      DLOG(INFO) << "Finished starting.";
+      break;
+    case kSbEventTypePause:
+      DLOG(INFO) << "Got pause event.";
+      app_status_ = kPausedAppStatus;
+      ++app_pause_count_;
+      browser_module_->Pause();
+      DLOG(INFO) << "Finished pausing.";
+      break;
+    case kSbEventTypeUnpause:
+      DLOG(INFO) << "Got unpause event.";
+      app_status_ = kRunningAppStatus;
+      ++app_unpause_count_;
+      browser_module_->Unpause();
+      DLOG(INFO) << "Finished unpausing.";
+      break;
+    case kSbEventTypeSuspend:
+      DLOG(INFO) << "Got suspend event.";
+      app_status_ = kSuspendedAppStatus;
+      ++app_suspend_count_;
+      browser_module_->Suspend();
+      DLOG(INFO) << "Finished suspending.";
+      break;
+    case kSbEventTypeResume:
+      DLOG(INFO) << "Got resume event.";
+      app_status_ = kPausedAppStatus;
+      ++app_resume_count_;
+      browser_module_->Resume();
+      DLOG(INFO) << "Finished resuming.";
+      break;
+    default:
+      NOTREACHED() << "Unexpected event type: " << event_type;
+      return;
   }
 }
 
@@ -877,5 +920,9 @@
   browser_module_->CheckMemory(used_cpu_memory, used_gpu_memory);
 }
 
+void Application::DispatchEventInternal(base::Event* event) {
+  event_dispatcher_.DispatchEvent(make_scoped_ptr<base::Event>(event));
+}
+
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/application.h b/src/cobalt/browser/application.h
index a8a5597..ab3ce08 100644
--- a/src/cobalt/browser/application.h
+++ b/src/cobalt/browser/application.h
@@ -24,6 +24,7 @@
 #include "cobalt/browser/browser_module.h"
 #include "cobalt/browser/memory_tracker/tool.h"
 #include "cobalt/system_window/system_window.h"
+#include "starboard/event.h"
 
 #if defined(ENABLE_WEBDRIVER)
 #include "cobalt/webdriver/web_driver_module.h"
@@ -36,21 +37,21 @@
 namespace cobalt {
 namespace browser {
 
-// The Application base class is meant to manage the main thread's UI
-// message loop.  A platform-specific application will be created via
-// CreateApplication().  This class and all of its subclasses are not designed
-// to be thread safe.
+// The Application class is meant to manage the main thread's UI message
+// loop. This class is not designed to be thread safe.
 class Application {
  public:
+  // The passed in |quit_closure| can be called internally by the Application to
+  // signal that it would like to quit.
+  Application(const base::Closure& quit_closure, bool should_preload);
   virtual ~Application();
 
   // Start from a preloaded state.
   void Start();
   void Quit();
+  void HandleStarboardEvent(const SbEvent* event);
 
  protected:
-  Application(const base::Closure& quit_closure, bool should_preload);
-
   MessageLoop* message_loop() { return message_loop_; }
 
  private:
@@ -64,7 +65,7 @@
   void OnNetworkEvent(const base::Event* event);
 
   // Called to handle an application event.
-  void OnApplicationEvent(const base::Event* event);
+  void OnApplicationEvent(SbEventType event_type);
 
   // Called to handle a deep link event.
   void OnDeepLinkEvent(const base::Event* event);
@@ -83,7 +84,6 @@
 
   // Event callbacks.
   base::EventCallback network_event_callback_;
-  base::EventCallback application_event_callback_;
   base::EventCallback deep_link_event_callback_;
 
   // Thread checkers to ensure that callbacks for network and application events
@@ -113,6 +113,7 @@
     kQuitAppStatus,
     kShutDownAppStatus,
   };
+
   enum NetworkStatus {
     kDisconnectedNetworkStatus,
     kConnectedNetworkStatus,
@@ -144,8 +145,8 @@
 
   void RegisterUserLogs();
   void UpdateAndMaybeRegisterUserAgent();
-
   void UpdatePeriodicStats();
+  void DispatchEventInternal(base::Event* event);
 
   static ssize_t available_memory_;
   static int64 lifetime_in_ms_;
@@ -167,16 +168,6 @@
   scoped_ptr<memory_tracker::Tool> memory_tracker_tool_;
 };
 
-// Factory method for creating a started application. The passed in
-// |quit_closure| can be called internally by the application to signal that it
-// would like to quit.
-scoped_ptr<Application> CreateApplication(const base::Closure& quit_closure);
-
-// Factory method for creating a preloading application. The passed in
-// |quit_closure| can be called internally by the application to signal that it
-// would like to quit.
-scoped_ptr<Application> PreloadApplication(const base::Closure& quit_closure);
-
 }  // namespace browser
 }  // namespace cobalt
 
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index 015dd40..d744b06 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -182,43 +182,6 @@
   return options;  // Copy.
 }
 
-void ApplyAutoMemSettings(const memory_settings::AutoMem& auto_mem,
-                          BrowserModule::Options* options) {
-  SB_LOG(INFO) << "\n\n"
-               << auto_mem.ToPrettyPrintString(SbLogIsTty()) << "\n\n";
-
-  options->web_module_options.image_cache_capacity =
-      static_cast<int>(auto_mem.image_cache_size_in_bytes()->value());
-
-  options->renderer_module_options.skia_cache_size_in_bytes =
-      static_cast<int>(auto_mem.skia_cache_size_in_bytes()->value());
-
-  const memory_settings::TextureDimensions skia_glyph_atlas_texture_dimensions =
-      auto_mem.skia_atlas_texture_dimensions()->value();
-
-  // Right now the bytes_per_pixel is assumed in the engine. Any other value
-  // is currently forbidden.
-  if (skia_glyph_atlas_texture_dimensions.bytes_per_pixel() > 0) {
-    DCHECK_EQ(2, skia_glyph_atlas_texture_dimensions.bytes_per_pixel());
-    options->renderer_module_options.skia_glyph_texture_atlas_dimensions =
-        math::Size(skia_glyph_atlas_texture_dimensions.width(),
-                   skia_glyph_atlas_texture_dimensions.height());
-  }
-
-  options->web_module_options.remote_typeface_cache_capacity =
-      static_cast<int>(auto_mem.remote_typeface_cache_size_in_bytes()->value());
-
-  options->web_module_options.javascript_options.gc_threshold_bytes =
-      static_cast<size_t>(auto_mem.javascript_gc_threshold_in_bytes()->value());
-
-  options->renderer_module_options.software_surface_cache_size_in_bytes =
-      static_cast<int>(
-          auto_mem.software_surface_cache_size_in_bytes()->value());
-  options->renderer_module_options.offscreen_target_cache_size_in_bytes =
-      static_cast<int>(
-          auto_mem.offscreen_target_cache_size_in_bytes()->value());
-}
-
 }  // namespace
 
 BrowserModule::BrowserModule(const GURL& url,
@@ -321,6 +284,13 @@
   if (application_state_ == base::kApplicationStateStarted ||
       application_state_ == base::kApplicationStatePaused) {
     InitializeSystemWindow();
+  } else if (application_state_ == base::kApplicationStatePreloading) {
+#if defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
+    // Preloading is not supported on platforms that allocate ArrayBuffers on
+    // GPU memory.
+    NOTREACHED();
+#endif  // defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
+    resource_provider_stub_.emplace(true /*allocate_image_data*/);
   }
 
 #if defined(ENABLE_DEBUG_CONSOLE)
@@ -527,7 +497,8 @@
     const browser::WebModule::LayoutResults& layout_results) {
   TRACE_EVENT0("cobalt::browser", "BrowserModule::OnRenderTreeProduced()");
   DCHECK_EQ(MessageLoop::current(), self_message_loop_);
-  if (!render_tree_combiner_) {
+  if (application_state_ == base::kApplicationStatePreloading ||
+      !render_tree_combiner_) {
     return;
   }
 
@@ -634,7 +605,8 @@
   TRACE_EVENT0("cobalt::browser",
                "BrowserModule::OnDebugConsoleRenderTreeProduced()");
   DCHECK_EQ(MessageLoop::current(), self_message_loop_);
-  if (!render_tree_combiner_) {
+  if (application_state_ == base::kApplicationStatePreloading ||
+      !render_tree_combiner_) {
     return;
   }
 
@@ -874,9 +846,10 @@
 void BrowserModule::Start() {
   TRACE_EVENT0("cobalt::browser", "BrowserModule::Start()");
   DCHECK(application_state_ == base::kApplicationStatePreloading);
-  render_tree::ResourceProvider* resource_provider = GetResourceProvider();
-  FOR_EACH_OBSERVER(LifecycleObserver, lifecycle_observers_,
-                    Start(resource_provider));
+
+  SuspendInternal(true /*is_start*/);
+  StartOrResumeInternal(true /*is_start*/);
+
   application_state_ = base::kApplicationStateStarted;
 }
 
@@ -896,52 +869,10 @@
 
 void BrowserModule::Suspend() {
   TRACE_EVENT0("cobalt::browser", "BrowserModule::Suspend()");
-  DCHECK(application_state_ == base::kApplicationStatePaused);
+  DCHECK(application_state_ == base::kApplicationStatePaused ||
+         application_state_ == base::kApplicationStatePreloading);
 
-  // First suspend all our web modules which implies that they will release
-  // their resource provider and all resources created through it.
-  FOR_EACH_OBSERVER(LifecycleObserver, lifecycle_observers_, Suspend());
-
-  // Flush out any submitted render trees pushed since we started shutting down
-  // the web modules above.
-  render_tree_submission_queue_.ProcessAll();
-
-#if defined(ENABLE_SCREENSHOT)
-  // The screenshot writer may be holding on to a reference to a render tree
-  // which could in turn be referencing resources like images, so clear that
-  // out.
-  if (screen_shot_writer_) {
-    screen_shot_writer_->ClearLastPipelineSubmission();
-  }
-#endif
-
-  // Clear out the render tree combiner so that it doesn't hold on to any
-  // render tree resources either.
-  if (render_tree_combiner_) {
-    render_tree_combiner_->Reset();
-  }
-
-#if defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
-  // Note that the following function call will leak the GPU memory allocated.
-  // This is because after renderer_module_->Suspend() is called it is no longer
-  // safe to release the GPU memory allocated.
-  //
-  // The following code can call reset() to release the allocated memory but the
-  // memory may still be used by XHR and ArrayBuffer.  As this feature is only
-  // used on platform without Resume() support, it is safer to leak the memory
-  // then to release it.
-  dom::ArrayBuffer::Allocator* allocator = array_buffer_allocator_.release();
-#endif  // defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
-
-  if (media_module_) {
-    media_module_->Suspend();
-  }
-
-  if (renderer_module_) {
-    // Place the renderer module into a suspended state where it releases all
-    // its graphical resources.
-    renderer_module_->Suspend();
-  }
+  SuspendInternal(false /*is_start*/);
 
   application_state_ = base::kApplicationStateSuspended;
 }
@@ -950,23 +881,7 @@
   TRACE_EVENT0("cobalt::browser", "BrowserModule::Resume()");
   DCHECK(application_state_ == base::kApplicationStateSuspended);
 
-  renderer_module_->Resume();
-
-  // Note that at this point, it is probable that this resource provider is
-  // different than the one that was managed in the associated call to
-  // Suspend().
-  render_tree::ResourceProvider* resource_provider = GetResourceProvider();
-
-  media_module_->Resume(resource_provider);
-
-#if defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
-  // Resume() is not supported on platforms that allocates ArrayBuffer on GPU
-  // memory.
-  NOTREACHED();
-#endif  // defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
-
-  FOR_EACH_OBSERVER(LifecycleObserver, lifecycle_observers_,
-                    Resume(resource_provider));
+  StartOrResumeInternal(false /*is_start*/);
 
   application_state_ = base::kApplicationStatePaused;
 }
@@ -974,6 +889,10 @@
 void BrowserModule::CheckMemory(
     const int64_t& used_cpu_memory,
     const base::optional<int64_t>& used_gpu_memory) {
+  if (!auto_mem_) {
+    return;
+  }
+
   memory_settings_checker_.RunChecks(*auto_mem_, used_cpu_memory,
                                      used_gpu_memory);
 }
@@ -1039,6 +958,11 @@
 
 render_tree::ResourceProvider* BrowserModule::GetResourceProvider() {
   if (!renderer_module_) {
+    if (resource_provider_stub_) {
+      DCHECK(application_state_ == base::kApplicationStatePreloading);
+      return &(resource_provider_stub_.value());
+    }
+
     return NULL;
   }
 
@@ -1046,13 +970,14 @@
 }
 
 void BrowserModule::InitializeSystemWindow() {
+  resource_provider_stub_ = base::nullopt;
   system_window_.reset(new system_window::SystemWindow(
       event_dispatcher_, options_.requested_viewport_size));
 
   auto_mem_.reset(new memory_settings::AutoMem(
       GetViewportSize(), options_.command_line_auto_mem_settings,
       options_.build_auto_mem_settings));
-  ApplyAutoMemSettings(*auto_mem_, &options_);
+  ApplyAutoMemSettings();
 
   input_device_manager_ = input::InputDeviceManager::CreateFromWindow(
                               base::Bind(&BrowserModule::OnKeyEventProduced,
@@ -1079,7 +1004,8 @@
 #if defined(ENABLE_SCREENSHOT)
   screen_shot_writer_.reset(new ScreenShotWriter(renderer_module_->pipeline()));
 #endif  // defined(ENABLE_SCREENSHOT)
-  // TODO: Pass in dialog closure instead of system window.
+  // TODO: Pass in dialog closure instead of system window, and initialize
+  // earlier.
   h5vcc_url_handler_.reset(new H5vccURLHandler(this, system_window_.get()));
 
   media_module_ =
@@ -1087,6 +1013,113 @@
                                  options_.media_module_options);
 }
 
+void BrowserModule::UpdateFromSystemWindow() {
+  math::Size size = GetViewportSize();
+  float video_pixel_ratio = system_window_->GetVideoPixelRatio();
+#if defined(ENABLE_DEBUG_CONSOLE)
+  if (debug_console_) {
+    debug_console_->SetSize(size, video_pixel_ratio);
+  }
+#endif  // defined(ENABLE_DEBUG_CONSOLE)
+
+  if (splash_screen_) {
+    splash_screen_->SetSize(size, video_pixel_ratio);
+  }
+
+  if (web_module_) {
+    web_module_->SetCamera3D(input_device_manager_->camera_3d());
+    web_module_->SetMediaModule(media_module_.get());
+    web_module_->SetSize(size, video_pixel_ratio);
+  }
+}
+
+void BrowserModule::SuspendInternal(bool is_start) {
+  TRACE_EVENT1("cobalt::browser", "BrowserModule::SuspendInternal", "is_start",
+               is_start ? "true" : "false");
+  // First suspend all our web modules which implies that they will release
+  // their resource provider and all resources created through it.
+  if (is_start) {
+    FOR_EACH_OBSERVER(LifecycleObserver, lifecycle_observers_, Prestart());
+  } else {
+    FOR_EACH_OBSERVER(LifecycleObserver, lifecycle_observers_, Suspend());
+  }
+
+  // Flush out any submitted render trees pushed since we started shutting down
+  // the web modules above.
+  render_tree_submission_queue_.ProcessAll();
+
+#if defined(ENABLE_SCREENSHOT)
+  // The screenshot writer may be holding on to a reference to a render tree
+  // which could in turn be referencing resources like images, so clear that
+  // out.
+  if (screen_shot_writer_) {
+    screen_shot_writer_->ClearLastPipelineSubmission();
+  }
+#endif
+
+  // Clear out the render tree combiner so that it doesn't hold on to any
+  // render tree resources either.
+  if (render_tree_combiner_) {
+    render_tree_combiner_->Reset();
+  }
+
+#if defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
+  // Note that the following function call will leak the GPU memory allocated.
+  // This is because after renderer_module_->Suspend() is called it is no longer
+  // safe to release the GPU memory allocated.
+  //
+  // The following code can call reset() to release the allocated memory but the
+  // memory may still be used by XHR and ArrayBuffer.  As this feature is only
+  // used on platform without Resume() support, it is safer to leak the memory
+  // then to release it.
+  dom::ArrayBuffer::Allocator* allocator = array_buffer_allocator_.release();
+#endif  // defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
+
+  if (media_module_) {
+    media_module_->Suspend();
+  }
+
+  if (renderer_module_) {
+    // Place the renderer module into a suspended state where it releases all
+    // its graphical resources.
+    renderer_module_->Suspend();
+  }
+}
+
+void BrowserModule::StartOrResumeInternal(bool is_start) {
+  TRACE_EVENT1("cobalt::browser", "BrowserModule::StartOrResumeInternal",
+               "is_start", is_start ? "true" : "false");
+  render_tree::ResourceProvider* resource_provider = NULL;
+  if (!renderer_module_) {
+    InitializeSystemWindow();
+    UpdateFromSystemWindow();
+    resource_provider = GetResourceProvider();
+  } else {
+    renderer_module_->Resume();
+
+    // Note that at this point, it is probable that this resource provider is
+    // different than the one that was managed in the associated call to
+    // Suspend().
+    resource_provider = GetResourceProvider();
+
+    media_module_->Resume(resource_provider);
+  }
+
+#if defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
+  // Start() and Resume() are not supported on platforms that allocate
+  // ArrayBuffers in GPU memory.
+  NOTREACHED();
+#endif  // defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
+
+  if (is_start) {
+    FOR_EACH_OBSERVER(LifecycleObserver, lifecycle_observers_,
+                      Start(resource_provider));
+  } else {
+    FOR_EACH_OBSERVER(LifecycleObserver, lifecycle_observers_,
+                      Resume(resource_provider));
+  }
+}
+
 math::Size BrowserModule::GetViewportSize() {
   // We trust the renderer module the most, if it exists.
   if (renderer_module_) {
@@ -1111,5 +1144,48 @@
   return math::Size(1280, 720);
 }
 
+void BrowserModule::ApplyAutoMemSettings() {
+  LOG(INFO) << "\n\n" << auto_mem_->ToPrettyPrintString(SbLogIsTty()) << "\n\n";
+
+  // Web Module options.
+  options_.web_module_options.image_cache_capacity =
+      static_cast<int>(auto_mem_->image_cache_size_in_bytes()->value());
+  options_.web_module_options.remote_typeface_cache_capacity = static_cast<int>(
+      auto_mem_->remote_typeface_cache_size_in_bytes()->value());
+  options_.web_module_options.javascript_options.gc_threshold_bytes =
+      static_cast<size_t>(
+          auto_mem_->javascript_gc_threshold_in_bytes()->value());
+  if (web_module_) {
+    web_module_->SetImageCacheCapacity(
+        auto_mem_->image_cache_size_in_bytes()->value());
+    web_module_->SetRemoteTypefaceCacheCapacity(
+        auto_mem_->remote_typeface_cache_size_in_bytes()->value());
+    web_module_->SetJavascriptGcThreshold(
+        auto_mem_->javascript_gc_threshold_in_bytes()->value());
+  }
+
+  // Renderer Module options.
+  options_.renderer_module_options.skia_cache_size_in_bytes =
+      static_cast<int>(auto_mem_->skia_cache_size_in_bytes()->value());
+  options_.renderer_module_options.software_surface_cache_size_in_bytes =
+      static_cast<int>(
+          auto_mem_->software_surface_cache_size_in_bytes()->value());
+  options_.renderer_module_options.offscreen_target_cache_size_in_bytes =
+      static_cast<int>(
+          auto_mem_->offscreen_target_cache_size_in_bytes()->value());
+
+  const memory_settings::TextureDimensions skia_glyph_atlas_texture_dimensions =
+      auto_mem_->skia_atlas_texture_dimensions()->value();
+  if (skia_glyph_atlas_texture_dimensions.bytes_per_pixel() > 0) {
+    // Right now the bytes_per_pixel is assumed in the engine. Any other value
+    // is currently forbidden.
+    DCHECK_EQ(2, skia_glyph_atlas_texture_dimensions.bytes_per_pixel());
+
+    options_.renderer_module_options.skia_glyph_texture_atlas_dimensions =
+        math::Size(skia_glyph_atlas_texture_dimensions.width(),
+                   skia_glyph_atlas_texture_dimensions.height());
+  }
+}
+
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index 066aa04..fcba62b 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -43,6 +43,8 @@
 #include "cobalt/input/input_device_manager.h"
 #include "cobalt/layout/layout_manager.h"
 #include "cobalt/network/network_module.h"
+#include "cobalt/render_tree/resource_provider.h"
+#include "cobalt/render_tree/resource_provider_stub.h"
 #include "cobalt/renderer/renderer_module.h"
 #include "cobalt/storage/storage_manager.h"
 #include "cobalt/system_window/system_window.h"
@@ -268,6 +270,16 @@
   // Initializes the system window, and all components that require it.
   void InitializeSystemWindow();
 
+  // Updates all components that have already been created with information
+  // resulting from the creation of the system window.
+  void UpdateFromSystemWindow();
+
+  // Does all the steps for either a Suspend or the first half of a Start.
+  void SuspendInternal(bool is_start);
+
+  // Does all the steps for either a Resume or the second half of a Start.
+  void StartOrResumeInternal(bool is_start);
+
   // Gets a viewport size to use for now. This may change depending on the
   // current application state. While preloading, this returns the requested
   // viewport size. If there was no requested viewport size, it returns a
@@ -275,6 +287,9 @@
   // it returns the confirmed size of the window.
   math::Size GetViewportSize();
 
+  // Applies the current AutoMem settings to all applicable submodules.
+  void ApplyAutoMemSettings();
+
   // TODO:
   //     WeakPtr usage here can be avoided if BrowserModule has a thread to
   //     own where it can ensure that its tasks are all resolved when it is
@@ -326,6 +341,10 @@
   // display and graphics context to the rasterizer and rendering pipeline.
   scoped_ptr<renderer::RendererModule> renderer_module_;
 
+  // A stub implementation of ResourceProvider that can be used until a real
+  // ResourceProvider is created. Only valid in the Preloading state.
+  base::optional<render_tree::ResourceProviderStub> resource_provider_stub_;
+
   // Optional memory allocator used by ArrayBuffer.
   scoped_ptr<dom::ArrayBuffer::Allocator> array_buffer_allocator_;
 
diff --git a/src/cobalt/browser/cobalt.gyp b/src/cobalt/browser/cobalt.gyp
index d2d2f29..473f353 100644
--- a/src/cobalt/browser/cobalt.gyp
+++ b/src/cobalt/browser/cobalt.gyp
@@ -20,30 +20,23 @@
     {
       'target_name': 'cobalt',
       'type': '<(final_executable_type)',
+      'dependencies': [
+        '<(DEPTH)/cobalt/browser/browser.gyp:browser',
+      ],
       'conditions': [
         ['cobalt_enable_lib == 1', {
-            'sources': ['lib/main.cc',],
-            'all_dependent_settings': {
-              'target_conditions': [
-                ['_type=="executable" and _toolset=="target"', {
-                  'sources': [
-                    'lib/imported/main_stub.cc',
-                  ],
-                }],
-              ],
-            },
+          'sources': ['lib/main.cc',],
+          'all_dependent_settings': {
+            'target_conditions': [
+              ['_type=="executable" and _toolset=="target"', {
+                'sources': [
+                  'lib/imported/main_stub.cc',
+                ],
+              }],
+            ],
+          },
         }, {
-            'sources': ['main.cc',],
-        }],
-        ['OS=="lb_shell"', {
-          'dependencies': [
-            '<(DEPTH)/cobalt/browser/<(actual_target_arch)/platform_browser.gyp:platform_browser',
-          ],
-        }],
-        ['OS=="starboard"', {
-          'dependencies': [
-            '<(DEPTH)/cobalt/browser/starboard/platform_browser.gyp:platform_browser',
-          ],
+          'sources': ['main.cc',],
         }],
         ['cobalt_copy_test_data == 1', {
           'dependencies': [
@@ -78,18 +71,7 @@
       ],
       'dependencies': [
         'cobalt',
-      ],
-      'conditions': [
-        ['OS=="lb_shell"', {
-          'dependencies': [
-            '<(DEPTH)/cobalt/browser/<(actual_target_arch)/platform_browser.gyp:platform_browser',
-          ],
-        }],
-        ['OS=="starboard"', {
-          'dependencies': [
-            '<(DEPTH)/cobalt/browser/starboard/platform_browser.gyp:platform_browser',
-          ],
-        }],
+        '<(DEPTH)/cobalt/browser/browser.gyp:browser',
       ],
     },
     {
diff --git a/src/cobalt/browser/debug_console.h b/src/cobalt/browser/debug_console.h
index 3782f40..9ecbef5 100644
--- a/src/cobalt/browser/debug_console.h
+++ b/src/cobalt/browser/debug_console.h
@@ -63,7 +63,12 @@
   // Returns the currently set debug console visibility mode.
   int GetMode();
 
+  void SetSize(const math::Size& window_dimensions, float video_pixel_ratio) {
+    web_module_->SetSize(window_dimensions, video_pixel_ratio);
+  }
+
   // LifecycleObserver implementation.
+  void Prestart() OVERRIDE { web_module_->Prestart(); }
   void Start(render_tree::ResourceProvider* resource_provider) OVERRIDE {
     web_module_->Start(resource_provider);
   }
diff --git a/src/cobalt/browser/lib/main.cc b/src/cobalt/browser/lib/main.cc
index 5d0fb44..13657ee 100644
--- a/src/cobalt/browser/lib/main.cc
+++ b/src/cobalt/browser/lib/main.cc
@@ -17,7 +17,6 @@
 #include "cobalt/base/wrap_main.h"
 #include "cobalt/browser/application.h"
 #include "cobalt/browser/lib/imported/main.h"
-#include "cobalt/browser/starboard/event_handler.h"
 #include "starboard/event.h"
 #include "starboard/input.h"
 
@@ -25,11 +24,24 @@
 
 cobalt::browser::Application* g_application = NULL;
 
+void PreloadApplication(int /*argc*/, char** /*argv*/, const char* /*link*/,
+                        const base::Closure& quit_closure) {
+  DCHECK(!g_application);
+  g_application =
+      new cobalt::browser::Application(quit_closure, true /*should_preload*/);
+  DCHECK(g_application);
+}
+
 void StartApplication(int /*argc*/, char** /*argv*/, const char* /*link*/,
                       const base::Closure& quit_closure) {
-  DCHECK(!g_application);
   LOG(INFO) << "Starting application!";
-  g_application = cobalt::browser::CreateApplication(quit_closure).release();
+  if (!g_application) {
+    g_application = new cobalt::browser::Application(quit_closure,
+                                                     false /*should_preload*/);
+    DCHECK(g_application);
+  } else {
+    g_application->Start();
+  }
   DCHECK(g_application);
   CbLibOnCobaltInitialized();
 }
@@ -41,14 +53,15 @@
   g_application = NULL;
 }
 
-void HandleEvent(const SbEvent* starboard_event) {
+void HandleStarboardEvent(const SbEvent* starboard_event) {
+  DCHECK(starboard_event);
   if (!CbLibHandleEvent(starboard_event)) {
-    cobalt::browser::EventHandler::HandleEvent(starboard_event);
+    DCHECK(g_application);
+    g_application->HandleStarboardEvent(starboard_event);
   }
 }
 
 }  // namespace
 
-COBALT_WRAP_EVENT_MAIN(StartApplication,
-                       HandleEvent,
-                       StopApplication);
+COBALT_WRAP_MAIN(PreloadApplication, StartApplication, HandleStarboardEvent,
+                 StopApplication);
diff --git a/src/cobalt/browser/lifecycle_observer.h b/src/cobalt/browser/lifecycle_observer.h
index fb69e9e..2e1b1ec 100644
--- a/src/cobalt/browser/lifecycle_observer.h
+++ b/src/cobalt/browser/lifecycle_observer.h
@@ -24,6 +24,9 @@
 // A pure virtual interface for observers of the application lifecycle.
 class LifecycleObserver {
  public:
+  // Sent before sending Start when transitioning from Preloading to Started.
+  virtual void Prestart() = 0;
+
   // Start running visibly with the given graphics ResourceProvider, loading if
   // necessary. This represents a transition from Preloading to Started, so it
   // only makes sense if the object is in the Preloading state.
diff --git a/src/cobalt/browser/main.cc b/src/cobalt/browser/main.cc
index f237b47..f97546e 100644
--- a/src/cobalt/browser/main.cc
+++ b/src/cobalt/browser/main.cc
@@ -16,9 +16,6 @@
 #include "base/logging.h"
 #include "cobalt/base/wrap_main.h"
 #include "cobalt/browser/application.h"
-#if defined(OS_STARBOARD)
-#include "cobalt/browser/starboard/event_handler.h"
-#endif
 
 namespace {
 
@@ -27,19 +24,20 @@
 void PreloadApplication(int /*argc*/, char** /*argv*/, const char* /*link*/,
                         const base::Closure& quit_closure) {
   DCHECK(!g_application);
-  g_application = cobalt::browser::PreloadApplication(quit_closure).release();
+  g_application =
+      new cobalt::browser::Application(quit_closure, true /*should_preload*/);
   DCHECK(g_application);
 }
 
 void StartApplication(int /*argc*/, char** /*argv*/, const char* /*link*/,
                       const base::Closure& quit_closure) {
   if (!g_application) {
-    g_application = cobalt::browser::CreateApplication(quit_closure).release();
+    g_application = new cobalt::browser::Application(quit_closure,
+                                                     false /*should_preload*/);
+    DCHECK(g_application);
   } else {
     g_application->Start();
   }
-
-  DCHECK(g_application);
 }
 
 void StopApplication() {
@@ -48,11 +46,17 @@
   g_application = NULL;
 }
 
+void HandleStarboardEvent(const SbEvent* starboard_event) {
+  DCHECK(starboard_event);
+  DCHECK(g_application);
+  g_application->HandleStarboardEvent(starboard_event);
+}
+
 }  // namespace
 
 #if defined(OS_STARBOARD)
-COBALT_WRAP_MAIN(PreloadApplication, StartApplication,
-                 cobalt::browser::EventHandler::HandleEvent, StopApplication);
+COBALT_WRAP_MAIN(PreloadApplication, StartApplication, HandleStarboardEvent,
+                 StopApplication);
 #else
 COBALT_WRAP_BASE_MAIN(StartApplication, StopApplication);
 #endif
diff --git a/src/cobalt/browser/memory_tracker/tool.cc b/src/cobalt/browser/memory_tracker/tool.cc
index 5083f99..9a95e1b 100644
--- a/src/cobalt/browser/memory_tracker/tool.cc
+++ b/src/cobalt/browser/memory_tracker/tool.cc
@@ -121,6 +121,24 @@
   std::string arg_str = command_arg.substr(begin_idx, length);
   return arg_str;
 }
+
+struct DisableMemoryTrackerInScope {
+  explicit DisableMemoryTrackerInScope(MemoryTracker* tracker)
+      : tracker_(tracker) {
+    if (tracker_) {
+      tracker_->SetMemoryTrackingEnabled(false);
+    }
+  }
+
+  ~DisableMemoryTrackerInScope() {
+    if (tracker_) {
+      tracker_->SetMemoryTrackingEnabled(true);
+    }
+  }
+
+  MemoryTracker* tracker_;
+};
+
 }  // namespace.
 
 class MemoryTrackerThreadImpl : public Tool {
@@ -307,6 +325,7 @@
       // Time until output is triggered.
       int sampling_time_ms = F::ToMilliseconds(num_mins);
       // Create a thread that will gather memory metrics for startup.
+      DisableMemoryTrackerInScope disable_in_scope(memory_tracker);
       tool_ptr.reset(new PrintCSVTool(sampling_interval_ms, sampling_time_ms));
       break;
     }
@@ -314,6 +333,7 @@
       memory_tracker = MemoryTracker::Get();
       memory_tracker->InstallGlobalTrackingHooks();
       // Create a thread that will continuously report memory use.
+      DisableMemoryTrackerInScope disable_in_scope(memory_tracker);
       tool_ptr.reset(new PrintTool);
       break;
     }
@@ -321,12 +341,14 @@
       memory_tracker = MemoryTracker::Get();
       memory_tracker->InstallGlobalTrackingHooks();
       // Create a thread that will continuously report memory use.
+      DisableMemoryTrackerInScope disable_in_scope(memory_tracker);
       tool_ptr.reset(new CompressedTimeSeriesTool);
       break;
     }
     case kBinnerAnalytics: {
       memory_tracker = MemoryTracker::Get();
       memory_tracker->InstallGlobalTrackingHooks();
+      DisableMemoryTrackerInScope disable_in_scope(memory_tracker);
       // Create a thread that will continuously report javascript memory
       // analytics.
       tool_ptr.reset(new MemorySizeBinnerTool(tool_arg));
@@ -368,6 +390,7 @@
   }
 
   if (tool_ptr.get()) {
+    DisableMemoryTrackerInScope disable_in_scope(memory_tracker);
     base::SimpleThread* thread =
         new ToolThread(memory_tracker,  // May be NULL.
                        tool_ptr.release(), new SbLogger);
diff --git a/src/cobalt/browser/memory_tracker/tool/tool_impl_test.cc b/src/cobalt/browser/memory_tracker/tool/tool_impl_test.cc
index 1a963e9..b5a59e9 100644
--- a/src/cobalt/browser/memory_tracker/tool/tool_impl_test.cc
+++ b/src/cobalt/browser/memory_tracker/tool/tool_impl_test.cc
@@ -73,7 +73,7 @@
 
   // Expect data.
   found = (csv_string.find("2,1") != std::string::npos);
-  SbMemoryFree(dummy_memory);
+  SbMemoryDeallocate(dummy_memory);
 }
 
 // Tests the expectation that AllocationSizeBinner will correctly bin
diff --git a/src/cobalt/browser/memory_tracker/tool/tool_thread.cc b/src/cobalt/browser/memory_tracker/tool/tool_thread.cc
index 23ce566..a6e4a27 100644
--- a/src/cobalt/browser/memory_tracker/tool/tool_thread.cc
+++ b/src/cobalt/browser/memory_tracker/tool/tool_thread.cc
@@ -65,6 +65,10 @@
 }
 
 ToolThread::~ToolThread() {
+  nb::analytics::MemoryTracker* memory_tracker = params_->memory_tracker();
+  if (memory_tracker) {
+    memory_tracker->SetMemoryTrackerDebugCallback(nullptr);
+  }
   Join();
   tool_.reset();
   params_.reset();
diff --git a/src/cobalt/browser/screen_shot_writer.cc b/src/cobalt/browser/screen_shot_writer.cc
index 00ecfc8..e534c76 100644
--- a/src/cobalt/browser/screen_shot_writer.cc
+++ b/src/cobalt/browser/screen_shot_writer.cc
@@ -41,8 +41,8 @@
 
   // No conversion needed here, simply write out the pixels as is.
   return EncodeRGBAToBuffer(static_cast<uint8_t*>(bitmap.pixelRef()->pixels()),
-                            bitmap.width(), bitmap.height(), bitmap.rowBytes(),
-                            out_num_bytes);
+                            bitmap.width(), bitmap.height(),
+                            static_cast<int>(bitmap.rowBytes()), out_num_bytes);
 }
 }  // namespace
 
@@ -107,8 +107,9 @@
                                         size_t num_bytes) {
   DCHECK_EQ(MessageLoop::current(), screenshot_thread_.message_loop());
   // Blocking write to output_path.
-  int bytes_written = file_util::WriteFile(
-      output_path, reinterpret_cast<char*>(png_data.get()), num_bytes);
+  int bytes_written =
+      file_util::WriteFile(output_path, reinterpret_cast<char*>(png_data.get()),
+                           static_cast<int>(num_bytes));
   DLOG_IF(ERROR, bytes_written != num_bytes) << "Error writing PNG to file.";
 
   // Notify the caller that the screenshot is complete.
diff --git a/src/cobalt/browser/snapshot_app_stats.cc b/src/cobalt/browser/snapshot_app_stats.cc
index 0b83f02..aa502ab 100644
--- a/src/cobalt/browser/snapshot_app_stats.cc
+++ b/src/cobalt/browser/snapshot_app_stats.cc
@@ -141,7 +141,8 @@
       cobalt::browser::switches::kDebugConsoleMode, "off");
 
   // Create the application object just like is done in the Cobalt main app.
-  g_application = cobalt::browser::CreateApplication(quit_closure).release();
+  g_application =
+      new cobalt::browser::Application(quit_closure, false /*should_preload*/);
 
   // Create a thread to start a timer for kSecondsToWait seconds after which
   // we will take a snapshot of the CVals at that time and then quit the
diff --git a/src/cobalt/browser/splash_screen.h b/src/cobalt/browser/splash_screen.h
index e775e2a..1780bd5 100644
--- a/src/cobalt/browser/splash_screen.h
+++ b/src/cobalt/browser/splash_screen.h
@@ -41,7 +41,12 @@
                float layout_refresh_rate, const GURL& url);
   ~SplashScreen();
 
+  void SetSize(const math::Size& window_dimensions, float video_pixel_ratio) {
+    web_module_->SetSize(window_dimensions, video_pixel_ratio);
+  }
+
   // LifecycleObserver implementation.
+  void Prestart() OVERRIDE { web_module_->Prestart(); }
   void Start(render_tree::ResourceProvider* resource_provider) OVERRIDE {
     web_module_->Start(resource_provider);
   }
diff --git a/src/cobalt/browser/starboard/application.cc b/src/cobalt/browser/starboard/application.cc
deleted file mode 100644
index 1c3e5fe..0000000
--- a/src/cobalt/browser/starboard/application.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2015 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cobalt/browser/application.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "cobalt/browser/starboard/event_handler.h"
-#include "starboard/system.h"
-
-namespace cobalt {
-namespace browser {
-
-class ApplicationStarboard : public Application {
- public:
-  ApplicationStarboard(const base::Closure& quit_closure, bool should_preload)
-      : Application(quit_closure, should_preload),
-        event_handler_(&event_dispatcher_) {}
-
- private:
-  // Event handler to receive Starboard events, convert to Cobalt events
-  // and dispatch to the rest of the system.
-  EventHandler event_handler_;
-};
-
-scoped_ptr<Application> CreateApplication(const base::Closure& quit_closure) {
-  return scoped_ptr<Application>(
-      new ApplicationStarboard(quit_closure, false /*should_preload*/));
-}
-
-scoped_ptr<Application> PreloadApplication(const base::Closure& quit_closure) {
-  return scoped_ptr<Application>(
-      new ApplicationStarboard(quit_closure, true /*should_preload*/));
-}
-
-}  // namespace browser
-}  // namespace cobalt
diff --git a/src/cobalt/browser/starboard/event_handler.cc b/src/cobalt/browser/starboard/event_handler.cc
deleted file mode 100644
index dab7e1b..0000000
--- a/src/cobalt/browser/starboard/event_handler.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cobalt/browser/starboard/event_handler.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "cobalt/base/accessibility_settings_changed_event.h"
-#include "cobalt/base/application_event.h"
-#include "cobalt/base/deep_link_event.h"
-#include "cobalt/network/network_event.h"
-#include "cobalt/system_window/input_event.h"
-
-namespace cobalt {
-namespace browser {
-
-namespace {
-EventHandler* g_the_event_handler = NULL;
-}  // namespace
-
-EventHandler::EventHandler(base::EventDispatcher* event_dispatcher)
-    : event_dispatcher_(event_dispatcher) {
-  DCHECK(!g_the_event_handler) << "There should be only one event handler.";
-  g_the_event_handler = this;
-}
-
-// static
-void EventHandler::HandleEvent(const SbEvent* starboard_event) {
-  DCHECK(starboard_event);
-
-  // Forward input events to |SystemWindow|.
-  if (starboard_event->type == kSbEventTypeInput) {
-    system_window::HandleInputEvent(starboard_event);
-    return;
-  }
-
-  // Handle all other events internally.
-  DCHECK(g_the_event_handler);
-  g_the_event_handler->DispatchEvent(starboard_event);
-}
-
-void EventHandler::DispatchEventInternal(base::Event* event) const {
-  event_dispatcher_->DispatchEvent(make_scoped_ptr<base::Event>(event));
-}
-
-void EventHandler::DispatchEvent(const SbEvent* starboard_event) const {
-  // Create a Cobalt event from the Starboard event, if recognized.
-  switch (starboard_event->type) {
-    case kSbEventTypePause:
-    case kSbEventTypeUnpause:
-    case kSbEventTypeSuspend:
-    case kSbEventTypeResume:
-    case kSbEventTypeStart:
-      DispatchEventInternal(new base::ApplicationEvent(starboard_event->type));
-      break;
-    case kSbEventTypeNetworkConnect:
-      DispatchEventInternal(
-          new network::NetworkEvent(network::NetworkEvent::kConnection));
-      break;
-    case kSbEventTypeNetworkDisconnect:
-      DispatchEventInternal(
-          new network::NetworkEvent(network::NetworkEvent::kDisconnection));
-      break;
-    case kSbEventTypeLink: {
-      const char* link = static_cast<const char*>(starboard_event->data);
-      DispatchEventInternal(new base::DeepLinkEvent(link));
-      break;
-    }
-#if SB_API_VERSION >= 4
-    case kSbEventTypeAccessiblitySettingsChanged:
-      DispatchEventInternal(new base::AccessibilitySettingsChangedEvent());
-      break;
-#endif  // SB_API_VERSION >= 4
-    default:
-      DLOG(WARNING) << "Unhandled Starboard event of type: "
-                    << starboard_event->type;
-  }
-}
-
-}  // namespace browser
-}  // namespace cobalt
diff --git a/src/cobalt/browser/starboard/event_handler.h b/src/cobalt/browser/starboard/event_handler.h
deleted file mode 100644
index 13391d2..0000000
--- a/src/cobalt/browser/starboard/event_handler.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef COBALT_BROWSER_STARBOARD_EVENT_HANDLER_H_
-#define COBALT_BROWSER_STARBOARD_EVENT_HANDLER_H_
-
-#include "cobalt/base/event_dispatcher.h"
-#include "starboard/event.h"
-
-namespace cobalt {
-namespace browser {
-
-class EventHandler {
- public:
-  explicit EventHandler(base::EventDispatcher* event_dispatcher);
-
-  // Static event handler called by |SbEventHandle|. Forwards input events to
-  // |system_window::HandleInputEvent| and passes all other events to
-  // |DispatchEvent|.
-  static void HandleEvent(const SbEvent* event);
-
- private:
-  // Creates a Cobalt event from a Starboard event and dispatches to the rest
-  // of the system via |event_dispatcher_|.
-  void DispatchEvent(const SbEvent* event) const;
-
-  void DispatchEventInternal(base::Event*) const;
-
-  // The event dispatcher that dispatches Cobalt events to the rest of the
-  // system.
-  base::EventDispatcher* event_dispatcher_;
-};
-
-}  // namespace browser
-}  // namespace cobalt
-
-#endif  // COBALT_BROWSER_STARBOARD_EVENT_HANDLER_H_
diff --git a/src/cobalt/browser/starboard/platform_browser.gyp b/src/cobalt/browser/starboard/platform_browser.gyp
deleted file mode 100644
index 13e5af6..0000000
--- a/src/cobalt/browser/starboard/platform_browser.gyp
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2015 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-{
-  'targets': [
-    {
-      'target_name': 'platform_browser',
-      'type': 'static_library',
-      'sources': [
-        'application.cc',
-        'event_handler.cc',
-        'event_handler.h',
-      ],
-      'dependencies': [
-        '<(DEPTH)/cobalt/browser/browser.gyp:browser',
-      ],
-      'export_dependent_settings': [
-        '<(DEPTH)/cobalt/browser/browser.gyp:browser',
-      ],
-    },
-  ],
-}
diff --git a/src/cobalt/browser/switches.cc b/src/cobalt/browser/switches.cc
index 2c107df..2c39eed 100644
--- a/src/cobalt/browser/switches.cc
+++ b/src/cobalt/browser/switches.cc
@@ -102,7 +102,8 @@
 extern const char kVideoDecoderStub[] = "video_decoder_stub";
 
 // Enable text-to-speech functionality, for platforms that implement the speech
-// synthesis API.
+// synthesis API. If the platform doesn't have speech synthesis, TTSLogger will
+// be used instead.
 const char kUseTTS[] = "use_tts";
 
 // Port that the WebDriver server should be listening on.
diff --git a/src/cobalt/browser/testdata/deep-link-demo/deep-link-demo.html b/src/cobalt/browser/testdata/deep-link-demo/deep-link-demo.html
new file mode 100644
index 0000000..a99d33d
--- /dev/null
+++ b/src/cobalt/browser/testdata/deep-link-demo/deep-link-demo.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script type="text/javascript">
+    console.log("h5vcc.runtime.initialDeepLink: " +
+                h5vcc.runtime.initialDeepLink);
+
+    h5vcc.runtime.onDeepLink = function(link) {
+      console.log("h5vcc.runtime.onDeepLink: " + link);
+    };
+  </script>
+</head>
+<body style="background-color:#48C"></body>
+</html>
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 48094a9..8a4b237 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -152,6 +152,11 @@
 #endif  // ENABLE_DEBUG_CONSOLE
 
   void SetSize(math::Size window_dimensions, float video_pixel_ratio);
+  void SetCamera3D(const scoped_refptr<input::Camera3D>& camera_3d);
+  void SetMediaModule(media::MediaModule* media_module);
+  void SetImageCacheCapacity(int64_t bytes);
+  void SetRemoteTypefaceCacheCapacity(int64_t bytes);
+  void SetJavascriptGcThreshold(int64_t bytes);
 
   // Sets the application state, asserts preconditions to transition to that
   // state, and dispatches any precipitate web events.
@@ -160,7 +165,10 @@
   // Suspension of the WebModule is a two-part process since a message loop
   // gap is needed in order to give a chance to handle loader callbacks
   // that were initiated from a loader thread.
-  void SuspendLoaders();
+  //
+  // If |update_application_state| is false, then SetApplicationState will not
+  // be called, and no state transition events will be generated.
+  void SuspendLoaders(bool update_application_state);
   void FinishSuspend();
 
   // See LifecycleObserver. These functions do not implement the interface, but
@@ -213,6 +221,9 @@
   // Handle queued pointer events. Called by LayoutManager on_layout callback.
   void HandlePointerEvents();
 
+  // Initializes the ResourceProvider and dependent resources.
+  void SetResourceProvider(render_tree::ResourceProvider* resource_provider);
+
   // Thread checker ensures all calls to the WebModule are made from the same
   // thread that it is created in.
   base::ThreadChecker thread_checker_;
@@ -455,7 +466,6 @@
   media_source_registry_.reset(new dom::MediaSource::Registry);
 
   media_session_client_ = media_session::MediaSessionClient::Create();
-
   window_ = new dom::Window(
       data.window_dimensions.width(), data.window_dimensions.height(),
       data.video_pixel_ratio, data.initial_application_state, css_parser_.get(),
@@ -605,7 +615,7 @@
 
   web_module_stat_tracker_->OnEndInjectEvent(
       window_->HasPendingAnimationFrameCallbacks(),
-      layout_manager_->IsNewRenderTreePending());
+      layout_manager_->IsRenderTreePending());
 }
 
 void WebModule::Impl::InjectKeyboardEvent(scoped_refptr<dom::Element> element,
@@ -663,7 +673,7 @@
   // Notify the stat tracker that the animation frame callbacks have finished.
   // This may end the current event being tracked.
   web_module_stat_tracker_->OnRanAnimationFrameCallbacks(
-      layout_manager_->IsNewRenderTreePending());
+      layout_manager_->IsRenderTreePending());
 }
 
 void WebModule::Impl::OnRenderTreeProduced(
@@ -761,20 +771,57 @@
   }
 }
 
-void WebModule::Impl::SetSize(math::Size /*window_dimensions*/,
-                              float /*video_pixel_ratio*/) {
-  NOTIMPLEMENTED();
+void WebModule::Impl::SetImageCacheCapacity(int64_t bytes) {
+  image_cache_->SetCapacity(static_cast<uint32>(bytes));
+}
+
+void WebModule::Impl::SetRemoteTypefaceCacheCapacity(int64_t bytes) {
+  remote_typeface_cache_->SetCapacity(static_cast<uint32>(bytes));
+}
+
+void WebModule::Impl::SetJavascriptGcThreshold(int64_t bytes) {
+  javascript_engine_->SetGcThreshold(bytes);
+}
+
+void WebModule::Impl::SetSize(math::Size window_dimensions,
+                              float video_pixel_ratio) {
+  window_->SetSize(window_dimensions.width(), window_dimensions.height(),
+                   video_pixel_ratio);
+}
+
+void WebModule::Impl::SetCamera3D(
+    const scoped_refptr<input::Camera3D>& camera_3d) {
+  window_->SetCamera3D(camera_3d);
+}
+
+void WebModule::Impl::SetMediaModule(media::MediaModule* media_module) {
+  window_->set_can_play_type_handler(media_module);
+  window_->set_web_media_player_factory(media_module);
+  environment_settings_->set_media_module(media_module);
+  environment_settings_->set_can_play_type_handler(media_module);
 }
 
 void WebModule::Impl::SetApplicationState(base::ApplicationState state) {
   window_->SetApplicationState(state);
 }
 
+void WebModule::Impl::SetResourceProvider(
+    render_tree::ResourceProvider* resource_provider) {
+  resource_provider_ = resource_provider;
+  if (resource_provider_) {
+    loader_factory_->Resume(resource_provider_);
+
+    // Permit render trees to be generated again.  Layout will have been
+    // invalidated with the call to Suspend(), so the layout manager's first
+    // task will be to perform a full re-layout.
+    layout_manager_->Resume();
+  }
+}
+
 void WebModule::Impl::Start(render_tree::ResourceProvider* resource_provider) {
   TRACE_EVENT0("cobalt::browser", "WebModule::Impl::Start()");
+  SetResourceProvider(resource_provider);
   SetApplicationState(base::kApplicationStateStarted);
-  // TODO: Initialize resource provider here rather than constructor.
-  DCHECK(resource_provider == resource_provider_);
 }
 
 void WebModule::Impl::Pause() {
@@ -787,10 +834,12 @@
   SetApplicationState(base::kApplicationStateStarted);
 }
 
-void WebModule::Impl::SuspendLoaders() {
+void WebModule::Impl::SuspendLoaders(bool update_application_state) {
   TRACE_EVENT0("cobalt::browser", "WebModule::Impl::SuspendLoaders()");
 
-  SetApplicationState(base::kApplicationStateSuspended);
+  if (update_application_state) {
+    SetApplicationState(base::kApplicationStateSuspended);
+  }
 
   // Purge the resource caches before running any suspend logic. This will force
   // any pending callbacks that the caches are batching to run.
@@ -840,18 +889,7 @@
 
 void WebModule::Impl::Resume(render_tree::ResourceProvider* resource_provider) {
   TRACE_EVENT0("cobalt::browser", "WebModule::Impl::Resume()");
-  DCHECK(resource_provider);
-  DCHECK(!resource_provider_);
-
-  resource_provider_ = resource_provider;
-
-  loader_factory_->Resume(resource_provider_);
-
-  // Permit render trees to be generated again.  Layout will have been
-  // invalidated with the call to Suspend(), so the layout manager's first task
-  // will be to perform a full re-layout.
-  layout_manager_->Resume();
-
+  SetResourceProvider(resource_provider);
   SetApplicationState(base::kApplicationStatePaused);
 }
 
@@ -1110,6 +1148,55 @@
                  window_dimensions, video_pixel_ratio));
 }
 
+void WebModule::SetCamera3D(const scoped_refptr<input::Camera3D>& camera_3d) {
+  message_loop()->PostTask(
+      FROM_HERE, base::Bind(&WebModule::Impl::SetCamera3D,
+                            base::Unretained(impl_.get()), camera_3d));
+}
+
+void WebModule::SetMediaModule(media::MediaModule* media_module) {
+  message_loop()->PostTask(
+      FROM_HERE, base::Bind(&WebModule::Impl::SetMediaModule,
+                            base::Unretained(impl_.get()), media_module));
+}
+
+void WebModule::SetImageCacheCapacity(int64_t bytes) {
+  message_loop()->PostTask(FROM_HERE,
+                           base::Bind(&WebModule::Impl::SetImageCacheCapacity,
+                                      base::Unretained(impl_.get()), bytes));
+}
+
+void WebModule::SetRemoteTypefaceCacheCapacity(int64_t bytes) {
+  message_loop()->PostTask(
+      FROM_HERE, base::Bind(&WebModule::Impl::SetRemoteTypefaceCacheCapacity,
+                            base::Unretained(impl_.get()), bytes));
+}
+
+void WebModule::SetJavascriptGcThreshold(int64_t bytes) {
+  message_loop()->PostTask(
+      FROM_HERE, base::Bind(&WebModule::Impl::SetJavascriptGcThreshold,
+                            base::Unretained(impl_.get()), bytes));
+}
+
+void WebModule::Prestart() {
+  // Must only be called by a thread external from the WebModule thread.
+  DCHECK_NE(MessageLoop::current(), message_loop());
+
+  // We must block here so that we don't queue the finish until after
+  // SuspendLoaders has run to completion, and therefore has already queued any
+  // precipitate tasks.
+  message_loop()->PostBlockingTask(
+      FROM_HERE, base::Bind(&WebModule::Impl::SuspendLoaders,
+                            base::Unretained(impl_.get()),
+                            false /*update_application_state*/));
+
+  // We must block here so that the call doesn't return until the web
+  // application has had a chance to process the whole event.
+  message_loop()->PostBlockingTask(FROM_HERE,
+                                   base::Bind(&WebModule::Impl::FinishSuspend,
+                                              base::Unretained(impl_.get())));
+}
+
 void WebModule::Start(render_tree::ResourceProvider* resource_provider) {
   // Must only be called by a thread external from the WebModule thread.
   DCHECK_NE(MessageLoop::current(), message_loop());
@@ -1117,9 +1204,8 @@
   // We must block here so that the call doesn't return until the web
   // application has had a chance to process the whole event.
   message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&WebModule::Impl::Start, base::Unretained(impl_.get()),
-                 base::Unretained(resource_provider)));
+      FROM_HERE, base::Bind(&WebModule::Impl::Start,
+                            base::Unretained(impl_.get()), resource_provider));
 }
 
 void WebModule::Pause() {
@@ -1151,9 +1237,10 @@
   // We must block here so that we don't queue the finish until after
   // SuspendLoaders has run to completion, and therefore has already queued any
   // precipitate tasks.
-  message_loop()->PostBlockingTask(FROM_HERE,
-                                   base::Bind(&WebModule::Impl::SuspendLoaders,
-                                              base::Unretained(impl_.get())));
+  message_loop()->PostBlockingTask(
+      FROM_HERE, base::Bind(&WebModule::Impl::SuspendLoaders,
+                            base::Unretained(impl_.get()),
+                            true /*update_application_state*/));
 
   // We must block here so that the call doesn't return until the web
   // application has had a chance to process the whole event.
@@ -1189,7 +1276,7 @@
       }
       topmost_event_target_->MaybeSendPointerEvents(event);
     }
-  } while (event && !layout_manager_->IsNewRenderTreePending());
+  } while (event && !layout_manager_->IsRenderTreePending());
 }
 
 }  // namespace browser
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index 47c22ee..ad3ab1e 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -239,7 +239,14 @@
   // not different from the current parameters.
   void SetSize(const math::Size& window_dimensions, float video_pixel_ratio);
 
+  void SetCamera3D(const scoped_refptr<input::Camera3D>& camera_3d);
+  void SetMediaModule(media::MediaModule* media_module);
+  void SetImageCacheCapacity(int64_t bytes);
+  void SetRemoteTypefaceCacheCapacity(int64_t bytes);
+  void SetJavascriptGcThreshold(int64_t bytes);
+
   // LifecycleObserver implementation
+  void Prestart() OVERRIDE;
   void Start(render_tree::ResourceProvider* resource_provider) OVERRIDE;
   void Pause() OVERRIDE;
   void Unpause() OVERRIDE;
diff --git a/src/cobalt/browser/win/application.cc b/src/cobalt/browser/win/application.cc
deleted file mode 100644
index fb88256..0000000
--- a/src/cobalt/browser/win/application.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cobalt/browser/application.h"
-
-namespace cobalt {
-namespace browser {
-
-class ApplicationWin : public Application {
- public:
-  explicit ApplicationWin(const base::Closure& quit_closure)
-      : Application(quit_closure) {}
-  ~ApplicationWin() OVERRIDE {}
-};
-
-scoped_ptr<Application> CreateApplication(const base::Closure& quit_closure) {
-  return scoped_ptr<Application>(new ApplicationWin(quit_closure));
-}
-
-}  // namespace browser
-}  // namespace cobalt
diff --git a/src/cobalt/browser/win/platform_browser.gyp b/src/cobalt/browser/win/platform_browser.gyp
deleted file mode 100644
index cd002f7..0000000
--- a/src/cobalt/browser/win/platform_browser.gyp
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2015 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-{
-  'targets': [
-    {
-      'target_name': 'platform_browser',
-      'type': 'static_library',
-      'sources': [
-        'application.cc',
-      ],
-      'dependencies': [
-        '<(DEPTH)/cobalt/browser/browser.gyp:browser',
-      ],
-    },
-  ],
-}
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index d7461cb..58c7a27 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-78263
\ No newline at end of file
+81256
\ No newline at end of file
diff --git a/src/cobalt/build/build_config.h b/src/cobalt/build/build_config.h
new file mode 100644
index 0000000..bfe3df5
--- /dev/null
+++ b/src/cobalt/build/build_config.h
@@ -0,0 +1,53 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_BUILD_BUILD_CONFIG_H_
+#define COBALT_BUILD_BUILD_CONFIG_H_
+
+#if COBALT_MEDIA_BUFFER_INITIAL_CAPACITY < 0
+#error cobalt_media_buffer_initial_capacity has to be greater than or equal to 0
+#endif  // COBALT_MEDIA_BUFFER_INITIAL_CAPACITY < 0
+
+#if COBALT_MEDIA_BUFFER_ALLOCATION_UNIT < 0
+#error cobalt_media_buffer_allocation_unit has to be greater than or equal to 0
+#endif  // COBALT_MEDIA_BUFFER_ALLOCATION_UNIT < 0
+
+#if COBALT_MEDIA_BUFFER_ALIGNMENT < 0
+#error "cobalt_media_buffer_alignment has to be greater than or equal to 0."
+#endif  // COBALT_MEDIA_BUFFER_ALIGNMENT < 0
+
+#if COBALT_MEDIA_BUFFER_PADDING < 0
+#error "cobalt_media_buffer_padding has to be greater than or equal to 0."
+#endif  // COBALT_MEDIA_BUFFER_PADDING < 0
+
+#if COBALT_MEDIA_BUFFER_PROGRESSIVE_BUDGET < 8 * 1024 * 1024
+#error cobalt_media_buffer_progressive_budget has to be greater than or equal \
+           to 8 MB.
+#endif  // COBALT_MEDIA_BUFFER_PROGRESSIVE_BUDGET < 0
+
+#if COBALT_MEDIA_BUFFER_NON_VIDEO_BUDGET <= 0
+#error "cobalt_media_buffer_non_video_budget has to be greater than 0."
+#endif  // COBALT_MEDIA_BUFFER_NON_VIDEO_BUDGET < 0
+
+#if COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P <= 0
+#error "cobalt_media_buffer_video_budget_1080p has to be greater than 0."
+#endif  // COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P < 0
+
+#if COBALT_MEDIA_BUFFER_VIDEO_BUDGET_4K < COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P
+#error cobalt_media_buffer_video_budget_4k has to be greater than or equal to \
+           cobalt_media_buffer_video_budget_1080p.
+#endif  // COBALT_MEDIA_BUFFER_VIDEO_BUDGET_4K <
+        //     COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P
+
+#endif  // COBALT_BUILD_BUILD_CONFIG_H_
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index 439781f..96d4005 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -135,11 +135,6 @@
     'cobalt_version%': 0,
     # Contains the name of the hosting OS. The value is defined by gyp_cobalt.
     'host_os%': 'win',
-    # The "real" target_arch that is used to select the correct delegate source.
-    # TODO: Investigate why adding % will break the build on platforms
-    # other than Windows
-    # TODO: Remove after starboard.
-    'actual_target_arch': '<(target_arch)',
 
     # The target platform id as a string, like 'ps3', 'ps4', etc..
     'sb_target_platform': '',
@@ -229,9 +224,6 @@
     # Used by cobalt/media/media.gyp to pick a proper media platform.
     'sb_media_platform%': 'starboard',
 
-    # Needed for backwards compatibility with lbshell code.
-    'lbshell_root%': '<(DEPTH)/lbshell',
-
     # The relative path from src/ to the directory containing the
     # starboard_platform.gyp file.  It is currently set to
     # 'starboard/<(target_arch)' to make semi-starboard platforms work.
@@ -436,7 +428,6 @@
 
     'platform_libraries%': [],
 
-
     # The only currently-supported Javascript engine is 'mozjs-45'.
     # TODO: Figure out how to massage gyp the right way to make this work
     # as expected, rather than requiring it to be set for each platform.
@@ -456,7 +447,7 @@
 
     # Use media source extension implementation that is conformed to the
     # Candidate Recommandation of July 5th 2016.
-    'cobalt_media_source_2016%': 0,
+    'cobalt_media_source_2016%': 1,
 
     # Note that the following media buffer related variables are only used when
     # |cobalt_media_source_2016| is set to 1.
@@ -469,18 +460,43 @@
     # value is "file" the media stack will still allocate memory to cache the
     # the buffers in use.
     'cobalt_media_buffer_storage_type%': 'memory',
+    # When either |cobalt_media_buffer_initial_capacity| or
+    # |cobalt_media_buffer_allocation_unit| isn't zero, media buffers will be
+    # allocated using a memory pool.  Set the following variable to 1 to
+    # allocate the media buffer pool memory on demand and return all memory to
+    # the system when there is no media buffer allocated.  Setting the following
+    # value to 0 results in that Cobalt will allocate
+    # |cobalt_media_buffer_initial_capacity| bytes for media buffer on startup
+    # and will not release any media buffer memory back to the system even if
+    # there is no media buffers allocated.
+    'cobalt_media_buffer_pool_allocate_on_demand%': 1,
     # The amount of memory that will be used to store media buffers allocated
     # during system startup.  To allocate a large chunk at startup helps with
-    # reducing frafmentation and can avoid failures to allocate incrementally.
+    # reducing fragmentation and can avoid failures to allocate incrementally.
     # This can be set to 0.
-    'cobalt_media_buffer_initial_capacity%': 0 * 1024 * 1024,
+    'cobalt_media_buffer_initial_capacity%': 21 * 1024 * 1024,
     # When the media stack needs more memory to store media buffers, it will
     # allocate extra memory in units of |cobalt_media_buffer_allocation_unit|.
     # This can be set to 0, in which case the media stack will allocate extra
     # memory on demand.  When |cobalt_media_buffer_initial_capacity| and this
     # value are both set to 0, the media stack will allocate individual buffers
     # directly using SbMemory functions.
-    'cobalt_media_buffer_allocation_unit%': 0 * 1024 * 1024,
+    'cobalt_media_buffer_allocation_unit%': 1 * 1024 * 1024,
+
+    # The media buffer will be allocated using the following alignment.  Set
+    # this to a larger value may increase the memory consumption of media
+    # buffers.
+    'cobalt_media_buffer_alignment%': 0,
+    # Extra bytes allocated at the end of a media buffer to ensure that the
+    # buffer can be use optimally by specific instructions like SIMD.  Set to 0
+    # to remove any padding.
+    'cobalt_media_buffer_padding%': 0,
+
+    # The memory used when playing mp4 videos that is not in DASH format.  The
+    # resolution of such videos shouldn't go beyond 1080p.  Its value should be
+    # less than the sum of 'cobalt_media_buffer_non_video_budget' and
+    # 'cobalt_media_buffer_video_budget_1080p' but not less than 8 MB.
+    'cobalt_media_buffer_progressive_budget%': 12 * 1024 * 1024,
 
     # Specifies the maximum amount of memory used by audio or text buffers of
     # media source before triggering a garbage collection.  A large value will
@@ -521,11 +537,15 @@
     },
     'defines': [
       'COBALT',
+      'COBALT_MEDIA_BUFFER_POOL_ALLOCATE_ON_DEMAND=<(cobalt_media_buffer_pool_allocate_on_demand)',
+      'COBALT_MEDIA_BUFFER_INITIAL_CAPACITY=<(cobalt_media_buffer_initial_capacity)',
+      'COBALT_MEDIA_BUFFER_ALLOCATION_UNIT=<(cobalt_media_buffer_allocation_unit)',
+      'COBALT_MEDIA_BUFFER_ALIGNMENT=<(cobalt_media_buffer_alignment)',
+      'COBALT_MEDIA_BUFFER_PADDING=<(cobalt_media_buffer_padding)',
+      'COBALT_MEDIA_BUFFER_PROGRESSIVE_BUDGET=<(cobalt_media_buffer_progressive_budget)',
       'COBALT_MEDIA_BUFFER_NON_VIDEO_BUDGET=<(cobalt_media_buffer_non_video_budget)',
       'COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P=<(cobalt_media_buffer_video_budget_1080p)',
       'COBALT_MEDIA_BUFFER_VIDEO_BUDGET_4K=<(cobalt_media_buffer_video_budget_4k)',
-      'COBALT_MEDIA_BUFFER_INITIAL_CAPACITY=<(cobalt_media_buffer_initial_capacity)',
-      'COBALT_MEDIA_BUFFER_ALLOCATION_UNIT=<(cobalt_media_buffer_allocation_unit)',
     ],
     'cflags': [ '<@(compiler_flags)' ],
     'ldflags': [ '<@(linker_flags)' ],
diff --git a/src/cobalt/build/config/starboard.py b/src/cobalt/build/config/starboard.py
index 07ffc4b..ecba441 100644
--- a/src/cobalt/build/config/starboard.py
+++ b/src/cobalt/build/config/starboard.py
@@ -31,12 +31,26 @@
     return True
 
   def GetEnvironmentVariables(self):
-    raise NotImplementedError
+    return {}
 
   def GetToolchain(self):
     """Returns the instance of the toolchain implementation class."""
     return None
 
+  def GetTargetToolchain(self):
+    """Returns a list of target tools."""
+    # TODO: If this method throws |NotImplementedError|, GYP will fall back to
+    #       the legacy toolchain. Once all platforms are migrated to the
+    #       abstract toolchain, this method should be made |@abstractmethod|.
+    raise NotImplementedError()
+
+  def GetHostToolchain(self):
+    """Returns a list of host tools."""
+    # TODO: If this method throws |NotImplementedError|, GYP will fall back to
+    #       the legacy toolchain. Once all platforms are migrated to the
+    #       abstract toolchain, this method should be made |@abstractmethod|.
+    raise NotImplementedError()
+
   def GetVariables(self, config, use_clang=0):
     use_asan = 0
     use_tsan = 0
diff --git a/src/cobalt/doc/lifecycle.md b/src/cobalt/doc/lifecycle.md
new file mode 100644
index 0000000..a75d2fb
--- /dev/null
+++ b/src/cobalt/doc/lifecycle.md
@@ -0,0 +1,137 @@
+# Application Lifecycle
+
+In order to meet common needs of applications running on CE devices, Cobalt
+implements a well-defined web application lifecycle, managing resources and
+notifying the application as appropriate.
+
+## Application States
+
+Starboard Application State | Page Visibility State | Window Focused
+:-------------------------- | :-------------------- | :-------------
+*Preloading*                | prerender             | false
+*Started*                   | visible               | true
+*Paused*                    | visible               | false
+*Suspended*                 | hidden                | false
+
+### Preloading
+
+The application is not visible, and will receive no input, but is running. Only
+possible to enter as the start state. May transition to *Started* or *Suspended*
+at any time.
+
+#### Expectations for the web application
+
+Initialize as much as possible to get to an interactive state. There is no
+official signal for an application that has finished preloading.
+
+#### Expectations for the porter
+
+For applications that can be preloaded, the platform should send
+`kSbEventTypePreload` as the first Starboard event instead of
+`kSbEventTypeStart`. `src/starboard/shared/starboard/application.cc` subclasses
+can opt-in to already implemented support for the `--preload` command-line
+switch.
+
+The platform should then send `kSbEventTypeStart` when the application is first
+brought to the foreground. In Linux desktop (linux-x64x11), this can be done by
+sending a `SIGCONT` to the process that is in the *Preloading* state.
+
+If the platform wants to only give applications a certain amount of time to
+preload, they can send `kSbEventTypeSuspend` to halt preloading and move to the
+*Suspended* state. In Linux desktop, this can be done by sending SIGUSR1 to the
+process that is in the *Preloading* state.
+
+### Started
+
+The application is running, visible, and interactive. The normal foreground
+application state. May be the start state, can be entered from *Preloading*, or
+*Paused*.
+
+May only transition to *Paused*. In Linux desktop, this happens anytime the
+top-level Cobalt X11 window loses focus. Linux transition back to *Started* when
+the top-level Cobalt X11 window gains focus again.
+
+### Paused
+
+The application may be fully visible, partially visible, or completely obscured,
+but it has lost input focus, so will receive no input events. It has been
+allowed to retain all its resources for a very quick return to *Started*, and
+the application is still running. May be entered from or transition to *Started*
+or *Suspended*.
+
+### Suspended
+
+The application is not visible, and, once *Suspended*, will not run any
+code. All graphics and media resources will be revoked until resumed, so the
+application should expect all images to be lost, all caches to be cleared, and
+all network requests to be aborted. The application may be terminated in this
+state without notification.
+
+#### Expectations for the web application
+
+The application should **shut down** playback, releasing resources. On resume,
+all resources need to be reloaded, and playback should be reinitialized where it
+left off, or at the nearest key frame.
+
+#### Expectations for the porter
+
+The platform Starboard implementation **must always** send events in the
+prescribed order - meaning, for example, that it should never send a
+`kSbEventTypeSuspend` event unless in the *Preloading* or *Paused* states.
+
+Currently, Cobalt does not manually stop JavaScript execution when it goes into
+the *Suspended* state. In Linux desktop, it expects that a `SIGSTOP` will be
+raised, causing all the threads not to get any more CPU time until resumed. This
+will be fixed in a future version of Cobalt.
+
+## Implementing the Application Lifecycle (for the porter)
+
+Most porters will want to subclass either `starboard::shared::Application` (in
+`src/starboard/shared/starboard/application.cc`) or
+`starboard::shared::QueueApplication` (in
+`src/starboard/shared/starboard/queue_application.cc`), as these are reference
+classes that rigorously implement the Starboard application lifecycle. They are
+optional, and platforms can directly dispatch events to SbEventHandle(), but it
+is then up to them to ensure that events are **always** sent in the correct
+state as specified in the Starboard documentation.
+
+`starboard::shared::Application` guarantees the correct ordering by implementing
+a small state machine that ignores invalid application state transitions, and
+inserts any necessary transitions to make them valid. For example, you can call
+`starboard::shared::Application::Suspend()`, and if you are in *Paused*, it will
+just dispatch a `kSbEventTypeSuspend` event. But if you call `Suspend()` in the
+*Started* state, it will dispatch `kSbEventTypePause` and then
+`kSbEventTypeSuspend` events. If you call `Suspend()` in the *Suspended* state,
+it just does nothing.
+
+To control starting up in the *Preloading* state, `Application` subclasses must
+override two functions:
+
+``` c++
+class MyApplication : public shared::starboard::QueueApplication {
+  // [ ... ]
+  bool IsStartImmediate() SB_OVERRIDE;
+  bool IsPreloadImmediate() SB_OVERRIDE;
+  // [ ... ]
+}
+```
+
+To start up in the *Preloading* state, `IsStartImmediate()` should return
+`false` and `IsPreloadImmediate()` should return `true`.
+
+To start up in the *Starting* state (which is the default), `IsStartImmediate()`
+should return `true` and `IsPreloadImmediate()` will not be called.
+
+To delay starting up until some later event, `IsStartImmediate()` and
+`IsPreloadImmediate()` should both return `false`. No initial event will be
+automatically sent to the application, and it is then up to the porter to
+dispatch a `kSbEventTypeStart` or `kSbEventTypePreload` event as the first
+event. This is useful if you need to wait for an asynchronous system activity to
+complete before starting Cobalt.
+
+To support the `--preload` command-line argument:
+
+``` c++
+  bool IsStartImmediate() SB_OVERRIDE { return !HasPreloadSwitch(); }
+  bool IsPreloadImmediate() SB_OVERRIDE { return HasPreloadSwitch(); }
+```
diff --git a/src/cobalt/dom/blob_test.cc b/src/cobalt/dom/blob_test.cc
index 1e015a5..8b0016e 100644
--- a/src/cobalt/dom/blob_test.cc
+++ b/src/cobalt/dom/blob_test.cc
@@ -38,7 +38,7 @@
   scoped_refptr<DataView> data_view =
       new DataView(array_buffer, &exception_state);
   data_view->SetInt16(0, static_cast<int16>(0x0607), &exception_state);
-  data_view->SetInt16(3, static_cast<int16>(0xABCD), &exception_state);
+  data_view->SetInt16(3, static_cast<int16>(0x7BCD), &exception_state);
   scoped_refptr<Blob> blob_with_buffer = new Blob(NULL, array_buffer);
 
   ASSERT_EQ(5, blob_with_buffer->size());
@@ -47,7 +47,7 @@
   EXPECT_EQ(0x6, blob_with_buffer->data()[0]);
   EXPECT_EQ(0x7, blob_with_buffer->data()[1]);
   EXPECT_EQ(0, blob_with_buffer->data()[2]);
-  EXPECT_EQ(0xAB, blob_with_buffer->data()[3]);
+  EXPECT_EQ(0x7B, blob_with_buffer->data()[3]);
   EXPECT_EQ(0xCD, blob_with_buffer->data()[4]);
 
   scoped_refptr<DataView> data_view_mid_3 =
@@ -63,7 +63,7 @@
   EXPECT_EQ(0x6, blob_with_parts->data()[0]);
   EXPECT_EQ(0x7, blob_with_parts->data()[5]);
   EXPECT_EQ(0, blob_with_parts->data()[6]);
-  EXPECT_EQ(0xAB, blob_with_parts->data()[11]);
+  EXPECT_EQ(0x7B, blob_with_parts->data()[11]);
   EXPECT_EQ(0xCD, blob_with_parts->data()[12]);
 }
 
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index f0cda7e..aaa034b 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -740,6 +740,11 @@
 #endif  // defined(ENABLE_PARTIAL_LAYOUT_CONTROL)
 
 void Document::SetViewport(const math::Size& viewport_size) {
+  if (viewport_size_ && viewport_size_->width() == viewport_size.width() &&
+      viewport_size_->height() == viewport_size.height()) {
+    return;
+  }
+
   viewport_size_ = viewport_size;
   initial_computed_style_data_ = CreateInitialComputedStyle(*viewport_size_);
   initial_computed_style_declaration_->SetData(initial_computed_style_data_);
@@ -751,6 +756,8 @@
   if (current_html) {
     current_html->InvalidateComputedStylesOfNodeAndDescendants();
   }
+
+  RecordMutation();
 }
 
 Document::~Document() {
diff --git a/src/cobalt/dom/dom_settings.h b/src/cobalt/dom/dom_settings.h
index 507c723..c6b8895 100644
--- a/src/cobalt/dom/dom_settings.h
+++ b/src/cobalt/dom/dom_settings.h
@@ -101,6 +101,9 @@
   }
   network::NetworkModule* network_module() const { return network_module_; }
   media::MediaModule* media_module() const { return media_module_; }
+  void set_media_module(media::MediaModule* media_module) {
+    media_module_ = media_module;
+  }
   script::JavaScriptEngine* javascript_engine() const {
     return javascript_engine_;
   }
@@ -113,6 +116,10 @@
   media::CanPlayTypeHandler* can_play_type_handler() const {
     return can_play_type_handler_;
   }
+  void set_can_play_type_handler(
+      media::CanPlayTypeHandler* can_play_type_handler) {
+    can_play_type_handler_ = can_play_type_handler;
+  }
   MutationObserverTaskManager* mutation_observer_task_manager() const {
     return mutation_observer_task_manager_;
   }
diff --git a/src/cobalt/dom/event_target.h b/src/cobalt/dom/event_target.h
index 9af3d72..df9e286 100644
--- a/src/cobalt/dom/event_target.h
+++ b/src/cobalt/dom/event_target.h
@@ -230,6 +230,13 @@
     SetAttributeEventListener(base::Tokens::playing(), event_listener);
   }
 
+  const EventListenerScriptValue* onresize() {
+    return GetAttributeEventListener(base::Tokens::resize());
+  }
+  void set_onresize(const EventListenerScriptValue& event_listener) {
+    SetAttributeEventListener(base::Tokens::resize(), event_listener);
+  }
+
   const EventListenerScriptValue* onpointerdown() {
     return GetAttributeEventListener(base::Tokens::pointerdown());
   }
diff --git a/src/cobalt/dom/global_event_handlers.idl b/src/cobalt/dom/global_event_handlers.idl
index cdacb6b..31627a2 100644
--- a/src/cobalt/dom/global_event_handlers.idl
+++ b/src/cobalt/dom/global_event_handlers.idl
@@ -42,6 +42,8 @@
   attribute EventHandler onplay;
   attribute EventHandler onplaying;
 
+  attribute EventHandler onresize;
+
   // Extensions for the Pointer Events recommendation.
   //  https://www.w3.org/TR/2015/REC-pointerevents-20150224/#extensions-to-the-globaleventhandlers-interface
   attribute EventHandler onpointerdown;
diff --git a/src/cobalt/dom/html_element_context.h b/src/cobalt/dom/html_element_context.h
index 970bc32..d7054db 100644
--- a/src/cobalt/dom/html_element_context.h
+++ b/src/cobalt/dom/html_element_context.h
@@ -77,9 +77,17 @@
   media::CanPlayTypeHandler* can_play_type_handler() {
     return can_play_type_handler_;
   }
+  void set_can_play_type_handler(
+      media::CanPlayTypeHandler* can_play_type_handler) {
+    can_play_type_handler_ = can_play_type_handler;
+  }
   media::WebMediaPlayerFactory* web_media_player_factory() {
     return web_media_player_factory_;
   }
+  void set_web_media_player_factory(
+      media::WebMediaPlayerFactory* web_media_player_factory) {
+    web_media_player_factory_ = web_media_player_factory;
+  }
 
   script::ScriptRunner* script_runner() const { return script_runner_; }
 
@@ -135,7 +143,7 @@
   cssom::CSSParser* const css_parser_;
   Parser* const dom_parser_;
   media::CanPlayTypeHandler* can_play_type_handler_;
-  media::WebMediaPlayerFactory* const web_media_player_factory_;
+  media::WebMediaPlayerFactory* web_media_player_factory_;
   script::ScriptRunner* const script_runner_;
   script::ScriptValueFactory* const script_value_factory_;
   MediaSourceRegistry* const media_source_registry_;
diff --git a/src/cobalt/dom/node.cc b/src/cobalt/dom/node.cc
index 6db5f93..733bfd2 100644
--- a/src/cobalt/dom/node.cc
+++ b/src/cobalt/dom/node.cc
@@ -885,14 +885,14 @@
       GatherInclusiveAncestorsObservers();
   if (!observers->empty()) {
     MutationReporter mutation_reporter(this, observers.Pass());
-    scoped_refptr<dom::NodeList> added_nodes = new dom::NodeList();
+    scoped_refptr<dom::NodeList> new_added_nodes = new dom::NodeList();
     if (node) {
-      added_nodes->AppendNode(node);
+      new_added_nodes->AppendNode(node);
     }
-    if (added_nodes->length() > 0 || removed_nodes->length() > 0) {
-      mutation_reporter.ReportChildListMutation(
-          added_nodes, removed_nodes, NULL /* previous_sibling */,
-          NULL /* next_sibling */);
+    if (new_added_nodes->length() > 0 || removed_nodes->length() > 0) {
+      mutation_reporter.ReportChildListMutation(new_added_nodes, removed_nodes,
+                                                NULL /* previous_sibling */,
+                                                NULL /* next_sibling */);
     }
   }
 }
diff --git a/src/cobalt/dom/screen.h b/src/cobalt/dom/screen.h
index 1fd43ff..5118a4a 100644
--- a/src/cobalt/dom/screen.h
+++ b/src/cobalt/dom/screen.h
@@ -25,9 +25,12 @@
 //   https://www.w3.org/TR/2013/WD-cssom-view-20131217/#the-screen-interface
 class Screen : public script::Wrappable {
  public:
-  Screen(int width, int height)
-      : width_(static_cast<float>(width)),
-        height_(static_cast<float>(height)) {}
+  Screen(int width, int height) { SetSize(width, height); }
+
+  void SetSize(int width, int height) {
+    width_ = static_cast<float>(width);
+    height_ = static_cast<float>(height);
+  }
 
   // Web API
   //   https://www.w3.org/TR/2013/WD-cssom-view-20131217/#the-screen-interface
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index 856d46f..eaba14d 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -141,7 +141,6 @@
       ALLOW_THIS_IN_INITIALIZER_LIST(
           relay_on_load_event_(new RelayLoadEvent(this))),
       console_(new Console(execution_state)),
-      camera_3d_(new Camera3D(camera_3d)),
       ALLOW_THIS_IN_INITIALIZER_LIST(window_timers_(new WindowTimers(this))),
       ALLOW_THIS_IN_INITIALIZER_LIST(animation_frame_request_callback_list_(
           new AnimationFrameRequestCallbackList(this))),
@@ -161,6 +160,7 @@
 #endif
   document_->AddObserver(relay_on_load_event_.get());
   html_element_context_->page_visibility_state()->AddObserver(this);
+  SetCamera3D(camera_3d);
 
   // Document load start is deferred from this constructor so that we can be
   // guaranteed that this Window object is fully constructed before document
@@ -168,7 +168,6 @@
   MessageLoop::current()->PostTask(
       FROM_HERE, base::Bind(&Window::StartDocumentLoad, this, fetcher_factory,
                             url, dom_parser, error_callback));
-  camera_3d_->StartOrientationEvents(base::AsWeakPtr(this));
 }
 
 void Window::StartDocumentLoad(
@@ -432,6 +431,28 @@
   document_->set_synchronous_layout_callback(synchronous_layout_callback);
 }
 
+void Window::SetSize(int width, int height, float device_pixel_ratio) {
+  if (width_ == width && height_ == height &&
+      device_pixel_ratio_ == device_pixel_ratio) {
+    return;
+  }
+
+  width_ = width;
+  height_ = height;
+  device_pixel_ratio_ = device_pixel_ratio;
+  screen_->SetSize(width, height);
+
+  // This will cause layout invalidation.
+  document_->SetViewport(math::Size(width, height));
+
+  PostToDispatchEvent(FROM_HERE, base::Tokens::resize());
+}
+
+void Window::SetCamera3D(const scoped_refptr<input::Camera3D>& camera_3d) {
+  camera_3d_ = new Camera3D(camera_3d);
+  camera_3d_->StartOrientationEvents(base::AsWeakPtr(this));
+}
+
 void Window::OnWindowFocusChanged(bool has_focus) {
   DispatchEvent(
       new Event(has_focus ? base::Tokens::focus() : base::Tokens::blur()));
diff --git a/src/cobalt/dom/window.h b/src/cobalt/dom/window.h
index 1ab441c..8c669e8 100644
--- a/src/cobalt/dom/window.h
+++ b/src/cobalt/dom/window.h
@@ -30,6 +30,7 @@
 #include "cobalt/dom/csp_delegate_type.h"
 #include "cobalt/dom/dom_stat_tracker.h"
 #include "cobalt/dom/event_target.h"
+#include "cobalt/dom/html_element_context.h"
 #include "cobalt/dom/media_query_list.h"
 #include "cobalt/dom/parser.h"
 #if defined(ENABLE_TEST_RUNNER)
@@ -76,7 +77,6 @@
 class Element;
 class Event;
 class History;
-class HTMLElementContext;
 class LocalStorageDatabase;
 class Location;
 class MediaSource;
@@ -287,6 +287,21 @@
   void SetSynchronousLayoutCallback(
       const base::Closure& synchronous_layout_callback);
 
+  void SetSize(int width, int height, float device_pixel_ratio);
+
+  void SetCamera3D(const scoped_refptr<input::Camera3D>& camera_3d);
+
+  void set_can_play_type_handler(
+      media::CanPlayTypeHandler* can_play_type_handler) {
+    html_element_context_->set_can_play_type_handler(can_play_type_handler);
+  }
+
+  void set_web_media_player_factory(
+      media::WebMediaPlayerFactory* web_media_player_factory) {
+    html_element_context_->set_web_media_player_factory(
+        web_media_player_factory);
+  }
+
   // Sets the current application state, forwarding on to the
   // PageVisibilityState associated with it and its document, causing
   // precipitate events to be dispatched.
diff --git a/src/cobalt/h5vcc/h5vcc_accessibility.cc b/src/cobalt/h5vcc/h5vcc_accessibility.cc
index d6f9aec..2f9ddb7 100644
--- a/src/cobalt/h5vcc/h5vcc_accessibility.cc
+++ b/src/cobalt/h5vcc/h5vcc_accessibility.cc
@@ -28,8 +28,8 @@
 namespace h5vcc {
 
 namespace {
-#if SB_HAS(SPEECH_SYNTHESIS)
-bool IsTextToSpeechEnabled() {
+
+bool ShouldForceTextToSpeech() {
 #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   // Check for a command-line override to enable TTS.
   CommandLine* command_line = CommandLine::ForCurrentProcess();
@@ -37,6 +37,11 @@
     return true;
   }
 #endif  // defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
+  return false;
+}
+
+#if SB_HAS(SPEECH_SYNTHESIS)
+bool IsTextToSpeechEnabled() {
 #if SB_API_VERSION >= 4
   // Check if the tts feature is enabled in Starboard.
   SbAccessibilityTextToSpeechSettings tts_settings = {0};
@@ -49,6 +54,7 @@
   return false;
 }
 #endif  // SB_HAS(SPEECH_SYNTHESIS)
+
 }  // namespace
 
 H5vccAccessibility::H5vccAccessibility(
@@ -61,17 +67,22 @@
       base::AccessibilitySettingsChangedEvent::TypeId(),
       base::Bind(&H5vccAccessibility::OnApplicationEvent,
                  base::Unretained(this)));
+  if (ShouldForceTextToSpeech()) {
 #if SB_HAS(SPEECH_SYNTHESIS)
-  if (IsTextToSpeechEnabled()) {
+    // Create a StarboardTTSEngine if the platform has speech synthesis.
+    tts_engine_.reset(new accessibility::StarboardTTSEngine());
+#else
+    tts_engine_.reset(new accessibility::TTSLogger());
+#endif
+  }
+
+#if SB_HAS(SPEECH_SYNTHESIS)
+  if (!tts_engine_ && IsTextToSpeechEnabled()) {
     // Create a StarboardTTSEngine if TTS is enabled.
     tts_engine_.reset(new accessibility::StarboardTTSEngine());
   }
-#endif  // SB_HAS(SPEECH_SYNTHESIS)
-#if !defined(COBALT_BUILD_TYPE_GOLD)
-  if (!tts_engine_) {
-    tts_engine_.reset(new accessibility::TTSLogger());
-  }
-#endif  // !defined(COBALT_BUILD_TYPE_GOLD)
+#endif
+
   if (tts_engine_) {
     screen_reader_.reset(new accessibility::ScreenReader(
         window->document(), tts_engine_.get(), mutation_observer_task_manager));
diff --git a/src/cobalt/input/input.gyp b/src/cobalt/input/input.gyp
index b220f36..5a31e33 100644
--- a/src/cobalt/input/input.gyp
+++ b/src/cobalt/input/input.gyp
@@ -21,8 +21,11 @@
         'camera_3d.h',
         'create_default_camera_3d.h',
         'input_device_manager.h',
+        'input_device_manager_desktop.cc',
+        'input_device_manager_desktop.h',
         'input_device_manager_fuzzer.cc',
         'input_device_manager_fuzzer.h',
+        'input_device_manager_starboard.cc',
         'input_poller.h',
         'input_poller_impl.cc',
         'input_poller_impl.h',
@@ -40,20 +43,6 @@
         '<(DEPTH)/cobalt/system_window/system_window.gyp:system_window',
       ],
       'conditions': [
-        ['OS=="starboard"', {
-          'sources': [
-            'input_device_manager_desktop.cc',
-            'input_device_manager_desktop.h',
-            'input_device_manager_starboard.cc',
-          ],
-        }],
-        ['OS!="starboard" and actual_target_arch=="win"', {
-          'sources': [
-            'input_device_manager_<(actual_target_arch).cc',
-            'input_device_manager_desktop.cc',
-            'input_device_manager_desktop.h',
-          ],
-        }],
         ['enable_vr==1', {
           'sources': [
             'private/camera_3d_vr.cc',
diff --git a/src/cobalt/layout/container_box.cc b/src/cobalt/layout/container_box.cc
index fa33ea8..b7edf46 100644
--- a/src/cobalt/layout/container_box.cc
+++ b/src/cobalt/layout/container_box.cc
@@ -83,14 +83,14 @@
   update_size_results_valid_ = false;
 
   // Check to see if the split sibling is positioned, which means that it
-  // needs to invalidate its cross references.
-  // NOTE: Only block level and atomic inline-level elements are transformable.
-  // As these are not splittable, the split sibling does not need to be checked
-  // for being transformed.
-  // https://www.w3.org/TR/css-transforms-1/#transformable-element
-  DCHECK(!split_sibling->IsTransformable());
-  if (split_sibling->IsPositioned() || split_sibling->IsStackingContext()) {
+  // needs to invalidate its containing block's cross references.
+  bool is_positioned = split_sibling->IsPositioned();
+  if (is_positioned) {
     split_sibling->GetContainingBlock()->are_cross_references_valid_ = false;
+  }
+  // Check to see if the split sibling is a stacking context child, which means
+  // that it needs to invalidate its stacking context's cross references.
+  if (is_positioned || split_sibling->IsStackingContext()) {
     split_sibling->GetStackingContext()->are_cross_references_valid_ = false;
   }
 
@@ -153,6 +153,23 @@
       DCHECK(negative_z_index_stacking_context_children_.empty());
       GetStackingContext()->are_cross_references_valid_ = false;
     }
+  } else if (computed_style()->overflow().get() ==
+                 cssom::KeywordValue::GetHidden() &&
+             !IsStackingContext()) {
+    // If this container box hides overflow and isn't a stacking context, then
+    // the nearest ancestor that is a stacking context needs to be invalidated.
+    // The reason for this is that the ancestor stacking context may have
+    // stacking context children that include this container as an overflow
+    // hidden containing block.
+    // NOTE: GetStackingContext() can't simply be called, because that will
+    // incorrectly return the parent, regardless of whether or not it is a
+    // stacking context, in the case where the containing block is not
+    // positioned.
+    ContainerBox* stacking_context_ancestor = parent();
+    while (!stacking_context_ancestor->IsStackingContext()) {
+      stacking_context_ancestor = stacking_context_ancestor->parent();
+    }
+    stacking_context_ancestor->are_cross_references_valid_ = false;
   }
 
   // Invalidate the render tree nodes now that the children have changed.
diff --git a/src/cobalt/layout/layout.cc b/src/cobalt/layout/layout.cc
index 98c2d6d..1a9fb07 100644
--- a/src/cobalt/layout/layout.cc
+++ b/src/cobalt/layout/layout.cc
@@ -127,20 +127,11 @@
   }
 }
 
-scoped_refptr<render_tree::Node> Layout(
-    const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
-    int dom_max_element_depth, UsedStyleProvider* used_style_provider,
+scoped_refptr<render_tree::Node> GenerateRenderTreeFromBoxTree(
+    UsedStyleProvider* used_style_provider,
     LayoutStatTracker* layout_stat_tracker,
-    icu::BreakIterator* line_break_iterator,
-    icu::BreakIterator* character_break_iterator,
     scoped_refptr<BlockLevelBlockContainerBox>* initial_containing_block) {
-  TRACE_EVENT0("cobalt::layout", "Layout()");
-  UpdateComputedStylesAndLayoutBoxTree(
-      locale, document, dom_max_element_depth, used_style_provider,
-      layout_stat_tracker, line_break_iterator, character_break_iterator,
-      initial_containing_block);
-
-  // Add to render tree.
+  TRACE_EVENT0("cobalt::layout", "GenerateRenderTreeFromBoxTree()");
   render_tree::CompositionNode::Builder render_tree_root_builder;
   {
     TRACE_EVENT0("cobalt::layout", kBenchmarkStatRenderAndAnimate);
diff --git a/src/cobalt/layout/layout.h b/src/cobalt/layout/layout.h
index a777318..678fe54 100644
--- a/src/cobalt/layout/layout.h
+++ b/src/cobalt/layout/layout.h
@@ -38,7 +38,8 @@
 // (https://www.w3.org/TR/CSS2/visuren.html) as recommended by a newer draft
 // (http://dev.w3.org/csswg/css-box/) which is undergoing active changes.
 
-// Update the computed styles, then generate and layout the box tree.
+// Update the computed styles, then generate and layout the box tree produced
+// by the given document.
 void UpdateComputedStylesAndLayoutBoxTree(
     const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
     int dom_max_element_depth, UsedStyleProvider* used_style_provider,
@@ -47,15 +48,11 @@
     icu::BreakIterator* character_break_iterator,
     scoped_refptr<BlockLevelBlockContainerBox>* initial_containing_block);
 
-// Main entry point to the layout engine.
-// Produces the render tree (along with corresponding animations) which is a
-// result of recursive layout of the given HTML element.
-scoped_refptr<render_tree::Node> Layout(
-    const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
-    int dom_max_element_depth, UsedStyleProvider* used_style_provider,
+// Generates the render tree (along with corresponding animations) of the box
+// tree contained within the provided containing block.
+scoped_refptr<render_tree::Node> GenerateRenderTreeFromBoxTree(
+    UsedStyleProvider* used_style_provider,
     LayoutStatTracker* layout_stat_tracker,
-    icu::BreakIterator* line_break_iterator,
-    icu::BreakIterator* character_break_iterator,
     scoped_refptr<BlockLevelBlockContainerBox>* initial_containing_block);
 
 }  // namespace layout
diff --git a/src/cobalt/layout/layout_manager.cc b/src/cobalt/layout/layout_manager.cc
index dfb4b44..e9b8319 100644
--- a/src/cobalt/layout/layout_manager.cc
+++ b/src/cobalt/layout/layout_manager.cc
@@ -59,9 +59,10 @@
   void Suspend();
   void Resume();
 
-  bool IsNewRenderTreePending() const;
+  bool IsRenderTreePending() const;
 
  private:
+  void DirtyLayout();
   void StartLayoutTimer();
   void DoLayoutAndProduceRenderTree();
 
@@ -76,11 +77,13 @@
   const OnLayoutCallback on_layout_callback_;
   const LayoutTrigger layout_trigger_;
 
-  // This flag indicates whether or not we should do a re-layout.  The flag
-  // is checked at a regular interval (e.g. 60Hz) and if it is set to true,
-  // a layout is initiated and it is set back to false.  Events such as
-  // DOM mutations will set this flag back to true.
-  base::CVal<bool> layout_dirty_;
+  // Setting these flags triggers an update of the layout box tree and the
+  // generation of a new render tree at a regular interval (e.g. 60Hz). Events
+  // such as DOM mutations cause them to be set to true. While the render tree
+  // is excusively produced at the regular interval, the box tree can also be
+  // updated via a call to DoSynchronousLayout().
+  bool are_computed_styles_and_box_tree_dirty_;
+  base::CVal<bool> is_render_tree_pending_;
 
   // Construction of |BreakIterator| requires a disk read, so we cache them
   // in the layout manager in order to reuse them with all layouts happening
@@ -164,9 +167,10 @@
       on_render_tree_produced_callback_(on_render_tree_produced),
       on_layout_callback_(on_layout),
       layout_trigger_(layout_trigger),
-      layout_dirty_(StringPrintf("%s.Layout.IsDirty", name.c_str()), true,
-                    "Non-zero when the layout is dirty and a new render tree "
-                    "is pending."),
+      are_computed_styles_and_box_tree_dirty_(true),
+      is_render_tree_pending_(
+          StringPrintf("%s.Layout.IsRenderTreePending", name.c_str()), true,
+          "Non-zero when a new render tree is pending."),
       layout_timer_(true, true, true),
       dom_max_element_depth_(dom_max_element_depth),
       layout_refresh_rate_(layout_refresh_rate),
@@ -210,7 +214,7 @@
 #if defined(ENABLE_TEST_RUNNER)
   if (layout_trigger_ == kTestRunnerMode &&
       !window_->test_runner()->should_wait()) {
-    layout_dirty_ = true;
+    DirtyLayout();
 
     // Run the |DoLayoutAndProduceRenderTree| task after onload event finished.
     MessageLoop::current()->PostTask(
@@ -223,7 +227,7 @@
 
 void LayoutManager::Impl::OnMutation() {
   if (layout_trigger_ == kOnDocumentMutation) {
-    layout_dirty_ = true;
+    DirtyLayout();
   }
 }
 
@@ -233,11 +237,14 @@
     return;
   }
 
-  layout::UpdateComputedStylesAndLayoutBoxTree(
-      locale_, window_->document(), dom_max_element_depth_,
-      used_style_provider_.get(), layout_stat_tracker_,
-      line_break_iterator_.get(), character_break_iterator_.get(),
-      &initial_containing_block_);
+  if (are_computed_styles_and_box_tree_dirty_) {
+    layout::UpdateComputedStylesAndLayoutBoxTree(
+        locale_, window_->document(), dom_max_element_depth_,
+        used_style_provider_.get(), layout_stat_tracker_,
+        line_break_iterator_.get(), character_break_iterator_.get(),
+        &initial_containing_block_);
+    are_computed_styles_and_box_tree_dirty_ = false;
+  }
 }
 
 void LayoutManager::Impl::Suspend() {
@@ -258,18 +265,18 @@
 void LayoutManager::Impl::Resume() {
   // Mark that we are no longer suspended and indicate that the layout is
   // dirty since when Suspend() was called we invalidated our previous layout.
-  layout_dirty_ = true;
+  DirtyLayout();
   suspended_ = false;
 }
 
-bool LayoutManager::Impl::IsNewRenderTreePending() const {
-  return layout_dirty_;
+bool LayoutManager::Impl::IsRenderTreePending() const {
+  return is_render_tree_pending_;
 }
 
 #if defined(ENABLE_TEST_RUNNER)
 void LayoutManager::Impl::DoTestRunnerLayoutCallback() {
   DCHECK_EQ(kTestRunnerMode, layout_trigger_);
-  layout_dirty_ = true;
+  DirtyLayout();
 
   if (layout_trigger_ == kTestRunnerMode &&
       window_->test_runner()->should_wait()) {
@@ -285,6 +292,11 @@
 }
 #endif  // ENABLE_TEST_RUNNER
 
+void LayoutManager::Impl::DirtyLayout() {
+  are_computed_styles_and_box_tree_dirty_ = true;
+  is_render_tree_pending_ = true;
+}
+
 void LayoutManager::Impl::StartLayoutTimer() {
   // TODO: Eventually we would like to instead base our layouts off of a
   //       "refresh" signal generated by the rasterizer, instead of trying to
@@ -317,7 +329,7 @@
 
   bool has_layout_processing_started = false;
   if (window_->HasPendingAnimationFrameCallbacks()) {
-    if (layout_dirty_) {
+    if (are_computed_styles_and_box_tree_dirty_) {
       has_layout_processing_started = true;
       TRACE_EVENT_BEGIN0("cobalt::layout", kBenchmarkStatLayout);
       // Update our computed style before running animation callbacks, so that
@@ -334,7 +346,10 @@
     window_->RunAnimationFrameCallbacks();
   }
 
-  if (layout_dirty_) {
+  // It should never be possible for for the computed styles and box tree to
+  // be dirty when a render tree is not pending.
+  DCHECK(is_render_tree_pending_ || !are_computed_styles_and_box_tree_dirty_);
+  if (is_render_tree_pending_) {
     if (!has_layout_processing_started) {
       // We want to catch the beginning of all layout processing.  If it didn't
       // begin before the call to RunAnimationFrameCallbacks(), then the flow
@@ -342,11 +357,19 @@
       TRACE_EVENT_BEGIN0("cobalt::layout", kBenchmarkStatLayout);
     }
 
-    scoped_refptr<render_tree::Node> render_tree_root = layout::Layout(
-        locale_, window_->document(), dom_max_element_depth_,
-        used_style_provider_.get(), layout_stat_tracker_,
-        line_break_iterator_.get(), character_break_iterator_.get(),
-        &initial_containing_block_);
+    if (are_computed_styles_and_box_tree_dirty_) {
+      layout::UpdateComputedStylesAndLayoutBoxTree(
+          locale_, window_->document(), dom_max_element_depth_,
+          used_style_provider_.get(), layout_stat_tracker_,
+          line_break_iterator_.get(), character_break_iterator_.get(),
+          &initial_containing_block_);
+      are_computed_styles_and_box_tree_dirty_ = false;
+    }
+
+    scoped_refptr<render_tree::Node> render_tree_root =
+        layout::GenerateRenderTreeFromBoxTree(used_style_provider_.get(),
+                                              layout_stat_tracker_,
+                                              &initial_containing_block_);
     bool run_on_render_tree_produced_callback = true;
 #if defined(ENABLE_TEST_RUNNER)
     if (layout_trigger_ == kTestRunnerMode &&
@@ -361,8 +384,7 @@
                                 *document->timeline()->current_time())));
     }
 
-    layout_dirty_ = false;
-
+    is_render_tree_pending_ = false;
     TRACE_EVENT_END0("cobalt::layout", kBenchmarkStatLayout);
   }
 
@@ -384,8 +406,8 @@
 
 void LayoutManager::Suspend() { impl_->Suspend(); }
 void LayoutManager::Resume() { impl_->Resume(); }
-bool LayoutManager::IsNewRenderTreePending() const {
-  return impl_->IsNewRenderTreePending();
+bool LayoutManager::IsRenderTreePending() const {
+  return impl_->IsRenderTreePending();
 }
 
 }  // namespace layout
diff --git a/src/cobalt/layout/layout_manager.h b/src/cobalt/layout/layout_manager.h
index 6830336..1a973a5 100644
--- a/src/cobalt/layout/layout_manager.h
+++ b/src/cobalt/layout/layout_manager.h
@@ -74,7 +74,7 @@
   void Suspend();
   void Resume();
 
-  bool IsNewRenderTreePending() const;
+  bool IsRenderTreePending() const;
 
  private:
   class Impl;
diff --git a/src/cobalt/loader/image/image_data_decoder.cc b/src/cobalt/loader/image/image_data_decoder.cc
index af95b3b..33e939f 100644
--- a/src/cobalt/loader/image/image_data_decoder.cc
+++ b/src/cobalt/loader/image/image_data_decoder.cc
@@ -112,9 +112,6 @@
   if (!image_data_) {
     DLOG(WARNING) << "Failed to allocate image data (" << size.width() << "x"
                   << size.height() << ").";
-    // We want to know in debug if we have problems allocating image data.
-    // It should never happen.
-    DCHECK(false);
   }
   return image_data_;
 }
diff --git a/src/cobalt/loader/loader.gyp b/src/cobalt/loader/loader.gyp
index b9bdc78..b4fb1fe 100644
--- a/src/cobalt/loader/loader.gyp
+++ b/src/cobalt/loader/loader.gyp
@@ -129,6 +129,7 @@
         '<(DEPTH)/testing/gtest.gyp:gtest',
         'loader',
         'loader_copy_test_data',
+        '<@(cobalt_platform_dependencies)',
       ],
     },
 
diff --git a/src/cobalt/loader/loader_factory.cc b/src/cobalt/loader/loader_factory.cc
index b2e68eb..d65a87b 100644
--- a/src/cobalt/loader/loader_factory.cc
+++ b/src/cobalt/loader/loader_factory.cc
@@ -122,8 +122,6 @@
 void LoaderFactory::Resume(render_tree::ResourceProvider* resource_provider) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(resource_provider);
-  DCHECK(!resource_provider_);
-  DCHECK(is_suspended_);
 
   is_suspended_ = false;
   resource_provider_ = resource_provider;
diff --git a/src/cobalt/loader/mesh/mesh_decoder.cc b/src/cobalt/loader/mesh/mesh_decoder.cc
index 2964508..556e191 100644
--- a/src/cobalt/loader/mesh/mesh_decoder.cc
+++ b/src/cobalt/loader/mesh/mesh_decoder.cc
@@ -180,7 +180,7 @@
     render_tree::ResourceProvider* resource_provider, uint8_t version,
     uint32_t flags, const uint8* data, size_t data_size) {
   MeshDecoderSink::MeshCollectionList mesh_collection_list;
-  uint32 crc = -1;
+  uint32 crc = kuint32max;
 
   if (!DecodeBoxContents(resource_provider, version, flags, data, data_size,
                          &mesh_collection_list, &crc)) {
diff --git a/src/cobalt/loader/mesh/projection_codec/projection_decoder.cc b/src/cobalt/loader/mesh/projection_codec/projection_decoder.cc
index fe7a421..1635eb2 100644
--- a/src/cobalt/loader/mesh/projection_codec/projection_decoder.cc
+++ b/src/cobalt/loader/mesh/projection_codec/projection_decoder.cc
@@ -625,7 +625,7 @@
     int v_index = 0;
     int bits_per_vertex_index =
         static_cast<int>(ceil(log2(static_cast<double>(num_verts * 2))));
-    for (uint32_t i = 0; i < num_indices; ++i) {
+    for (uint32_t j = 0; j < num_indices; ++j) {
       v_index += ZigZagDecode32(GetBits(bits_per_vertex_index));
 
       // Check that this vertex index is in range before sending it off.
diff --git a/src/cobalt/media/base/decoder_buffer.cc b/src/cobalt/media/base/decoder_buffer.cc
index b01b364..919f9ca 100644
--- a/src/cobalt/media/base/decoder_buffer.cc
+++ b/src/cobalt/media/base/decoder_buffer.cc
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 #include "cobalt/media/base/decoder_buffer.h"
+
+#include "cobalt/build/build_config.h"
 #include "starboard/memory.h"
 
 namespace cobalt {
@@ -10,73 +12,63 @@
 
 DecoderBuffer::ScopedAllocatorPtr::ScopedAllocatorPtr(Allocator* allocator,
                                                       Type type, size_t size)
-    : allocator_(allocator), type_(type), ptr_(NULL) {
+    : allocator_(allocator), type_(type) {
   if (size > 0) {
     DCHECK(allocator_);
-    ptr_ = static_cast<uint8_t*>(
-        allocator_->Allocate(type_, size + kPaddingSize, kAlignmentSize));
-    if (ptr_) {
-      SbMemorySet(ptr_ + size, 0, kPaddingSize);
+    allocations_ = allocator_->Allocate(size + COBALT_MEDIA_BUFFER_PADDING,
+                                        COBALT_MEDIA_BUFFER_ALIGNMENT,
+                                        static_cast<intptr_t>(type));
+#if COBALT_MEDIA_BUFFER_PADDING > 0
+    if (allocations_.number_of_buffers() > 0) {
+      char zeros[COBALT_MEDIA_BUFFER_PADDING + 1] = {0};
+      allocations_.Write(size, zeros, COBALT_MEDIA_BUFFER_PADDING);
+      allocations_.ShrinkTo(size);
     }
+#endif  // COBALT_MEDIA_BUFFER_PADDING > 0
   }
 }
 
 DecoderBuffer::ScopedAllocatorPtr::~ScopedAllocatorPtr() {
   // |allocator_| can be NULL for EOS buffer.
-  if (allocator_ && ptr_) {
-    allocator_->Free(type_, ptr_);
+  if (allocator_) {
+    allocator_->Free(allocations_);
   }
 }
 
 DecoderBuffer::DecoderBuffer()
-    : allocator_(NULL),
-      type_(DemuxerStream::UNKNOWN),
-      allocated_size_(0),
-      size_(0),
-      data_(NULL, DemuxerStream::UNKNOWN, 0),
-      side_data_size_(0),
-      side_data_(NULL, DemuxerStream::UNKNOWN, 0),
+    : data_(NULL, DemuxerStream::UNKNOWN, 0),
       splice_timestamp_(kNoTimestamp),
       is_key_frame_(false) {}
 
 DecoderBuffer::DecoderBuffer(Allocator* allocator, Type type, size_t size)
-    : allocator_(allocator),
-      type_(type),
-      allocated_size_(size),
-      size_(size),
-      data_(allocator_, type, size),
-      side_data_size_(0),
-      side_data_(allocator_, type, 0),
+    : data_(allocator, type, size),
       splice_timestamp_(kNoTimestamp),
       is_key_frame_(false) {}
 
 DecoderBuffer::DecoderBuffer(Allocator* allocator, Type type,
-                             const uint8_t* data, size_t size,
-                             const uint8_t* side_data, size_t side_data_size)
-    : allocator_(allocator),
-      type_(type),
-      allocated_size_(size),
-      size_(size),
-      data_(allocator_, type, size),
-      side_data_size_(side_data_size),
-      side_data_(allocator_, type, side_data_size),
+                             const uint8_t* data, size_t size)
+    : data_(allocator, type, size),
       splice_timestamp_(kNoTimestamp),
       is_key_frame_(false) {
   if (!data) {
-    CHECK_EQ(size_, 0u);
-    CHECK(!side_data);
+    CHECK_EQ(size, 0u);
     return;
   }
 
-  SbMemoryCopy(data_.get(), data, size_);
+  allocations().Write(0, data, size);
+}
 
-  if (!side_data) {
-    CHECK_EQ(side_data_size, 0u);
-    return;
+DecoderBuffer::DecoderBuffer(Allocator* allocator, Type type,
+                             Allocator::Allocations allocations)
+    : data_(allocator, type, allocations.size()),
+      splice_timestamp_(kNoTimestamp),
+      is_key_frame_(false) {
+  int offset = 0;
+  for (int i = 0; i < allocations.number_of_buffers(); ++i) {
+    this->allocations().Write(offset, allocations.buffers()[i],
+                              allocations.buffer_sizes()[i]);
+    offset += allocations.buffer_sizes()[i];
   }
-
-  DCHECK_GT(side_data_size_, 0u);
-  SbMemoryCopy(side_data_.get(), side_data, side_data_size_);
 }
 
 DecoderBuffer::~DecoderBuffer() {}
@@ -101,7 +93,7 @@
   // If you hit this CHECK you likely have a bug in a demuxer. Go fix it.
   CHECK(data);
   scoped_refptr<DecoderBuffer> decoder_buffer =
-      new DecoderBuffer(allocator, type, data, data_size, NULL, 0);
+      new DecoderBuffer(allocator, type, data, data_size);
   if (decoder_buffer->has_data()) {
     return decoder_buffer;
   }
@@ -109,21 +101,6 @@
 }
 
 // static
-scoped_refptr<DecoderBuffer> DecoderBuffer::CopyFrom(
-    Allocator* allocator, Type type, const uint8_t* data, size_t data_size,
-    const uint8_t* side_data, size_t side_data_size) {
-  // If you hit this CHECK you likely have a bug in a demuxer. Go fix it.
-  CHECK(data);
-  CHECK(side_data);
-  scoped_refptr<DecoderBuffer> decoder_buffer = new DecoderBuffer(
-      allocator, type, data, data_size, side_data, side_data_size);
-  if (decoder_buffer->has_data() && decoder_buffer->has_side_data()) {
-    return decoder_buffer;
-  }
-  return NULL;
-}
-
-// static
 scoped_refptr<DecoderBuffer> DecoderBuffer::CreateEOSBuffer() {
   return make_scoped_refptr(new DecoderBuffer);
 }
@@ -154,8 +131,7 @@
   std::ostringstream s;
   s << "type: " << GetTypeName()
     << " timestamp: " << timestamp_.InMicroseconds()
-    << " duration: " << duration_.InMicroseconds() << " size: " << size_
-    << " side_data_size: " << side_data_size_
+    << " duration: " << duration_.InMicroseconds() << " size: " << data_size()
     << " is_key_frame: " << is_key_frame_
     << " encrypted: " << (decrypt_config_ != NULL) << " discard_padding (ms): ("
     << discard_padding_.first.InMilliseconds() << ", "
diff --git a/src/cobalt/media/base/decoder_buffer.h b/src/cobalt/media/base/decoder_buffer.h
index ec7b3d7..d8b72a0 100644
--- a/src/cobalt/media/base/decoder_buffer.h
+++ b/src/cobalt/media/base/decoder_buffer.h
@@ -19,6 +19,7 @@
 #include "cobalt/media/base/demuxer_stream.h"
 #include "cobalt/media/base/media_export.h"
 #include "cobalt/media/base/timestamp_constants.h"
+#include "nb/multipart_allocator.h"
 #include "starboard/memory.h"
 #include "starboard/types.h"
 
@@ -38,22 +39,7 @@
     : public base::RefCountedThreadSafe<DecoderBuffer> {
  public:
   typedef DemuxerStream::Type Type;
-
-  class Allocator {
-   public:
-    typedef DecoderBuffer::Type Type;
-
-    virtual ~Allocator() {}
-
-    // Allocate a memory block that contains at least |size| bytes and its
-    // address is aligned to |alignment|.  It returns NULL on failure.
-    virtual void* Allocate(Type type, size_t size, size_t alignment) = 0;
-    // Free a memory block previously allocated by calling Allocate().  No-op on
-    // NULL.
-    virtual void Free(Type type, void* ptr) = 0;
-  };
-
-  static const size_t kAlignmentSize = 128;
+  typedef nb::MultipartAllocator Allocator;
 
   // Create a DecoderBuffer whose |data_| points to a memory with at least
   // |size| bytes.  Buffer will be padded and aligned as necessary.
@@ -68,15 +54,6 @@
                                                const uint8_t* data,
                                                size_t size);
 
-  // Create a DecoderBuffer whose |data_| is copied from |data| and |side_data_|
-  // is copied from |side_data|. Buffers will be padded and aligned as necessary
-  // Data pointers must not be NULL and sizes must be >= 0. The buffer's
-  // |is_key_frame_| will default to false.
-  static scoped_refptr<DecoderBuffer> CopyFrom(Allocator* allocator, Type type,
-                                               const uint8_t* data, size_t size,
-                                               const uint8_t* side_data,
-                                               size_t side_data_size);
-
   // Create a DecoderBuffer indicating we've reached end of stream.
   //
   // Calling any method other than end_of_stream() on the resulting buffer
@@ -85,11 +62,11 @@
 
   // Returns the allocator.  This is usually used when creating a copy of the
   // buffer.
-  Allocator* allocator() const { return allocator_; }
+  Allocator* allocator() const { return data_.allocator(); }
 
   // Gets the parser's media type associated with this buffer. Value is
   // meaningless for EOS buffers.
-  Type type() const { return type_; }
+  Type type() const { return data_.type(); }
   const char* GetTypeName() const;
 
   base::TimeDelta timestamp() const {
@@ -114,39 +91,21 @@
     duration_ = duration;
   }
 
-  bool has_data() const { return data_.get() != NULL; }
+  bool has_data() const { return allocations().number_of_buffers() > 0; }
 
-  const uint8_t* data() const {
-    DCHECK(!end_of_stream());
-    return data_.get();
+  const Allocator::Allocations& allocations() const {
+    return data_.allocations();
   }
+  Allocator::Allocations& allocations() { return data_.allocations(); }
 
-  uint8_t* writable_data() {
-    DCHECK(!end_of_stream());
-    return data_.get();
-  }
-
-  size_t allocated_size() const { return allocated_size_; }
   size_t data_size() const {
     DCHECK(!end_of_stream());
-    return size_;
+    return data_.allocations().size();
   }
 
   void shrink_to(size_t size) {
-    DCHECK_LE(size, allocated_size_);
-    size_ = size;
-  }
-
-  bool has_side_data() const { return side_data_.get() != NULL; }
-
-  const uint8_t* side_data() const {
-    DCHECK(!end_of_stream());
-    return side_data_.get();
-  }
-
-  size_t side_data_size() const {
-    DCHECK(!end_of_stream());
-    return side_data_size_;
+    DCHECK_GE(static_cast<int>(size), 0);
+    allocations().ShrinkTo(static_cast<int>(size));
   }
 
   // A discard window indicates the amount of data which should be discard from
@@ -176,7 +135,7 @@
   }
 
   // If there's no data in this buffer, it represents end of stream.
-  bool end_of_stream() const { return data_.get() == NULL; }
+  bool end_of_stream() const { return !has_data(); }
 
   // Indicates this buffer is part of a splice around |splice_timestamp_|.
   // Returns kNoTimestamp if the buffer is not part of a splice.
@@ -220,41 +179,39 @@
   // set to NULL and |buffer_size_| to 0.  |is_key_frame_| will default to
   // false.
   DecoderBuffer(Allocator* allocator, Type type, const uint8_t* data,
-                size_t size, const uint8_t* side_data, size_t side_data_size);
+                size_t size);
+
+  // Allocates a buffer to copy the data in |allocations|.  Buffer will be
+  // padded and aligned as necessary.  |is_key_frame_| will default to false.
+  DecoderBuffer(Allocator* allocator, Type type,
+                Allocator::Allocations allocations);
+
   virtual ~DecoderBuffer();
 
  private:
   class ScopedAllocatorPtr {
    public:
-    // Extra bytes allocated at the end of a buffer to ensure that the buffer
-    // can be use optimally by specific instructions like SIMD.
-    static const size_t kPaddingSize = 32;
-
     ScopedAllocatorPtr(Allocator* allocator, Type type, size_t size);
     ~ScopedAllocatorPtr();
-    uint8_t* get() { return ptr_; }
-    const uint8_t* get() const { return ptr_; }
+
+    const Allocator::Allocations& allocations() const { return allocations_; }
+    Allocator::Allocations& allocations() { return allocations_; }
+
+    Allocator* allocator() const { return allocator_; }
+    Type type() const { return type_; }
 
    private:
     Allocator* allocator_;
     Type type_;
-    uint8_t* ptr_;
+    Allocator::Allocations allocations_;
 
     DISALLOW_COPY_AND_ASSIGN(ScopedAllocatorPtr);
   };
 
-  Allocator* allocator_;
-
-  Type type_;
-
   base::TimeDelta timestamp_;
   base::TimeDelta duration_;
 
-  const size_t allocated_size_;
-  size_t size_;
   ScopedAllocatorPtr data_;
-  size_t side_data_size_;
-  ScopedAllocatorPtr side_data_;
   scoped_ptr<DecryptConfig> decrypt_config_;
   DiscardPadding discard_padding_;
   base::TimeDelta splice_timestamp_;
diff --git a/src/cobalt/media/base/starboard_player.cc b/src/cobalt/media/base/starboard_player.cc
index d91a113..cb8749c 100644
--- a/src/cobalt/media/base/starboard_player.cc
+++ b/src/cobalt/media/base/starboard_player.cc
@@ -161,9 +161,13 @@
     return;
   }
 
-  DecodingBuffers::iterator iter = decoding_buffers_.find(buffer->data());
+  const auto& allocations = buffer->allocations();
+  DCHECK_GT(allocations.number_of_buffers(), 0);
+
+  DecodingBuffers::iterator iter =
+      decoding_buffers_.find(allocations.buffers()[0]);
   if (iter == decoding_buffers_.end()) {
-    decoding_buffers_[buffer->data()] = std::make_pair(buffer, 1);
+    decoding_buffers_[allocations.buffers()[0]] = std::make_pair(buffer, 1);
   } else {
     ++iter->second.second;
   }
@@ -178,30 +182,25 @@
   video_info.frame_width = frame_width_;
   video_info.frame_height = frame_height_;
 
-#if SB_API_VERSION >= 4
   SbMediaColorMetadata sb_media_color_metadata =
       MediaToSbMediaColorMetadata(video_config_.webm_color_metadata());
   video_info.color_metadata = &sb_media_color_metadata;
-#endif
+
   if (is_encrypted) {
     FillDrmSampleInfo(buffer, &drm_info, &subsample_mapping);
   }
 
-#if SB_API_VERSION >= 4
-  const void* sample_buffers[] = {buffer->data()};
-  int sample_buffer_sizes[] = {buffer->data_size()};
   SbPlayerWriteSample(player_, DemuxerStreamTypeToSbMediaType(type),
-                      sample_buffers, sample_buffer_sizes, 1,
+#if SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
+                      allocations.buffers(), allocations.buffer_sizes(),
+#else   // SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
+                      const_cast<const void**>(allocations.buffers()),
+                      const_cast<int*>(allocations.buffer_sizes()),
+#endif  // SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
+                      allocations.number_of_buffers(),
                       TimeDeltaToSbMediaTime(buffer->timestamp()),
                       type == DemuxerStream::VIDEO ? &video_info : NULL,
                       drm_info.subsample_count > 0 ? &drm_info : NULL);
-#else   // SB_API_VERSION >= 4
-  SbPlayerWriteSample(player_, DemuxerStreamTypeToSbMediaType(type),
-                      buffer->data(), buffer->data_size(),
-                      TimeDeltaToSbMediaTime(buffer->timestamp()),
-                      type == DemuxerStream::VIDEO ? &video_info : NULL,
-                      drm_info.subsample_count > 0 ? &drm_info : NULL);
-#endif  // SB_API_VERSION >= 4
 }
 
 void StarboardPlayer::SetBounds(const gfx::Rect& rect) {
@@ -503,9 +502,11 @@
 void StarboardPlayer::ClearDecoderBufferCache() {
   DCHECK(message_loop_->BelongsToCurrentThread());
 
-  base::TimeDelta media_time;
-  GetInfo(NULL, NULL, &media_time);
-  decoder_buffer_cache_.ClearSegmentsBeforeMediaTime(media_time);
+  if (state_ != kResuming) {
+    base::TimeDelta media_time;
+    GetInfo(NULL, NULL, &media_time);
+    decoder_buffer_cache_.ClearSegmentsBeforeMediaTime(media_time);
+  }
 
   message_loop_->PostDelayedTask(
       FROM_HERE,
diff --git a/src/cobalt/media/base/stream_parser_buffer.cc b/src/cobalt/media/base/stream_parser_buffer.cc
index 3680f9c..dc5b14e 100644
--- a/src/cobalt/media/base/stream_parser_buffer.cc
+++ b/src/cobalt/media/base/stream_parser_buffer.cc
@@ -12,32 +12,6 @@
 namespace cobalt {
 namespace media {
 
-static scoped_refptr<StreamParserBuffer> CopyBuffer(
-    const StreamParserBuffer& buffer) {
-  if (buffer.end_of_stream()) return StreamParserBuffer::CreateEOSBuffer();
-
-  scoped_refptr<StreamParserBuffer> copied_buffer =
-      StreamParserBuffer::CopyFrom(
-          buffer.allocator(), buffer.data(), buffer.data_size(),
-          buffer.side_data(), buffer.side_data_size(), buffer.is_key_frame(),
-          buffer.type(), buffer.track_id());
-  copied_buffer->SetDecodeTimestamp(buffer.GetDecodeTimestamp());
-  copied_buffer->SetConfigId(buffer.GetConfigId());
-  copied_buffer->set_timestamp(buffer.timestamp());
-  copied_buffer->set_duration(buffer.duration());
-  copied_buffer->set_is_duration_estimated(buffer.is_duration_estimated());
-  copied_buffer->set_discard_padding(buffer.discard_padding());
-  copied_buffer->set_splice_timestamp(buffer.splice_timestamp());
-  const DecryptConfig* decrypt_config = buffer.decrypt_config();
-  if (decrypt_config) {
-    copied_buffer->set_decrypt_config(scoped_ptr<DecryptConfig>(
-        new DecryptConfig(decrypt_config->key_id(), decrypt_config->iv(),
-                          decrypt_config->subsamples())));
-  }
-
-  return copied_buffer;
-}
-
 scoped_refptr<StreamParserBuffer> StreamParserBuffer::CreateEOSBuffer() {
   return make_scoped_refptr(new StreamParserBuffer);
 }
@@ -46,16 +20,7 @@
     Allocator* allocator, const uint8_t* data, int data_size, bool is_key_frame,
     Type type, TrackId track_id) {
   return make_scoped_refptr(new StreamParserBuffer(
-      allocator, data, data_size, NULL, 0, is_key_frame, type, track_id));
-}
-
-scoped_refptr<StreamParserBuffer> StreamParserBuffer::CopyFrom(
-    Allocator* allocator, const uint8_t* data, int data_size,
-    const uint8_t* side_data, int side_data_size, bool is_key_frame, Type type,
-    TrackId track_id) {
-  return make_scoped_refptr(
-      new StreamParserBuffer(allocator, data, data_size, side_data,
-                             side_data_size, is_key_frame, type, track_id));
+      allocator, data, data_size, is_key_frame, type, track_id));
 }
 
 DecodeTimestamp StreamParserBuffer::GetDecodeTimestamp() const {
@@ -77,11 +42,9 @@
 
 StreamParserBuffer::StreamParserBuffer(Allocator* allocator,
                                        const uint8_t* data, int data_size,
-                                       const uint8_t* side_data,
-                                       int side_data_size, bool is_key_frame,
-                                       Type type, TrackId track_id)
-    : DecoderBuffer(allocator, type, data, data_size, side_data,
-                    side_data_size),
+                                       bool is_key_frame, Type type,
+                                       TrackId track_id)
+    : DecoderBuffer(allocator, type, data, data_size),
       decode_timestamp_(kNoDecodeTimestamp()),
       config_id_(kInvalidConfigId),
       track_id_(track_id),
@@ -96,6 +59,23 @@
   if (is_key_frame) set_is_key_frame(true);
 }
 
+StreamParserBuffer::StreamParserBuffer(Allocator* allocator,
+                                       Allocator::Allocations allocations,
+                                       bool is_key_frame, Type type,
+                                       TrackId track_id)
+    : DecoderBuffer(allocator, type, allocations),
+      decode_timestamp_(kNoDecodeTimestamp()),
+      config_id_(kInvalidConfigId),
+      track_id_(track_id),
+      is_duration_estimated_(false) {
+  // TODO(scherkus): Should DataBuffer constructor accept a timestamp and
+  // duration to force clients to set them? Today they end up being zero which
+  // is both a common and valid value and could lead to bugs.
+  set_duration(kNoTimestamp);
+
+  if (is_key_frame) set_is_key_frame(true);
+}
+
 StreamParserBuffer::~StreamParserBuffer() {}
 
 int StreamParserBuffer::GetConfigId() const { return config_id_; }
@@ -126,7 +106,7 @@
   DCHECK(!is_duration_estimated_);
 
   // Make a copy of this first, before making any changes.
-  scoped_refptr<StreamParserBuffer> overlapping_buffer = CopyBuffer(*this);
+  scoped_refptr<StreamParserBuffer> overlapping_buffer = Clone();
   overlapping_buffer->set_splice_timestamp(kNoTimestamp);
 
   const scoped_refptr<StreamParserBuffer>& first_splice_buffer =
@@ -135,9 +115,8 @@
   // Ensure the given buffers are actually before the splice point.
   DCHECK(first_splice_buffer->timestamp() <= overlapping_buffer->timestamp());
 
-  // TODO(dalecurtis): We should also clear |data| and |side_data|, but since
-  // that implies EOS care must be taken to ensure there are no clients relying
-  // on that behavior.
+  // TODO(dalecurtis): We should also clear |data|, but since that implies EOS
+  // care must be taken to ensure there are no clients relying on that behavior.
 
   // Move over any preroll from this buffer.
   if (preroll_buffer_.get()) {
@@ -172,7 +151,7 @@
     DCHECK(!buffer->preroll_buffer().get());
     DCHECK(buffer->splice_buffers().empty());
     DCHECK(!buffer->is_duration_estimated());
-    splice_buffers_.push_back(CopyBuffer(*buffer.get()));
+    splice_buffers_.push_back(buffer->Clone());
     splice_buffers_.back()->set_splice_timestamp(splice_timestamp());
   }
 
@@ -206,5 +185,29 @@
   if (preroll_buffer_.get()) preroll_buffer_->set_timestamp(timestamp);
 }
 
+scoped_refptr<StreamParserBuffer> StreamParserBuffer::Clone() const {
+  if (end_of_stream()) {
+    return StreamParserBuffer::CreateEOSBuffer();
+  }
+
+  scoped_refptr<StreamParserBuffer> clone = new StreamParserBuffer(
+      allocator(), allocations(), is_key_frame(), type(), track_id());
+  clone->SetDecodeTimestamp(GetDecodeTimestamp());
+  clone->SetConfigId(GetConfigId());
+  clone->set_timestamp(timestamp());
+  clone->set_duration(duration());
+  clone->set_is_duration_estimated(is_duration_estimated());
+  clone->set_discard_padding(discard_padding());
+  clone->set_splice_timestamp(splice_timestamp());
+  const DecryptConfig* decrypt_config = this->decrypt_config();
+  if (decrypt_config) {
+    clone->set_decrypt_config(scoped_ptr<DecryptConfig>(
+        new DecryptConfig(decrypt_config->key_id(), decrypt_config->iv(),
+                          decrypt_config->subsamples())));
+  }
+
+  return clone;
+}
+
 }  // namespace media
 }  // namespace cobalt
diff --git a/src/cobalt/media/base/stream_parser_buffer.h b/src/cobalt/media/base/stream_parser_buffer.h
index 34bf0d6..f715824 100644
--- a/src/cobalt/media/base/stream_parser_buffer.h
+++ b/src/cobalt/media/base/stream_parser_buffer.h
@@ -112,10 +112,6 @@
   static scoped_refptr<StreamParserBuffer> CopyFrom(
       Allocator* allocator, const uint8_t* data, int data_size,
       bool is_key_frame, Type type, TrackId track_id);
-  static scoped_refptr<StreamParserBuffer> CopyFrom(
-      Allocator* allocator, const uint8_t* data, int data_size,
-      const uint8_t* side_data, int side_data_size, bool is_key_frame,
-      Type type, TrackId track_id);
 
   // Decode timestamp. If not explicitly set, or set to kNoTimestamp, the
   // value will be taken from the normal timestamp.
@@ -176,10 +172,13 @@
   // The default ctor creates an EOS buffer without specific stream type.
   StreamParserBuffer();
   StreamParserBuffer(Allocator* allocator, const uint8_t* data, int data_size,
-                     const uint8_t* side_data, int side_data_size,
+                     bool is_key_frame, Type type, TrackId track_id);
+  StreamParserBuffer(Allocator* allocator, Allocator::Allocations allocations,
                      bool is_key_frame, Type type, TrackId track_id);
   ~StreamParserBuffer() OVERRIDE;
 
+  scoped_refptr<StreamParserBuffer> Clone() const;
+
   DecodeTimestamp decode_timestamp_;
   int config_id_;
   TrackId track_id_;
diff --git a/src/cobalt/media/decoder_buffer_allocator.cc b/src/cobalt/media/decoder_buffer_allocator.cc
index 7097815..fd9f178 100644
--- a/src/cobalt/media/decoder_buffer_allocator.cc
+++ b/src/cobalt/media/decoder_buffer_allocator.cc
@@ -14,6 +14,9 @@
 
 #include "cobalt/media/decoder_buffer_allocator.h"
 
+#include <vector>
+
+#include "nb/allocator.h"
 #include "nb/memory_scope.h"
 #include "starboard/common/scoped_ptr.h"
 #include "starboard/configuration.h"
@@ -22,50 +25,211 @@
 namespace cobalt {
 namespace media {
 
-DecoderBufferAllocator::DecoderBufferAllocator() : memory_block_(NULL) {
-  TRACK_MEMORY_SCOPE("Media");
-  if (COBALT_MEDIA_BUFFER_INITIAL_CAPACITY > 0) {
-    memory_block_ = SbMemoryAllocateAligned(
-        DecoderBuffer::kAlignmentSize, COBALT_MEDIA_BUFFER_INITIAL_CAPACITY);
-  }
+namespace {
 
-  if (COBALT_MEDIA_BUFFER_INITIAL_CAPACITY > 0 ||
-      COBALT_MEDIA_BUFFER_ALLOCATION_UNIT > 0) {
-    // TODO: Support COBALT_MEDIA_BUFFER_ALLOCATION_UNIT > 0.
-    memory_pool_.set(starboard::make_scoped_ptr(new nb::FirstFitMemoryPool(
-        memory_block_, COBALT_MEDIA_BUFFER_INITIAL_CAPACITY)));
-  }
+const bool kEnableMultiblockAllocate = false;
+const bool kEnableAllocationLog = false;
+
+const std::size_t kAllocationRecordGranularity = 512 * 1024;
+const std::size_t kSmallAllocationThreshold = 512;
+
+bool IsLargeAllocation(std::size_t size) {
+  return size > kSmallAllocationThreshold;
+}
+
+}  // namespace
+
+DecoderBufferAllocator::DecoderBufferAllocator() {
+#if COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
+#if COBALT_MEDIA_BUFFER_POOL_ALLOCATE_ON_DEMAND
+  DLOG(INFO) << "Allocated media buffer pool on demand.";
+#else   // COBALT_MEDIA_BUFFER_POOL_ALLOCATE_ON_DEMAND
+  TRACK_MEMORY_SCOPE("Media");
+
+  reuse_allcator_.reset(new ReuseAllcator(&fallback_allocator_,
+                                          COBALT_MEDIA_BUFFER_INITIAL_CAPACITY,
+                                          COBALT_MEDIA_BUFFER_ALLOCATION_UNIT));
+  DLOG(INFO) << "Allocated " << COBALT_MEDIA_BUFFER_INITIAL_CAPACITY
+             << " bytes for media buffer pool as its initial buffer.";
+#endif  // COBALT_MEDIA_BUFFER_POOL_ALLOCATE_ON_DEMAND
+#else   // COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
+  DLOG(INFO) << "Allocated media buffer memory using SbMemory* functions.";
+#endif  // COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
 }
 
 DecoderBufferAllocator::~DecoderBufferAllocator() {
-  if (memory_pool_.is_valid()) {
-    DCHECK_EQ(memory_pool_->GetAllocated(), 0);
-  }
-
-  if (memory_block_) {
-    SbMemoryDeallocateAligned(memory_block_);
-  }
-}
-
-void* DecoderBufferAllocator::Allocate(Type type, size_t size,
-                                       size_t alignment) {
+#if COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
   TRACK_MEMORY_SCOPE("Media");
-  UNREFERENCED_PARAMETER(type);
-  if (memory_pool_.is_valid()) {
-    return memory_pool_->Allocate(size, alignment);
-  }
 
-  return SbMemoryAllocateAligned(alignment, size);
+  starboard::ScopedLock scoped_lock(mutex_);
+
+  if (reuse_allcator_) {
+    DCHECK_EQ(reuse_allcator_->GetAllocated(), 0);
+    reuse_allcator_.reset();
+  }
+#endif  // COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
 }
 
-void DecoderBufferAllocator::Free(Type type, void* ptr) {
-  UNREFERENCED_PARAMETER(type);
-  if (memory_pool_.is_valid()) {
-    memory_pool_->Free(ptr);
-    return;
+DecoderBuffer::Allocator::Allocations DecoderBufferAllocator::Allocate(
+    size_t size, size_t alignment, intptr_t context) {
+  TRACK_MEMORY_SCOPE("Media");
+
+#if COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
+  starboard::ScopedLock scoped_lock(mutex_);
+
+  if (!reuse_allcator_) {
+    reuse_allcator_.reset(new ReuseAllcator(
+        &fallback_allocator_, COBALT_MEDIA_BUFFER_INITIAL_CAPACITY,
+        COBALT_MEDIA_BUFFER_ALLOCATION_UNIT));
+    DLOG(INFO) << "Returned " << COBALT_MEDIA_BUFFER_INITIAL_CAPACITY
+               << " bytes from media buffer pool to system.";
   }
 
-  SbMemoryDeallocateAligned(ptr);
+  if (!kEnableMultiblockAllocate || kEnableAllocationLog) {
+    void* p = reuse_allcator_->Allocate(size, alignment);
+    LOG_IF(INFO, kEnableAllocationLog)
+        << "======== Media Allocation Log " << p << " " << size << " "
+        << alignment << " " << context;
+    UpdateAllocationRecord();
+    return Allocations(p, size);
+  }
+
+  std::size_t allocated_size = size;
+  void* p =
+      reuse_allcator_->AllocateBestBlock(alignment, context, &allocated_size);
+  DCHECK_LE(allocated_size, size);
+  if (allocated_size == size) {
+    UpdateAllocationRecord();
+    return Allocations(p, size);
+  }
+
+  std::vector<void*> buffers = {p};
+  std::vector<int> buffer_sizes = {static_cast<int>(allocated_size)};
+  size -= allocated_size;
+
+  while (size > 0) {
+    allocated_size = size;
+    void* p =
+        reuse_allcator_->AllocateBestBlock(alignment, context, &allocated_size);
+    DCHECK_LE(allocated_size, size);
+    buffers.push_back(p);
+    buffer_sizes.push_back(allocated_size);
+
+    size -= allocated_size;
+  }
+  UpdateAllocationRecord(buffers.size());
+  return Allocations(static_cast<int>(buffers.size()), buffers.data(),
+                     buffer_sizes.data());
+#else   // COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
+  return Allocations(SbMemoryAllocateAligned(alignment, size), size);
+#endif  // COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
+}
+
+void DecoderBufferAllocator::Free(Allocations allocations) {
+  TRACK_MEMORY_SCOPE("Media");
+
+#if COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
+  starboard::ScopedLock scoped_lock(mutex_);
+
+  DCHECK(reuse_allcator_);
+
+  if (kEnableAllocationLog) {
+    DCHECK_EQ(allocations.number_of_buffers(), 1);
+    LOG(INFO) << "======== Media Allocation Log " << allocations.buffers()[0];
+  }
+  for (int i = 0; i < allocations.number_of_buffers(); ++i) {
+    reuse_allcator_->Free(allocations.buffers()[i]);
+  }
+#if COBALT_MEDIA_BUFFER_POOL_ALLOCATE_ON_DEMAND
+  if (reuse_allcator_->GetAllocated() == 0) {
+    DLOG(INFO) << "Freed " << reuse_allcator_->GetCapacity()
+               << " bytes of media buffer pool `on demand`.";
+    reuse_allcator_.reset();
+  }
+#endif  // COBALT_MEDIA_BUFFER_POOL_ALLOCATE_ON_DEMAND
+#else   // COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
+  for (int i = 0; i < allocations.number_of_buffers(); ++i) {
+    SbMemoryDeallocateAligned(allocations.buffers()[i]);
+  }
+#endif  // COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
+}
+
+DecoderBufferAllocator::ReuseAllcator::ReuseAllcator(
+    Allocator* fallback_allocator, std::size_t initial_capacity,
+    std::size_t allocation_increment)
+    : BidirectionalFitReuseAllocator(fallback_allocator, initial_capacity,
+                                     kSmallAllocationThreshold,
+                                     allocation_increment) {}
+
+DecoderBufferAllocator::ReuseAllcator::FreeBlockSet::iterator
+DecoderBufferAllocator::ReuseAllcator::FindBestFreeBlock(
+    std::size_t size, std::size_t alignment, intptr_t context,
+    FreeBlockSet::iterator begin, FreeBlockSet::iterator end,
+    bool* allocate_from_front) {
+  SB_DCHECK(allocate_from_front);
+
+  auto free_block_iter =
+      FindFreeBlock(size, alignment, begin, end, allocate_from_front);
+  if (free_block_iter != end) {
+    return free_block_iter;
+  }
+
+  *allocate_from_front = IsLargeAllocation(size);
+  *allocate_from_front = context == 1;
+  if (*allocate_from_front) {
+    for (FreeBlockSet::iterator it = begin; it != end; ++it) {
+      if (it->CanFullfill(1, alignment)) {
+        return it;
+      }
+    }
+
+    return end;
+  }
+
+  FreeBlockSet::reverse_iterator rbegin(end);
+  FreeBlockSet::reverse_iterator rend(begin);
+  for (FreeBlockSet::reverse_iterator it = rbegin; it != rend; ++it) {
+    if (it->CanFullfill(1, alignment)) {
+      return --it.base();
+    }
+  }
+  return end;
+}
+
+void DecoderBufferAllocator::UpdateAllocationRecord(
+    std::size_t blocks /*= 1*/) const {
+#if !defined(COBALT_BUILD_TYPE_GOLD)
+  // This code is not quite multi-thread safe but is safe enough for tracking
+  // purposes.
+  static std::size_t max_allocated = COBALT_MEDIA_BUFFER_INITIAL_CAPACITY / 2;
+  static std::size_t max_capacity = COBALT_MEDIA_BUFFER_INITIAL_CAPACITY;
+  static std::size_t max_blocks = 1;
+
+  bool new_max_reached = false;
+  if (reuse_allcator_->GetAllocated() >
+      max_allocated + kAllocationRecordGranularity) {
+    max_allocated = reuse_allcator_->GetAllocated();
+    new_max_reached = true;
+  }
+  if (reuse_allcator_->GetCapacity() >
+      max_capacity + kAllocationRecordGranularity) {
+    max_capacity = reuse_allcator_->GetCapacity();
+    new_max_reached = true;
+  }
+  if (blocks > max_blocks) {
+    max_blocks = blocks;
+    new_max_reached = true;
+  }
+  if (new_max_reached) {
+    SB_LOG(ERROR) << "======== New Media Buffer Allocation Record ========\n"
+                  << "\tMax Allocated: " << max_allocated
+                  << "  Max Capacity: " << max_capacity
+                  << "  Max Blocks: " << max_blocks;
+    // TODO: Enable the following line once PrintAllocations() accepts max line
+    // as a parameter.
+    // reuse_allcator_->PrintAllocations();
+  }
+#endif  // !defined(COBALT_BUILD_TYPE_GOLD)
 }
 
 }  // namespace media
diff --git a/src/cobalt/media/decoder_buffer_allocator.h b/src/cobalt/media/decoder_buffer_allocator.h
index 8fa87f2..303708a 100644
--- a/src/cobalt/media/decoder_buffer_allocator.h
+++ b/src/cobalt/media/decoder_buffer_allocator.h
@@ -17,23 +17,48 @@
 
 #include "base/compiler_specific.h"
 #include "cobalt/media/base/decoder_buffer.h"
-#include "nb/memory_pool.h"
-#include "starboard/common/locked_ptr.h"
+#include "nb/bidirectional_fit_reuse_allocator.h"
+#include "nb/starboard_memory_allocator.h"
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/mutex.h"
 
 namespace cobalt {
 namespace media {
 
+#if COBALT_MEDIA_BUFFER_INITIAL_CAPACITY > 0 || \
+    COBALT_MEDIA_BUFFER_ALLOCATION_UNIT > 0
+#define COBALT_MEDIA_BUFFER_USING_MEMORY_POOL 1
+#endif  // COBALT_MEDIA_BUFFER_INITIAL_CAPACITY == 0 &&
+        // COBALT_MEDIA_BUFFER_ALLOCATION_UNIT == 0
+
 class DecoderBufferAllocator : public DecoderBuffer::Allocator {
  public:
   DecoderBufferAllocator();
   ~DecoderBufferAllocator() OVERRIDE;
 
-  void* Allocate(Type type, size_t size, size_t alignment) OVERRIDE;
-  void Free(Type type, void* ptr) OVERRIDE;
+  Allocations Allocate(size_t size, size_t alignment,
+                       intptr_t context) OVERRIDE;
+  void Free(Allocations allocations) OVERRIDE;
 
  private:
-  void* memory_block_;
-  starboard::LockedPtr<nb::FirstFitMemoryPool> memory_pool_;
+#if COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
+  class ReuseAllcator : public nb::BidirectionalFitReuseAllocator {
+   public:
+    ReuseAllcator(Allocator* fallback_allocator, std::size_t initial_capacity,
+                  std::size_t allocation_increment);
+
+    FreeBlockSet::iterator FindBestFreeBlock(
+        std::size_t size, std::size_t alignment, intptr_t context,
+        FreeBlockSet::iterator begin, FreeBlockSet::iterator end,
+        bool* allocate_from_front) SB_OVERRIDE;
+  };
+
+  void UpdateAllocationRecord(std::size_t blocks = 1) const;
+
+  starboard::Mutex mutex_;
+  nb::StarboardMemoryAllocator fallback_allocator_;
+  starboard::scoped_ptr<ReuseAllcator> reuse_allcator_;
+#endif  // COBALT_MEDIA_BUFFER_USING_MEMORY_POOL
 };
 
 }  // namespace media
diff --git a/src/cobalt/media/filters/shell_au.cc b/src/cobalt/media/filters/shell_au.cc
index c1ac30d..0472a1b 100644
--- a/src/cobalt/media/filters/shell_au.cc
+++ b/src/cobalt/media/filters/shell_au.cc
@@ -14,6 +14,8 @@
 
 #include "cobalt/media/filters/shell_au.h"
 
+#include <algorithm>
+
 #include "cobalt/media/base/decoder_buffer.h"
 #include "cobalt/media/base/endian_util.h"
 #include "cobalt/media/base/timestamp_constants.h"
@@ -33,6 +35,38 @@
   return true;
 }
 
+bool ReadBytes(uint64 offset, size_t size, DecoderBuffer* decoder_buffer,
+               uint64 decoder_buffer_offset, ShellDataSourceReader* reader) {
+  size_t buffer_index = 0;
+  auto& allocations = decoder_buffer->allocations();
+  while (size > 0) {
+    if (buffer_index >= allocations.number_of_buffers()) {
+      NOTREACHED();
+      return false;
+    }
+    size_t buffer_size = allocations.buffer_sizes()[buffer_index];
+    if (buffer_size <= decoder_buffer_offset) {
+      decoder_buffer_offset -= buffer_size;
+    } else {
+      size_t bytes_to_read = std::min(
+          size, buffer_size - static_cast<size_t>(decoder_buffer_offset));
+      uint8_t* destination =
+          static_cast<uint8_t*>(allocations.buffers()[buffer_index]);
+      if (reader->BlockingRead(offset, bytes_to_read,
+                               destination + decoder_buffer_offset) !=
+          bytes_to_read) {
+        DLOG(ERROR) << "unable to download AU";
+        return false;
+      }
+      decoder_buffer_offset = 0;
+      size -= bytes_to_read;
+    }
+    ++buffer_index;
+  }
+
+  return true;
+}
+
 // ==== ShellEndOfStreamAU ==================================================
 
 class ShellEndOfStreamAU : public ShellAU {
@@ -114,9 +148,7 @@
 
 bool ShellAudioAU::Read(ShellDataSourceReader* reader, DecoderBuffer* buffer) {
   DCHECK_LE(size_ + prepend_size_, buffer->data_size());
-  if (!ReadBytes(offset_, size_, buffer->writable_data() + prepend_size_,
-                 reader))
-    return false;
+  if (!ReadBytes(offset_, size_, buffer, prepend_size_, reader)) return false;
 
   if (!parser_->Prepend(this, buffer)) {
     DLOG(ERROR) << "prepend fail";
@@ -183,20 +215,21 @@
 bool ShellVideoAU::Read(ShellDataSourceReader* reader, DecoderBuffer* buffer) {
   size_t au_left = size_;                      // bytes left in the AU
   uint64 au_offset = offset_;                  // offset to read in the reader
-  size_t buf_left = buffer->allocated_size();  // bytes left in the buffer
+  size_t buf_left = buffer->data_size();       // bytes left in the buffer
   // The current write position in the buffer
-  uint8* buf = buffer->writable_data() + prepend_size_;
+  int64_t decoder_buffer_offset = prepend_size_;
 
   // The NALU is stored as [size][data][size][data].... We are going to
   // transform it into [start code][data][start code][data]....
   // The length of size is indicated by length_of_nalu_size_
-  while (au_left >= length_of_nalu_size_ && buf_left >= kAnnexBStartCode) {
+  while (au_left >= length_of_nalu_size_ && buf_left >= kAnnexBStartCodeSize) {
     uint8 size_buf[4];
     uint32 nal_size;
 
     // Store [start code]
-    endian_util::store_uint32_big_endian(kAnnexBStartCode, buf);
-    buf += kAnnexBStartCodeSize;
+    buffer->allocations().Write(decoder_buffer_offset, kAnnexBStartCode,
+                                kAnnexBStartCodeSize);
+    decoder_buffer_offset += kAnnexBStartCodeSize;
     buf_left -= kAnnexBStartCodeSize;
 
     // Read [size]
@@ -218,9 +251,12 @@
     if (au_left < nal_size || buf_left < nal_size) break;
 
     // Read the [data] from reader into buf
-    if (!ReadBytes(au_offset, nal_size, buf, reader)) return false;
+    if (!ReadBytes(au_offset, nal_size, buffer, decoder_buffer_offset,
+                   reader)) {
+      return false;
+    }
 
-    buf += nal_size;
+    decoder_buffer_offset += nal_size;
     au_offset += nal_size;
     au_left -= nal_size;
     buf_left -= nal_size;
@@ -231,7 +267,7 @@
     return false;
   }
 
-  size_ = buf - buffer->writable_data();
+  size_ = decoder_buffer_offset;
   buffer->shrink_to(size_);
 
   if (!parser_->Prepend(this, buffer)) {
diff --git a/src/cobalt/media/filters/shell_au.h b/src/cobalt/media/filters/shell_au.h
index 3fa5527..ffd827a 100644
--- a/src/cobalt/media/filters/shell_au.h
+++ b/src/cobalt/media/filters/shell_au.h
@@ -24,9 +24,8 @@
 
 class ShellParser;
 
-// AnnexB start code is 4 bytes 0x00000001 big-endian
 static const int kAnnexBStartCodeSize = 4;
-static const uint32 kAnnexBStartCode = 0x00000001;
+static const uint8_t kAnnexBStartCode[] = {0, 0, 0, 1};
 
 // The basic unit of currency between ShellDemuxer and ShellParser, the ShellAU
 // defines all needed information for a given AccessUnit (Frame) of encoded
diff --git a/src/cobalt/media/filters/shell_avc_parser.cc b/src/cobalt/media/filters/shell_avc_parser.cc
index ed3873f..70756cb 100644
--- a/src/cobalt/media/filters/shell_avc_parser.cc
+++ b/src/cobalt/media/filters/shell_avc_parser.cc
@@ -54,35 +54,37 @@
     NOTREACHED() << "bad input to Prepend()";
     return false;
   }
-  uint8* prepend_buffer = buffer->writable_data();
-  if (!prepend_buffer) {
-    NOTREACHED() << "empty/undersized buffer to Prepend()";
-    return false;
-  }
   if (au->GetType() == DemuxerStream::VIDEO) {
-    if (au->AddPrepend())
-      SbMemoryCopy(prepend_buffer, video_prepend_, video_prepend_size_);
+    if (au->AddPrepend()) {
+      if (buffer->data_size() <= video_prepend_size_) {
+        NOTREACHED() << "empty/undersized buffer to Prepend()";
+        return false;
+      }
+      buffer->allocations().Write(0, video_prepend_, video_prepend_size_);
+    }
   } else if (au->GetType() == DemuxerStream::AUDIO) {
-#if defined(COBALT_WIN)
-    // We use raw AAC instead of ADTS on these platforms.
-    DCHECK(audio_prepend_.empty());
-    return true;
-#endif
-    if (audio_prepend_.empty())  // valid ADTS header not available
+    if (audio_prepend_.size() < 6) {
+      // valid ADTS header not available
       return false;
+    }
+    if (buffer->data_size() <= audio_prepend_.size()) {
+      NOTREACHED() << "empty/undersized buffer to Prepend()";
+      return false;
+    }
     // audio, need to copy ADTS header and then add buffer size
     uint32 buffer_size = au->GetSize() + audio_prepend_.size();
     // we can't express an AU size larger than 13 bits, something's bad here.
     if (buffer_size & 0xffffe000) {
       return false;
     }
-    SbMemoryCopy(prepend_buffer, &audio_prepend_[0], audio_prepend_.size());
+    std::vector<uint8_t> audio_prepend(audio_prepend_);
     // OR size into buffer, byte 3 gets 2 MSb of 13-bit size
-    prepend_buffer[3] |= (uint8)((buffer_size & 0x00001800) >> 11);
+    audio_prepend[3] |= (uint8)((buffer_size & 0x00001800) >> 11);
     // byte 4 gets bits 10-3 of size
-    prepend_buffer[4] = (uint8)((buffer_size & 0x000007f8) >> 3);
+    audio_prepend[4] = (uint8)((buffer_size & 0x000007f8) >> 3);
     // byte 5 gets bits 2-0 of size
-    prepend_buffer[5] |= (uint8)((buffer_size & 0x00000007) << 5);
+    audio_prepend[5] |= (uint8)((buffer_size & 0x00000007) << 5);
+    buffer->allocations().Write(0, audio_prepend.data(), audio_prepend.size());
   } else {
     NOTREACHED() << "unsupported demuxer stream type.";
     return false;
@@ -424,14 +426,14 @@
     return false;
   }
   // start code for sps comes first
-  endian_util::store_uint32_big_endian(kAnnexBStartCode, video_prepend_);
+  SbMemoryCopy(video_prepend_, kAnnexBStartCode, kAnnexBStartCodeSize);
   // followed by sps body
   SbMemoryCopy(video_prepend_ + kAnnexBStartCodeSize, sps, sps_size);
   int prepend_offset = kAnnexBStartCodeSize + sps_size;
   if (pps_size > 0) {
     // pps start code comes next
-    endian_util::store_uint32_big_endian(kAnnexBStartCode,
-                                         video_prepend_ + prepend_offset);
+    SbMemoryCopy(video_prepend_ + prepend_offset, kAnnexBStartCode,
+                 kAnnexBStartCodeSize);
     prepend_offset += kAnnexBStartCodeSize;
     // followed by pps
     SbMemoryCopy(video_prepend_ + prepend_offset, pps, pps_size);
@@ -463,11 +465,6 @@
   audio_prepend_[4] = 0;
   audio_prepend_[5] &= 0x1f;
 
-#if defined(COBALT_WIN)
-  // We use raw AAC instead of ADTS on these platforms.
-  audio_prepend_.clear();
-#endif  // defined(COBALT_WIN)
-
   const bool kSbrInMimetype = false;
   audio_config_.Initialize(
       kCodecAAC, kSampleFormatS16, aac.GetChannelLayout(kSbrInMimetype),
diff --git a/src/cobalt/media/filters/shell_demuxer.cc b/src/cobalt/media/filters/shell_demuxer.cc
index 6704e5e..e81de45 100644
--- a/src/cobalt/media/filters/shell_demuxer.cc
+++ b/src/cobalt/media/filters/shell_demuxer.cc
@@ -38,7 +38,8 @@
     : demuxer_(demuxer),
       type_(type),
       last_buffer_timestamp_(kNoTimestamp),
-      stopped_(false) {
+      stopped_(false),
+      total_buffer_size_(0) {
   TRACE_EVENT0("media_stack", "ShellDemuxerStream::ShellDemuxerStream()");
   DCHECK(demuxer_);
 }
@@ -68,6 +69,7 @@
       TRACE_EVENT0("media_stack", "ShellDemuxerStream::Read() EOS sent.");
     } else {
       // Do not pop EOS buffers, so that subsequent read requests also get EOS
+      total_buffer_size_ -= buffer->data_size();
       buffer_queue_.pop_front();
     }
     read_cb.Run(
@@ -134,6 +136,9 @@
   } else {
     // save the buffer for next read request
     buffer_queue_.push_back(buffer);
+    if (!buffer->end_of_stream()) {
+      total_buffer_size_ += buffer->data_size();
+    }
   }
 }
 
@@ -142,12 +147,18 @@
   return last_buffer_timestamp_;
 }
 
+size_t ShellDemuxerStream::GetTotalBufferSize() const {
+  base::AutoLock auto_lock(lock_);
+  return total_buffer_size_;
+}
+
 void ShellDemuxerStream::FlushBuffers() {
   TRACE_EVENT0("media_stack", "ShellDemuxerStream::FlushBuffers()");
   base::AutoLock auto_lock(lock_);
   // TODO: Investigate if the following warning is valid.
   DLOG_IF(WARNING, !read_queue_.empty()) << "Read requests should be empty";
   buffer_queue_.clear();
+  total_buffer_size_ = 0;
   last_buffer_timestamp_ = kNoTimestamp;
 }
 
@@ -156,6 +167,7 @@
   DCHECK(demuxer_->MessageLoopBelongsToCurrentThread());
   base::AutoLock auto_lock(lock_);
   buffer_queue_.clear();
+  total_buffer_size_ = 0;
   last_buffer_timestamp_ = kNoTimestamp;
   // fulfill any pending callbacks with EOS buffers set to end timestamp
   for (ReadQueue::iterator it = read_queue_.begin(); it != read_queue_.end();
@@ -345,8 +357,19 @@
   DCHECK(requested_au_);
 
   if (requested_au_ && !stopped_) {
-    // Note that this relies on "new DecoderBuffer" returns NULL if it is unable
-    // to allocate any DecoderBuffer.
+    size_t total_buffer_size = audio_demuxer_stream_->GetTotalBufferSize() +
+                               video_demuxer_stream_->GetTotalBufferSize();
+    if (total_buffer_size >= COBALT_MEDIA_BUFFER_PROGRESSIVE_BUDGET) {
+      // Retry after 100 milliseconds.
+      const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(100);
+      blocking_thread_.message_loop()->PostDelayedTask(
+          FROM_HERE,
+          base::Bind(&ShellDemuxer::AllocateBuffer, base::Unretained(this)),
+          kDelay);
+      return;
+    }
+    // Note that "new DecoderBuffer" may return NULL if it is unable to allocate
+    // any DecoderBuffer.
     scoped_refptr<DecoderBuffer> decoder_buffer(
         DecoderBuffer::Create(buffer_allocator_, requested_au_->GetType(),
                               requested_au_->GetMaxSize()));
diff --git a/src/cobalt/media/filters/shell_demuxer.h b/src/cobalt/media/filters/shell_demuxer.h
index 8aab57d..f976278 100644
--- a/src/cobalt/media/filters/shell_demuxer.h
+++ b/src/cobalt/media/filters/shell_demuxer.h
@@ -61,6 +61,7 @@
   void FlushBuffers();
   void Stop();
   base::TimeDelta GetLastBufferTimestamp() const;
+  size_t GetTotalBufferSize() const;
 
  private:
   // The Ranges object doesn't offer a complement object so we rebuild
@@ -91,6 +92,8 @@
   typedef std::deque<ReadCB> ReadQueue;
   ReadQueue read_queue_;
 
+  size_t total_buffer_size_;
+
   DISALLOW_COPY_AND_ASSIGN(ShellDemuxerStream);
 };
 
diff --git a/src/cobalt/media/formats/webm/webm_cluster_parser.cc b/src/cobalt/media/formats/webm/webm_cluster_parser.cc
index a8fac84..38a1234 100644
--- a/src/cobalt/media/formats/webm/webm_cluster_parser.cc
+++ b/src/cobalt/media/formats/webm/webm_cluster_parser.cc
@@ -509,9 +509,9 @@
     // TODO(wolenetz/acolwell): Validate and use a common cross-parser TrackId
     // type with remapped bytestream track numbers and allow multiple tracks as
     // applicable. See https://crbug.com/341581.
-    buffer = StreamParserBuffer::CopyFrom(
-        buffer_allocator_, data + data_offset, size - data_offset, additional,
-        additional_size, is_keyframe, buffer_type, track_num);
+    buffer = StreamParserBuffer::CopyFrom(buffer_allocator_, data + data_offset,
+                                          size - data_offset, is_keyframe,
+                                          buffer_type, track_num);
 
     if (decrypt_config) buffer->set_decrypt_config(decrypt_config.Pass());
   } else {
@@ -527,8 +527,7 @@
     // applicable. See https://crbug.com/341581.
     buffer = StreamParserBuffer::CopyFrom(
         buffer_allocator_, reinterpret_cast<const uint8_t*>(content.data()),
-        content.length(), &side_data[0], side_data.size(), true, buffer_type,
-        track_num);
+        content.length(), true, buffer_type, track_num);
   }
 
   buffer->set_timestamp(timestamp);
diff --git a/src/cobalt/media/media.gyp b/src/cobalt/media/media.gyp
index c287bdb..30a6943 100644
--- a/src/cobalt/media/media.gyp
+++ b/src/cobalt/media/media.gyp
@@ -26,8 +26,11 @@
         'fetcher_buffered_data_source.h',
         'media_module.cc',
         'media_module.h',
+        'media_module_<(sb_media_platform).cc',
         'media_module_stub.cc',
         'media_module_stub.h',
+        'shell_media_platform_<(sb_media_platform).cc',
+        'shell_media_platform_<(sb_media_platform).h',
         'shell_video_data_allocator_common.cc',
         'shell_video_data_allocator_common.h',
         'web_media_player_factory.h',
@@ -41,34 +44,12 @@
         '<(DEPTH)/media/media.gyp:media',
       ],
       'conditions': [
-        ['OS=="starboard"', {
-          'sources': [
-            'media_module_<(sb_media_platform).cc',
-            'shell_media_platform_<(sb_media_platform).cc',
-            'shell_media_platform_<(sb_media_platform).h',
-          ],
-        }],
-        ['OS=="starboard" and sb_media_platform == "ps4"', {
+        ['sb_media_platform == "ps4"', {
           'sources': [
             'decoder_working_memory_allocator_impl_ps4.cc',
             'decoder_working_memory_allocator_impl_ps4.h',
           ],
         }],
-        ['OS=="lb_shell"', {
-          'sources': [
-            'media_module_<(actual_target_arch).cc',
-          ],
-          'include_dirs': [
-            '<(lbshell_root)/src',
-            '<(lbshell_root)/src/platform/<(target_arch)',
-          ],
-        }],
-        ['OS=="lb_shell" and target_arch == "ps3"', {
-          'sources': [
-            'shell_media_platform_ps3.cc',
-            'shell_media_platform_ps3.h',
-          ],
-        }],
         ['enable_map_to_mesh == 1', {
           'defines' : ['ENABLE_MAP_TO_MESH'],
         }],
diff --git a/src/cobalt/network/network.gyp b/src/cobalt/network/network.gyp
index e77f82c..5d7efa7 100644
--- a/src/cobalt/network/network.gyp
+++ b/src/cobalt/network/network.gyp
@@ -40,6 +40,9 @@
         'persistent_cookie_store.cc',
         'persistent_cookie_store.h',
         'proxy_config_service.h',
+        'starboard/network_system.cc',
+        'starboard/proxy_config_service.cc',
+        'starboard/user_agent_string_factory_starboard.cc',
         'switches.cc',
         'switches.h',
         'url_request_context.cc',
@@ -76,19 +79,6 @@
             'ENABLE_NETWORK_LOGGING',
           ],
         }],
-        ['OS=="starboard"', {
-          'sources': [
-            'starboard/network_system.cc',
-            'starboard/proxy_config_service.cc',
-            'starboard/user_agent_string_factory_starboard.cc',
-          ],
-        }, {
-          'sources': [
-            '<(actual_target_arch)/network_system.cc',
-            '<(actual_target_arch)/proxy_config_service.cc',
-            '<(actual_target_arch)/user_agent_string_factory_<(actual_target_arch).cc',
-          ],
-        }],
       ],
       'export_dependent_settings': [
         '<(DEPTH)/net/net.gyp:net',
diff --git a/src/cobalt/page_visibility/page_visibility.gyp b/src/cobalt/page_visibility/page_visibility.gyp
index e943727..015f78ac 100644
--- a/src/cobalt/page_visibility/page_visibility.gyp
+++ b/src/cobalt/page_visibility/page_visibility.gyp
@@ -14,7 +14,7 @@
 
 {
   'variables': {
-    'cobalt_code': 1,
+    'sb_pedantic_warnings': 1,
   },
   'targets': [
     {
diff --git a/src/cobalt/page_visibility/page_visibility_state.cc b/src/cobalt/page_visibility/page_visibility_state.cc
index 56081ea..ce7efc5 100644
--- a/src/cobalt/page_visibility/page_visibility_state.cc
+++ b/src/cobalt/page_visibility/page_visibility_state.cc
@@ -14,9 +14,16 @@
 
 #include "cobalt/page_visibility/page_visibility_state.h"
 
+#include "base/debug/trace_event.h"
+#include "base/stringprintf.h"
+
 namespace cobalt {
 namespace page_visibility {
 
+#define STATE_STRING(state)                                             \
+  base::StringPrintf("%s (%d)", base::GetApplicationStateString(state), \
+                     static_cast<int>(state))
+
 namespace {
 // Converts an ApplicationState to a VisibilityState.
 VisibilityState ToVisibilityState(base::ApplicationState state) {
@@ -30,7 +37,7 @@
     case base::kApplicationStateStopped:
       return kVisibilityStateHidden;
     default:
-      NOTREACHED() << "Invalid Application State: " << state;
+      NOTREACHED() << "Invalid Application State: " << STATE_STRING(state);
       return kVisibilityStateHidden;
   }
 }
@@ -45,22 +52,27 @@
     case base::kApplicationStateStopped:
       return false;
     default:
-      NOTREACHED() << "Invalid Application State: " << state;
+      NOTREACHED() << "Invalid Application State: " << STATE_STRING(state);
       return false;
   }
 }
 }  // namespace
 
 PageVisibilityState::PageVisibilityState()
-    : application_state_(base::kApplicationStateStarted) {}
+    : application_state_(base::kApplicationStateStarted) {
+  DLOG(INFO) << __FUNCTION__
+             << ": app_state=" << STATE_STRING(application_state_);
+}
 
 PageVisibilityState::PageVisibilityState(
     base::ApplicationState initial_application_state)
     : application_state_(initial_application_state) {
+  DLOG(INFO) << __FUNCTION__
+             << ": app_state=" << STATE_STRING(application_state_);
   DCHECK((application_state_ == base::kApplicationStateStarted) ||
          (application_state_ == base::kApplicationStatePreloading) ||
          (application_state_ == base::kApplicationStatePaused))
-      << "application_state_=" << application_state_;
+      << "application_state_=" << STATE_STRING(application_state_);
 }
 
 bool PageVisibilityState::HasWindowFocus() const {
@@ -72,9 +84,12 @@
 }
 
 void PageVisibilityState::SetApplicationState(base::ApplicationState state) {
+  TRACE_EVENT1("cobalt::page_visibility",
+               "PageVisibilityState::SetApplicationState", "state",
+               STATE_STRING(state).c_str());
   if (application_state_ == state) {
     DLOG(WARNING) << __FUNCTION__ << ": Attempt to re-enter "
-                  << application_state_;
+                  << STATE_STRING(application_state_);
     return;
   }
 
@@ -83,30 +98,47 @@
     switch (application_state_) {
       case base::kApplicationStatePaused:
         DCHECK(state == base::kApplicationStateSuspended ||
-               state == base::kApplicationStateStarted);
+               state == base::kApplicationStateStarted)
+            << ": application_state_=" << STATE_STRING(application_state_)
+            << ", state=" << STATE_STRING(state);
+
         break;
       case base::kApplicationStatePreloading:
         DCHECK(state == base::kApplicationStateSuspended ||
-               state == base::kApplicationStateStarted);
+               state == base::kApplicationStateStarted)
+            << ": application_state_=" << STATE_STRING(application_state_)
+            << ", state=" << STATE_STRING(state);
+        break;
       case base::kApplicationStateStarted:
-        DCHECK(state == base::kApplicationStatePaused);
+        DCHECK(state == base::kApplicationStatePaused)
+            << ": application_state_=" << STATE_STRING(application_state_)
+            << ", state=" << STATE_STRING(state);
         break;
       case base::kApplicationStateStopped:
         DCHECK(state == base::kApplicationStatePreloading ||
-               state == base::kApplicationStateStarted);
+               state == base::kApplicationStateStarted)
+            << ": application_state_=" << STATE_STRING(application_state_)
+            << ", state=" << STATE_STRING(state);
         break;
       case base::kApplicationStateSuspended:
         DCHECK(state == base::kApplicationStatePaused ||
-               state == base::kApplicationStateStopped);
+               state == base::kApplicationStateStopped)
+            << ": application_state_=" << STATE_STRING(application_state_)
+            << ", state=" << STATE_STRING(state);
         break;
       default:
-        NOTREACHED() << application_state_;
+        NOTREACHED() << ": application_state_="
+                     << STATE_STRING(application_state_)
+                     << ", state=" << STATE_STRING(state);
+
         break;
     }
   }
 
   bool old_has_focus = HasFocus(application_state_);
   VisibilityState old_visibility_state = ToVisibilityState(application_state_);
+  DLOG(INFO) << __FUNCTION__ << ": " << STATE_STRING(application_state_)
+             << " -> " << STATE_STRING(state);
   application_state_ = state;
   bool has_focus = HasFocus(application_state_);
   VisibilityState visibility_state = ToVisibilityState(application_state_);
diff --git a/src/cobalt/render_tree/resource_provider_stub.h b/src/cobalt/render_tree/resource_provider_stub.h
index 826c1ea..aee3f69 100644
--- a/src/cobalt/render_tree/resource_provider_stub.h
+++ b/src/cobalt/render_tree/resource_provider_stub.h
@@ -68,6 +68,7 @@
     return descriptor_;
   }
 
+  void ReleaseMemory() { memory_.reset(); }
   uint8* GetMemory() OVERRIDE { return memory_.get(); }
 
  private:
@@ -106,18 +107,16 @@
                       Internal::kRobotoXHeightSizeMultiplier * font_size),
         glyph_bounds_(
             0,
-            -std::max(
-                static_cast<int>(
-                    Internal::kDefaultCharacterRobotoGlyphHeightSizeMultiplier *
-                    font_size),
-                1),
+            std::max(
+                Internal::kDefaultCharacterRobotoGlyphHeightSizeMultiplier *
+                    font_size,
+                1.0f),
             Internal::kDefaultCharacterRobotoGlyphWidthSizeMultiplier *
                 font_size,
             std::max(
-                static_cast<int>(
-                    Internal::kDefaultCharacterRobotoGlyphHeightSizeMultiplier *
-                    font_size),
-                1)) {}
+                Internal::kDefaultCharacterRobotoGlyphHeightSizeMultiplier *
+                    font_size,
+                1.0f)) {}
 
   TypefaceId GetTypefaceId() const OVERRIDE { return typeface_->GetId(); }
 
@@ -215,6 +214,9 @@
 // Return the stub versions defined above for each resource.
 class ResourceProviderStub : public ResourceProvider {
  public:
+  ResourceProviderStub() : release_image_data_(false) {}
+  explicit ResourceProviderStub(bool release_image_data)
+      : release_image_data_(release_image_data) {}
   ~ResourceProviderStub() OVERRIDE {}
 
   void Finish() OVERRIDE {}
@@ -239,6 +241,9 @@
   scoped_refptr<Image> CreateImage(scoped_ptr<ImageData> source_data) OVERRIDE {
     scoped_ptr<ImageDataStub> skia_source_data(
         base::polymorphic_downcast<ImageDataStub*>(source_data.release()));
+    if (release_image_data_) {
+      skia_source_data->ReleaseMemory();
+    }
     return make_scoped_refptr(new ImageStub(skia_source_data.Pass()));
   }
 
@@ -377,6 +382,8 @@
     UNREFERENCED_PARAMETER(root);
     return scoped_refptr<Image>(NULL);
   }
+
+  bool release_image_data_;
 };
 
 }  // namespace render_tree
diff --git a/src/cobalt/renderer/backend/backend.gyp b/src/cobalt/renderer/backend/backend.gyp
index b2f6e71..59c9b4a 100644
--- a/src/cobalt/renderer/backend/backend.gyp
+++ b/src/cobalt/renderer/backend/backend.gyp
@@ -25,17 +25,7 @@
       'dependencies': [
         '<(DEPTH)/cobalt/base/base.gyp:base',
         '<(DEPTH)/cobalt/math/math.gyp:math',
-      ],
-      'conditions': [
-        ['OS=="starboard"', {
-          'dependencies': [
-            '<(DEPTH)/cobalt/renderer/backend/starboard/platform_backend.gyp:renderer_platform_backend',
-          ],
-        }, {
-          'dependencies': [
-            '<(DEPTH)/cobalt/renderer/backend/<(actual_target_arch)/platform_backend.gyp:renderer_platform_backend',
-          ],
-        }],
+        '<(DEPTH)/cobalt/renderer/backend/starboard/platform_backend.gyp:renderer_platform_backend',
       ],
     },
   ],
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_object.cc b/src/cobalt/renderer/rasterizer/egl/draw_object.cc
index 1cae058..9dc8082 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_object.cc
+++ b/src/cobalt/renderer/rasterizer/egl/draw_object.cc
@@ -34,6 +34,8 @@
 DrawObject::BaseState::BaseState(const BaseState& other)
     : transform(other.transform),
       scissor(other.scissor),
+      rounded_scissor_rect(other.rounded_scissor_rect),
+      rounded_scissor_corners(other.rounded_scissor_corners),
       opacity(other.opacity) {}
 
 DrawObject::DrawObject(const BaseState& base_state)
@@ -72,6 +74,30 @@
   };
   GL_CALL(glUniform4fv(rect_uniform, 1, rect_data));
 
+  // Tweak corners that are square-ish so they have values that play
+  // nicely with the shader. Interpolating x^2 / a^2 + y^2 / b^2 does not
+  // work well when |a| or |b| are very small.
+  if (inset_corners.top_left.horizontal <= 0.5f ||
+      inset_corners.top_left.vertical <= 0.5f) {
+    inset_corners.top_left.horizontal = 0.0f;
+    inset_corners.top_left.vertical = 0.0f;
+  }
+  if (inset_corners.top_right.horizontal <= 0.5f ||
+      inset_corners.top_right.vertical <= 0.5f) {
+    inset_corners.top_right.horizontal = 0.0f;
+    inset_corners.top_right.vertical = 0.0f;
+  }
+  if (inset_corners.bottom_left.horizontal <= 0.5f ||
+      inset_corners.bottom_left.vertical <= 0.5f) {
+    inset_corners.bottom_left.horizontal = 0.0f;
+    inset_corners.bottom_left.vertical = 0.0f;
+  }
+  if (inset_corners.bottom_right.horizontal <= 0.5f ||
+      inset_corners.bottom_right.vertical <= 0.5f) {
+    inset_corners.bottom_right.horizontal = 0.0f;
+    inset_corners.bottom_right.vertical = 0.0f;
+  }
+
   // The corners data is a mat4 with each vector representing a corner
   // (ordered top left, top right, bottom left, bottom right). Each corner
   // vec4 represents (start.xy, radius.xy).
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_object.h b/src/cobalt/renderer/rasterizer/egl/draw_object.h
index 691b06c..cc40d09 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_object.h
+++ b/src/cobalt/renderer/rasterizer/egl/draw_object.h
@@ -43,6 +43,12 @@
 
     math::Matrix3F transform;
     math::Rect scissor;
+
+    // |rounded_scissor_rect| is only relevant when |rounded_scissor_corners|
+    // exists.
+    math::RectF rounded_scissor_rect;
+    OptionalRoundedCorners rounded_scissor_corners;
+
     float opacity;
   };
 
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rect_color_texture.h b/src/cobalt/renderer/rasterizer/egl/draw_rect_color_texture.h
index 1cc0862..85b356c 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_rect_color_texture.h
+++ b/src/cobalt/renderer/rasterizer/egl/draw_rect_color_texture.h
@@ -15,7 +15,6 @@
 #ifndef COBALT_RENDERER_RASTERIZER_EGL_DRAW_RECT_COLOR_TEXTURE_H_
 #define COBALT_RENDERER_RASTERIZER_EGL_DRAW_RECT_COLOR_TEXTURE_H_
 
-#include "base/callback.h"
 #include "cobalt/math/matrix3_f.h"
 #include "cobalt/math/rect_f.h"
 #include "cobalt/render_tree/color_rgba.h"
@@ -49,8 +48,6 @@
   math::RectF rect_;
   uint32_t color_;
   const backend::TextureEGL* texture_;
-  base::Closure draw_offscreen_;
-  base::Closure draw_onscreen_;
 
   uint8_t* vertex_buffer_;
   float texcoord_clamp_[4];   // texcoord clamping (min u, min v, max u, max v)
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rect_texture.h b/src/cobalt/renderer/rasterizer/egl/draw_rect_texture.h
index 18363a8..756d971 100644
--- a/src/cobalt/renderer/rasterizer/egl/draw_rect_texture.h
+++ b/src/cobalt/renderer/rasterizer/egl/draw_rect_texture.h
@@ -15,7 +15,6 @@
 #ifndef COBALT_RENDERER_RASTERIZER_EGL_DRAW_RECT_TEXTURE_H_
 #define COBALT_RENDERER_RASTERIZER_EGL_DRAW_RECT_TEXTURE_H_
 
-#include "base/callback.h"
 #include "cobalt/math/matrix3_f.h"
 #include "cobalt/math/rect_f.h"
 #include "cobalt/renderer/backend/egl/texture.h"
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rrect_color.cc b/src/cobalt/renderer/rasterizer/egl/draw_rrect_color.cc
new file mode 100644
index 0000000..c56a4ba
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/egl/draw_rrect_color.cc
@@ -0,0 +1,116 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/renderer/rasterizer/egl/draw_rrect_color.h"
+
+#include <GLES2/gl2.h>
+
+#include "cobalt/renderer/backend/egl/utils.h"
+#include "egl/generated_shader_impl.h"
+#include "starboard/memory.h"
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace egl {
+
+namespace {
+const int kVertexCount = 4;
+
+struct VertexAttributes {
+  float position[2];
+  float offset[2];
+  uint32_t color;
+};
+
+void SetVertex(VertexAttributes* vertex, float x, float y, uint32_t color) {
+  vertex->position[0] = x;
+  vertex->position[1] = y;
+  vertex->offset[0] = x;
+  vertex->offset[1] = y;
+  vertex->color = color;
+}
+}  // namespace
+
+DrawRRectColor::DrawRRectColor(GraphicsState* graphics_state,
+    const BaseState& base_state, const math::RectF& rect,
+    const render_tree::RoundedCorners& corners,
+    const render_tree::ColorRGBA& color)
+    : DrawObject(base_state),
+      rect_(rect),
+      corners_(corners),
+      vertex_buffer_(NULL) {
+  color_ = GetGLRGBA(color * base_state_.opacity);
+  corners_.Normalize(rect_);
+  graphics_state->ReserveVertexData(kVertexCount * sizeof(VertexAttributes));
+}
+
+void DrawRRectColor::ExecuteUpdateVertexBuffer(
+    GraphicsState* graphics_state,
+    ShaderProgramManager* program_manager) {
+  // Draw the rect with an extra pixel outset for anti-aliasing. The fragment
+  // shader will handle the rounded corners.
+  VertexAttributes attributes[kVertexCount];
+  math::RectF outer_rect(rect_);
+  outer_rect.Outset(1.0f, 1.0f);
+  SetVertex(&attributes[0], outer_rect.x(), outer_rect.y(), color_);
+  SetVertex(&attributes[1], outer_rect.right(), outer_rect.y(), color_);
+  SetVertex(&attributes[2], outer_rect.right(), outer_rect.bottom(), color_);
+  SetVertex(&attributes[3], outer_rect.x(), outer_rect.bottom(), color_);
+  vertex_buffer_ = graphics_state->AllocateVertexData(sizeof(attributes));
+  SbMemoryCopy(vertex_buffer_, attributes, sizeof(attributes));
+}
+
+void DrawRRectColor::ExecuteRasterize(
+    GraphicsState* graphics_state,
+    ShaderProgramManager* program_manager) {
+  ShaderProgram<ShaderVertexColorOffset,
+                ShaderFragmentColorRrect>* program;
+  program_manager->GetProgram(&program);
+  graphics_state->UseProgram(program->GetHandle());
+  graphics_state->UpdateClipAdjustment(
+      program->GetVertexShader().u_clip_adjustment());
+  graphics_state->UpdateTransformMatrix(
+      program->GetVertexShader().u_view_matrix(),
+      base_state_.transform);
+  graphics_state->Scissor(base_state_.scissor.x(), base_state_.scissor.y(),
+      base_state_.scissor.width(), base_state_.scissor.height());
+  graphics_state->VertexAttribPointer(
+      program->GetVertexShader().a_position(), 2, GL_FLOAT, GL_FALSE,
+      sizeof(VertexAttributes), vertex_buffer_ +
+      offsetof(VertexAttributes, position));
+  graphics_state->VertexAttribPointer(
+      program->GetVertexShader().a_color(), 4, GL_UNSIGNED_BYTE, GL_TRUE,
+      sizeof(VertexAttributes), vertex_buffer_ +
+      offsetof(VertexAttributes, color));
+  graphics_state->VertexAttribPointer(
+      program->GetVertexShader().a_offset(), 2, GL_FLOAT, GL_FALSE,
+      sizeof(VertexAttributes), vertex_buffer_ +
+      offsetof(VertexAttributes, offset));
+  graphics_state->VertexAttribFinish();
+  SetRRectUniforms(program->GetFragmentShader().u_rect(),
+                   program->GetFragmentShader().u_corners(),
+                   rect_, corners_, 0.5f);
+  GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, kVertexCount));
+}
+
+base::TypeId DrawRRectColor::GetTypeId() const {
+  return ShaderProgram<ShaderVertexColorOffset,
+                       ShaderFragmentColorRrect>::GetTypeId();
+}
+
+}  // namespace egl
+}  // namespace rasterizer
+}  // namespace renderer
+}  // namespace cobalt
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rrect_color.h b/src/cobalt/renderer/rasterizer/egl/draw_rrect_color.h
new file mode 100644
index 0000000..c5cd055
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/egl/draw_rrect_color.h
@@ -0,0 +1,56 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_RENDERER_RASTERIZER_EGL_DRAW_RRECT_COLOR_H_
+#define COBALT_RENDERER_RASTERIZER_EGL_DRAW_RRECT_COLOR_H_
+
+#include "cobalt/math/rect_f.h"
+#include "cobalt/render_tree/color_rgba.h"
+#include "cobalt/render_tree/rounded_corners.h"
+#include "cobalt/renderer/rasterizer/egl/draw_object.h"
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace egl {
+
+// Handles drawing a colored rounded rect.
+class DrawRRectColor : public DrawObject {
+ public:
+  DrawRRectColor(GraphicsState* graphics_state,
+                 const BaseState& base_state,
+                 const math::RectF& rect,
+                 const render_tree::RoundedCorners& corners,
+                 const render_tree::ColorRGBA& color);
+
+  void ExecuteUpdateVertexBuffer(GraphicsState* graphics_state,
+      ShaderProgramManager* program_manager) OVERRIDE;
+  void ExecuteRasterize(GraphicsState* graphics_state,
+      ShaderProgramManager* program_manager) OVERRIDE;
+  base::TypeId GetTypeId() const OVERRIDE;
+
+ private:
+  math::RectF rect_;
+  render_tree::RoundedCorners corners_;
+  uint32_t color_;
+
+  uint8_t* vertex_buffer_;
+};
+
+}  // namespace egl
+}  // namespace rasterizer
+}  // namespace renderer
+}  // namespace cobalt
+
+#endif  // COBALT_RENDERER_RASTERIZER_EGL_DRAW_RRECT_COLOR_H_
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rrect_color_texture.cc b/src/cobalt/renderer/rasterizer/egl/draw_rrect_color_texture.cc
new file mode 100644
index 0000000..bad11de
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/egl/draw_rrect_color_texture.cc
@@ -0,0 +1,180 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/renderer/rasterizer/egl/draw_rrect_color_texture.h"
+
+#include <GLES2/gl2.h>
+
+#include "base/basictypes.h"
+#include "cobalt/renderer/backend/egl/utils.h"
+#include "egl/generated_shader_impl.h"
+#include "starboard/memory.h"
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace egl {
+
+namespace {
+const int kVertexCount = 4;
+
+struct VertexAttributes {
+  float position[2];
+  float offset[2];
+  float texcoord[2];
+};
+
+void SetVertex(VertexAttributes* vertex, float x, float y, float u, float v) {
+  vertex->position[0] = x;
+  vertex->position[1] = y;
+  vertex->offset[0] = x;
+  vertex->offset[1] = y;
+  vertex->texcoord[0] = u;
+  vertex->texcoord[1] = v;
+}
+}  // namespace
+
+DrawRRectColorTexture::DrawRRectColorTexture(GraphicsState* graphics_state,
+    const BaseState& base_state, const math::RectF& rect,
+    const render_tree::ColorRGBA& color, const backend::TextureEGL* texture,
+    const math::Matrix3F& texcoord_transform,
+    bool clamp_texcoords)
+    : DrawObject(base_state),
+      texcoord_transform_(texcoord_transform),
+      rect_(rect),
+      texture_(texture),
+      vertex_buffer_(NULL),
+      clamp_texcoords_(clamp_texcoords),
+      tile_texture_(false) {
+  DCHECK(base_state_.rounded_scissor_corners);
+  color_ = color * base_state_.opacity;
+  graphics_state->ReserveVertexData(kVertexCount * sizeof(VertexAttributes));
+}
+
+void DrawRRectColorTexture::ExecuteUpdateVertexBuffer(
+    GraphicsState* graphics_state,
+    ShaderProgramManager* program_manager) {
+  VertexAttributes attributes[kVertexCount];
+  SetVertex(&attributes[0], rect_.x(), rect_.y(),
+      texcoord_transform_(0, 2), texcoord_transform_(1, 2));    // uv = (0,0)
+  SetVertex(&attributes[1], rect_.right(), rect_.y(),
+      texcoord_transform_(0, 0) + texcoord_transform_(0, 2),    // uv = (1,0)
+      texcoord_transform_(1, 0) + texcoord_transform_(1, 2));
+  SetVertex(&attributes[2], rect_.right(), rect_.bottom(),
+      texcoord_transform_(0, 0) + texcoord_transform_(0, 1) +   // uv = (1,1)
+          texcoord_transform_(0, 2),
+      texcoord_transform_(1, 0) + texcoord_transform_(1, 1) +
+          texcoord_transform_(1, 2));
+  SetVertex(&attributes[3], rect_.x(), rect_.bottom(),
+      texcoord_transform_(0, 1) + texcoord_transform_(0, 2),    // uv = (0,1)
+      texcoord_transform_(1, 1) + texcoord_transform_(1, 2));
+  vertex_buffer_ = graphics_state->AllocateVertexData(sizeof(attributes));
+  SbMemoryCopy(vertex_buffer_, attributes, sizeof(attributes));
+
+  // Find minimum and maximum texcoord values.
+  texcoord_clamp_[0] = attributes[0].texcoord[0];
+  texcoord_clamp_[1] = attributes[0].texcoord[1];
+  texcoord_clamp_[2] = attributes[0].texcoord[0];
+  texcoord_clamp_[3] = attributes[0].texcoord[1];
+  for (int i = 1; i < arraysize(attributes); ++i) {
+    float texcoord_u = attributes[i].texcoord[0];
+    float texcoord_v = attributes[i].texcoord[1];
+    if (texcoord_clamp_[0] > texcoord_u) {
+      texcoord_clamp_[0] = texcoord_u;
+    } else if (texcoord_clamp_[2] < texcoord_u) {
+      texcoord_clamp_[2] = texcoord_u;
+    }
+    if (texcoord_clamp_[1] > texcoord_v) {
+      texcoord_clamp_[1] = texcoord_v;
+    } else if (texcoord_clamp_[3] < texcoord_v) {
+      texcoord_clamp_[3] = texcoord_v;
+    }
+  }
+
+  tile_texture_ = texcoord_clamp_[0] < 0.0f || texcoord_clamp_[1] < 0.0f ||
+                  texcoord_clamp_[2] > 1.0f || texcoord_clamp_[3] > 1.0f;
+
+  if (clamp_texcoords_) {
+    // Inset 0.5-epsilon so the border texels are still sampled, but nothing
+    // beyond.
+    const float kTexelInset = 0.499f;
+    texcoord_clamp_[0] += kTexelInset / texture_->GetSize().width();
+    texcoord_clamp_[1] += kTexelInset / texture_->GetSize().height();
+    texcoord_clamp_[2] -= kTexelInset / texture_->GetSize().width();
+    texcoord_clamp_[3] -= kTexelInset / texture_->GetSize().height();
+  }
+}
+
+void DrawRRectColorTexture::ExecuteRasterize(
+    GraphicsState* graphics_state,
+    ShaderProgramManager* program_manager) {
+  ShaderProgram<ShaderVertexOffsetTexcoord,
+                ShaderFragmentTexcoordColorRrect>* program;
+  program_manager->GetProgram(&program);
+  graphics_state->UseProgram(program->GetHandle());
+  graphics_state->UpdateClipAdjustment(
+      program->GetVertexShader().u_clip_adjustment());
+  graphics_state->UpdateTransformMatrix(
+      program->GetVertexShader().u_view_matrix(),
+      base_state_.transform);
+  graphics_state->Scissor(base_state_.scissor.x(), base_state_.scissor.y(),
+      base_state_.scissor.width(), base_state_.scissor.height());
+  graphics_state->VertexAttribPointer(
+      program->GetVertexShader().a_position(), 2, GL_FLOAT, GL_FALSE,
+      sizeof(VertexAttributes), vertex_buffer_ +
+      offsetof(VertexAttributes, position));
+  graphics_state->VertexAttribPointer(
+      program->GetVertexShader().a_offset(), 2, GL_FLOAT, GL_FALSE,
+      sizeof(VertexAttributes), vertex_buffer_ +
+      offsetof(VertexAttributes, offset));
+  graphics_state->VertexAttribPointer(
+      program->GetVertexShader().a_texcoord(), 2, GL_FLOAT, GL_FALSE,
+      sizeof(VertexAttributes), vertex_buffer_ +
+      offsetof(VertexAttributes, texcoord));
+  graphics_state->VertexAttribFinish();
+
+  SetRRectUniforms(program->GetFragmentShader().u_rect(),
+                   program->GetFragmentShader().u_corners(),
+                   base_state_.rounded_scissor_rect,
+                   *base_state_.rounded_scissor_corners, 0.5f);
+  GL_CALL(glUniform4f(program->GetFragmentShader().u_color(),
+                      color_.r(), color_.g(), color_.b(), color_.a()));
+  GL_CALL(glUniform4fv(program->GetFragmentShader().u_texcoord_clamp(), 1,
+                       texcoord_clamp_));
+
+  if (tile_texture_) {
+    graphics_state->ActiveBindTexture(
+        program->GetFragmentShader().u_texture_texunit(),
+        texture_->GetTarget(), texture_->gl_handle(), GL_REPEAT);
+    GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, kVertexCount));
+    graphics_state->ActiveBindTexture(
+        program->GetFragmentShader().u_texture_texunit(),
+        texture_->GetTarget(), texture_->gl_handle(), GL_CLAMP_TO_EDGE);
+  } else {
+    graphics_state->ActiveBindTexture(
+        program->GetFragmentShader().u_texture_texunit(),
+        texture_->GetTarget(), texture_->gl_handle());
+    GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, kVertexCount));
+  }
+}
+
+base::TypeId DrawRRectColorTexture::GetTypeId() const {
+  return ShaderProgram<ShaderVertexOffsetTexcoord,
+                       ShaderFragmentTexcoordColorRrect>::GetTypeId();
+}
+
+}  // namespace egl
+}  // namespace rasterizer
+}  // namespace renderer
+}  // namespace cobalt
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rrect_color_texture.h b/src/cobalt/renderer/rasterizer/egl/draw_rrect_color_texture.h
new file mode 100644
index 0000000..c65347e
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/egl/draw_rrect_color_texture.h
@@ -0,0 +1,63 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_RENDERER_RASTERIZER_EGL_DRAW_RRECT_COLOR_TEXTURE_H_
+#define COBALT_RENDERER_RASTERIZER_EGL_DRAW_RRECT_COLOR_TEXTURE_H_
+
+#include "cobalt/math/matrix3_f.h"
+#include "cobalt/math/rect_f.h"
+#include "cobalt/render_tree/color_rgba.h"
+#include "cobalt/renderer/backend/egl/texture.h"
+#include "cobalt/renderer/rasterizer/egl/draw_object.h"
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace egl {
+
+// Handles drawing a textured rounded rectangle modulated by a given color.
+class DrawRRectColorTexture : public DrawObject {
+ public:
+  DrawRRectColorTexture(GraphicsState* graphics_state,
+                        const BaseState& base_state,
+                        const math::RectF& rect,
+                        const render_tree::ColorRGBA& color,
+                        const backend::TextureEGL* texture,
+                        const math::Matrix3F& texcoord_transform,
+                        bool clamp_texcoords);
+
+  void ExecuteUpdateVertexBuffer(GraphicsState* graphics_state,
+      ShaderProgramManager* program_manager) OVERRIDE;
+  void ExecuteRasterize(GraphicsState* graphics_state,
+      ShaderProgramManager* program_manager) OVERRIDE;
+  base::TypeId GetTypeId() const OVERRIDE;
+
+ private:
+  math::Matrix3F texcoord_transform_;
+  math::RectF rect_;
+  render_tree::ColorRGBA color_;
+  const backend::TextureEGL* texture_;
+
+  uint8_t* vertex_buffer_;
+  float texcoord_clamp_[4];   // texcoord clamping (min u, min v, max u, max v)
+  bool clamp_texcoords_;
+  bool tile_texture_;
+};
+
+}  // namespace egl
+}  // namespace rasterizer
+}  // namespace renderer
+}  // namespace cobalt
+
+#endif  // COBALT_RENDERER_RASTERIZER_EGL_DRAW_RRECT_COLOR_TEXTURE_H_
diff --git a/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.cc b/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.cc
index 3360ba3..7775f65 100644
--- a/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.cc
+++ b/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.cc
@@ -15,57 +15,11 @@
 #include "cobalt/renderer/rasterizer/egl/offscreen_target_manager.h"
 
 #include <algorithm>
+#include <unordered_map>
 
-#include "base/hash_tables.h"
 #include "cobalt/renderer/rasterizer/egl/rect_allocator.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
-namespace {
-// Structure describing the key for render target allocations in a given
-// offscreen target atlas.
-struct AllocationKey {
-  AllocationKey(const cobalt::render_tree::Node* tree_node,
-                const cobalt::math::SizeF& alloc_size)
-      : node_id(tree_node->GetId()),
-        size(alloc_size) {}
-
-  bool operator==(const AllocationKey& other) const {
-    return node_id == other.node_id && size == other.size;
-  }
-
-  bool operator!=(const AllocationKey& other) const {
-    return node_id != other.node_id || size != other.size;
-  }
-
-  bool operator<(const AllocationKey& rhs) const {
-    return (node_id < rhs.node_id) ||
-           (node_id == rhs.node_id &&
-               (size.width() < rhs.size.width() ||
-               (size.width() == rhs.size.width() &&
-                   size.height() < rhs.size.height())));
-  }
-
-  int64_t node_id;
-  cobalt::math::SizeF size;
-};
-}  // namespace
-
-namespace BASE_HASH_NAMESPACE {
-#if defined(BASE_HASH_USE_HASH_STRUCT)
-template <>
-struct hash<AllocationKey> {
-  size_t operator()(const AllocationKey& key) const {
-    return static_cast<size_t>(key.node_id);
-  }
-};
-#else
-template <>
-inline size_t hash_value<AllocationKey>(const AllocationKey& key) {
-  return static_cast<size_t>(key.node_id);
-}
-#endif
-}  // namespace BASE_HASH_NAMESPACE
-
 namespace cobalt {
 namespace renderer {
 namespace rasterizer {
@@ -73,7 +27,15 @@
 
 namespace {
 
-typedef base::hash_map<AllocationKey, math::Rect> AllocationMap;
+struct AllocationMapValue {
+  AllocationMapValue(const OffscreenTargetManager::ErrorData& in_error_data,
+                     const math::RectF& in_target_region)
+      : error_data(in_error_data), target_region(in_target_region) {}
+  OffscreenTargetManager::ErrorData error_data;
+  math::RectF target_region;
+};
+
+typedef std::unordered_multimap<int64_t, AllocationMapValue> AllocationMap;
 
 int32_t NextPowerOf2(int32_t num) {
   // Return the smallest power of 2 that is greater than or equal to num.
@@ -173,23 +135,36 @@
 }
 
 bool OffscreenTargetManager::GetCachedOffscreenTarget(
-    const render_tree::Node* node, const math::SizeF& size,
+    const render_tree::Node* node, const CacheErrorFunction& error_function,
     TargetInfo* out_target_info) {
-  AllocationMap::iterator iter = offscreen_cache_->allocation_map.find(
-      AllocationKey(node, size));
-  if (iter != offscreen_cache_->allocation_map.end()) {
+  // Find the cache of the given node (if any) with the lowest error.
+  AllocationMap::iterator best_iter = offscreen_cache_->allocation_map.end();
+  float best_error = 2.0f;
+
+  auto range = offscreen_cache_->allocation_map.equal_range(node->GetId());
+  for (auto iter = range.first; iter != range.second; ++iter) {
+    float error = error_function.Run(iter->second.error_data);
+    if (best_error > error) {
+      best_error = error;
+      best_iter = iter;
+    }
+  }
+
+  // A cache entry matches the caller's criteria only if error < 1.
+  if (best_error < 1.0f) {
     offscreen_cache_->allocations_used += 1;
     out_target_info->framebuffer = offscreen_cache_->framebuffer.get();
     out_target_info->skia_canvas = offscreen_cache_->skia_surface->getCanvas();
-    out_target_info->region = iter->second;
+    out_target_info->region = best_iter->second.target_region;
     return true;
   }
+
   return false;
 }
 
 void OffscreenTargetManager::AllocateOffscreenTarget(
     const render_tree::Node* node, const math::SizeF& size,
-    TargetInfo* out_target_info) {
+    const ErrorData& error_data, TargetInfo* out_target_info) {
   // Pad the offscreen target size to prevent interpolation with unwanted
   // texels when rendering the results.
   const int kInterpolatePad = 1;
@@ -200,13 +175,13 @@
   DCHECK(IsPowerOf2(offscreen_target_size_mask_.width() + 1));
   DCHECK(IsPowerOf2(offscreen_target_size_mask_.height() + 1));
   math::Size target_size(
-      (static_cast<int>(size.width()) + 2 * kInterpolatePad +
+      (static_cast<int>(std::ceil(size.width())) + 2 * kInterpolatePad +
           offscreen_target_size_mask_.width()) &
           ~offscreen_target_size_mask_.width(),
-      (static_cast<int>(size.height()) + 2 * kInterpolatePad +
+      (static_cast<int>(std::ceil(size.height())) + 2 * kInterpolatePad +
           offscreen_target_size_mask_.height()) &
           ~offscreen_target_size_mask_.height());
-  math::Rect target_rect(0, 0, 0, 0);
+  math::RectF target_rect(0.0f, 0.0f, 0.0f, 0.0f);
   OffscreenAtlas* atlas = NULL;
 
   // See if there's room in the offscreen cache for additional targets.
@@ -232,6 +207,9 @@
   } else {
     // Inset to prevent interpolation with unwanted pixels at the edge.
     target_rect.Inset(kInterpolatePad, kInterpolatePad);
+    DCHECK_LE(size.width(), target_rect.width());
+    DCHECK_LE(size.height(), target_rect.height());
+    target_rect.set_size(size);
 
     // Clear the atlas if this will be the first draw into it.
     if (atlas->allocation_map.empty()) {
@@ -239,7 +217,7 @@
     }
 
     atlas->allocation_map.insert(AllocationMap::value_type(
-        AllocationKey(node, size), target_rect));
+        node->GetId(), AllocationMapValue(error_data, target_rect)));
     atlas->allocations_used += 1;
     atlas->needs_flush = true;
 
diff --git a/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.h b/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.h
index 02c0704..3dc7803 100644
--- a/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.h
+++ b/src/cobalt/renderer/rasterizer/egl/offscreen_target_manager.h
@@ -48,6 +48,14 @@
     math::RectF region;
   };
 
+  // Offscreen targets are cached with additional ErrorData. When searching for
+  // a match, the caller specifies an error function which is used to verify
+  // that a particular cache entry is suitable for use. A cache entry is
+  // suitable if CacheErrorFunction(ErrorData) < 1. If multiple entries meet
+  // this criteria, then the entry with the lowest error is chosen.
+  typedef math::RectF ErrorData;
+  typedef base::Callback<float(const ErrorData&)> CacheErrorFunction;
+
   OffscreenTargetManager(backend::GraphicsContextEGL* graphics_context,
       const CreateFallbackSurfaceFunction& create_fallback_surface,
       size_t memory_limit);
@@ -65,14 +73,14 @@
   // otherwise, they are untouched.
   // The returned values are only valid until the next call to Update().
   bool GetCachedOffscreenTarget(
-      const render_tree::Node* node, const math::SizeF& size,
+      const render_tree::Node* node, const CacheErrorFunction& error_function,
       TargetInfo* out_target_info);
 
   // Allocate an offscreen target of the specified size.
   // The returned values are only valid until the next call to Update().
   void AllocateOffscreenTarget(
       const render_tree::Node* node, const math::SizeF& size,
-      TargetInfo* out_target_info);
+      const ErrorData& error_data, TargetInfo* out_target_info);
 
  private:
   // Use an atlas for offscreen targets.
diff --git a/src/cobalt/renderer/rasterizer/egl/rasterizer.gyp b/src/cobalt/renderer/rasterizer/egl/rasterizer.gyp
index 42e592e..9fc7942 100644
--- a/src/cobalt/renderer/rasterizer/egl/rasterizer.gyp
+++ b/src/cobalt/renderer/rasterizer/egl/rasterizer.gyp
@@ -57,6 +57,10 @@
         'draw_rect_shadow_blur.cc',
         'draw_rect_texture.h',
         'draw_rect_texture.cc',
+        'draw_rrect_color.h',
+        'draw_rrect_color.cc',
+        'draw_rrect_color_texture.h',
+        'draw_rrect_color_texture.cc',
         'graphics_state.h',
         'graphics_state.cc',
         'hardware_rasterizer.cc',
diff --git a/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
index b3c6c7b..88d6bdd 100644
--- a/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
@@ -34,6 +34,8 @@
 #include "cobalt/renderer/rasterizer/egl/draw_rect_shadow_blur.h"
 #include "cobalt/renderer/rasterizer/egl/draw_rect_shadow_spread.h"
 #include "cobalt/renderer/rasterizer/egl/draw_rect_texture.h"
+#include "cobalt/renderer/rasterizer/egl/draw_rrect_color.h"
+#include "cobalt/renderer/rasterizer/egl/draw_rrect_color_texture.h"
 #include "cobalt/renderer/rasterizer/skia/hardware_image.h"
 #include "cobalt/renderer/rasterizer/skia/image.h"
 
@@ -71,6 +73,75 @@
       0, 0, 1);
 }
 
+bool ImageNodeSupportedNatively(render_tree::ImageNode* image_node) {
+  skia::Image* skia_image = base::polymorphic_downcast<skia::Image*>(
+      image_node->data().source.get());
+  if (skia_image->GetTypeId() == base::GetTypeId<skia::SinglePlaneImage>() &&
+      skia_image->CanRenderInSkia()) {
+    return true;
+  }
+  return false;
+}
+
+bool RoundedViewportSupportedForSource(render_tree::Node* source) {
+  base::TypeId source_type = source->GetTypeId();
+  if (source_type == base::GetTypeId<render_tree::ImageNode>()) {
+    render_tree::ImageNode* image_node =
+        base::polymorphic_downcast<render_tree::ImageNode*>(source);
+    return ImageNodeSupportedNatively(image_node);
+  } else if (source_type == base::GetTypeId<render_tree::CompositionNode>()) {
+    // If this is a composition of valid sources, then rendering with a rounded
+    // viewport is also supported.
+    render_tree::CompositionNode* composition_node =
+        base::polymorphic_downcast<render_tree::CompositionNode*>(source);
+    typedef render_tree::CompositionNode::Children Children;
+    const Children& children = composition_node->data().children();
+
+    for (Children::const_iterator iter = children.begin();
+         iter != children.end(); ++iter) {
+      if (!RoundedViewportSupportedForSource(iter->get())) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  return false;
+}
+
+// Return the error value of a given offscreen taget cache entry.
+// |desired_bounds| specifies the world-space bounds to which an offscreen
+//   target will be rendered.
+// |cached_bounds| specifies the world-space bounds used when the offscreen
+//   target was generated.
+// Lower return values indicate better fits. Only cache entries with an error
+//   less than 1 will be considered suitable.
+float OffscreenTargetErrorFunction(const math::RectF& desired_bounds,
+                                   const math::RectF& cached_bounds) {
+  // The cached contents must be within 0.5 pixels of the desired size to avoid
+  // scaling artifacts.
+  if (std::abs(desired_bounds.width() - cached_bounds.width()) >= 0.5f ||
+      std::abs(desired_bounds.height() - cached_bounds.height()) >= 0.5f) {
+    return 1.0f;
+  }
+
+  // The cached contents' sub-pixel offset must be within 0.5 pixels to ensure
+  // appropriate positioning.
+  math::PointF desired_offset(
+      desired_bounds.x() - std::floor(desired_bounds.x()),
+      desired_bounds.y() - std::floor(desired_bounds.y()));
+  math::PointF cached_offset(
+      cached_bounds.x() - std::floor(cached_bounds.x()),
+      cached_bounds.y() - std::floor(cached_bounds.y()));
+  float error_x = std::abs(desired_offset.x() - cached_offset.x());
+  float error_y = std::abs(desired_offset.y() - cached_offset.y());
+  if (error_x >= 0.5f || error_y >= 0.5f) {
+    return 1.0f;
+  }
+
+  return error_x + error_y;
+}
+
 }  // namespace
 
 RenderTreeNodeVisitor::RenderTreeNodeVisitor(GraphicsState* graphics_state,
@@ -99,12 +170,14 @@
   math::Matrix3F old_transform = draw_state_.transform;
   draw_state_.transform = draw_state_.transform *
       math::TranslateMatrix(data.offset().x(), data.offset().y());
+  draw_state_.rounded_scissor_rect.Offset(-data.offset());
   const render_tree::CompositionNode::Children& children =
       data.children();
   for (render_tree::CompositionNode::Children::const_iterator iter =
        children.begin(); iter != children.end(); ++iter) {
     (*iter)->Accept(this);
   }
+  draw_state_.rounded_scissor_rect.Offset(data.offset());
   draw_state_.transform = old_transform;
 }
 
@@ -130,16 +203,30 @@
 void RenderTreeNodeVisitor::Visit(render_tree::FilterNode* filter_node) {
   const render_tree::FilterNode::Builder& data = filter_node->data();
 
-  // If this is only a viewport filter w/o rounded edges, and the current
-  // transform matrix keeps the filter as an orthogonal rect, then collapse
-  // the node.
+  // Handle viewport-only filter.
   if (data.viewport_filter &&
-      !data.viewport_filter->has_rounded_corners() &&
       !data.opacity_filter &&
       !data.blur_filter &&
       !data.map_to_mesh_filter) {
     const math::Matrix3F& transform = draw_state_.transform;
-    if (IsOnlyScaleAndTranslate(transform)) {
+    if (data.viewport_filter->has_rounded_corners()) {
+      // Certain source nodes have an optimized path for rendering inside
+      // rounded viewports.
+      if (RoundedViewportSupportedForSource(data.source)) {
+        DCHECK(!draw_state_.rounded_scissor_corners);
+        draw_state_.rounded_scissor_rect = data.viewport_filter->viewport();
+        draw_state_.rounded_scissor_corners =
+            data.viewport_filter->rounded_corners();
+        draw_state_.rounded_scissor_corners->Normalize(
+            draw_state_.rounded_scissor_rect);
+        data.source->Accept(this);
+        draw_state_.rounded_scissor_corners = base::nullopt;
+        return;
+      }
+    } else if (IsOnlyScaleAndTranslate(transform)) {
+      // Orthogonal viewport filters without rounded corners can be collapsed
+      // into the world-space scissor.
+
       // Transform local viewport to world viewport.
       const math::RectF& filter_viewport = data.viewport_filter->viewport();
       math::RectF transformed_viewport(
@@ -254,6 +341,11 @@
     return;
   }
 
+  if (!ImageNodeSupportedNatively(image_node)) {
+    FallbackRasterize(image_node);
+    return;
+  }
+
   skia::Image* skia_image =
       base::polymorphic_downcast<skia::Image*>(data.source.get());
   bool clamp_texcoords = false;
@@ -299,7 +391,14 @@
       return;
     }
 
-    if (clamp_texcoords || !is_opaque) {
+    if (draw_state_.rounded_scissor_corners) {
+      // Transparency is used to anti-alias the rounded rect.
+      is_opaque = false;
+      draw.reset(new DrawRRectColorTexture(graphics_state_, draw_state_,
+          data.destination_rect, kOpaqueWhite,
+          hardware_image->GetTextureEGL(), texcoord_transform,
+          clamp_texcoords));
+    } else if (clamp_texcoords || !is_opaque) {
       draw.reset(new DrawRectColorTexture(graphics_state_, draw_state_,
           data.destination_rect, kOpaqueWhite,
           hardware_image->GetTextureEGL(), texcoord_transform,
@@ -365,7 +464,8 @@
   // offscreen target, then use a single shader to render those.
   const bool border_supported = !data.border;
 
-  if (data.rounded_corners) {
+  if (data.rounded_corners && brush &&
+      brush->GetTypeId() != base::GetTypeId<render_tree::SolidColorBrush>()) {
     FallbackRasterize(rect_node);
   } else if (!brush_supported) {
     FallbackRasterize(rect_node);
@@ -373,7 +473,6 @@
     FallbackRasterize(rect_node);
   } else {
     DCHECK(!data.border);
-    const math::RectF& content_rect(data.rect);
 
     // Handle drawing the content.
     if (brush) {
@@ -383,26 +482,33 @@
             base::polymorphic_downcast<const render_tree::SolidColorBrush*>
                 (brush.get());
         const render_tree::ColorRGBA& brush_color(solid_brush->color());
-        render_tree::ColorRGBA content_color(
+        render_tree::ColorRGBA color(
             brush_color.r() * brush_color.a(),
             brush_color.g() * brush_color.a(),
             brush_color.b() * brush_color.a(),
             brush_color.a());
-        scoped_ptr<DrawObject> draw(new DrawPolyColor(graphics_state_,
-            draw_state_, content_rect, content_color));
-        if (draw_state_.opacity * content_color.a() == 1.0f) {
-          AddOpaqueDraw(draw.Pass(), rect_node->GetBounds());
-        } else {
+        if (data.rounded_corners) {
+          scoped_ptr<DrawObject> draw(new DrawRRectColor(graphics_state_,
+              draw_state_, data.rect, *data.rounded_corners, color));
+          // Transparency is used for anti-aliasing.
           AddTransparentDraw(draw.Pass(), rect_node->GetBounds());
+        } else {
+          scoped_ptr<DrawObject> draw(new DrawPolyColor(graphics_state_,
+              draw_state_, data.rect, color));
+          if (draw_state_.opacity * color.a() == 1.0f) {
+            AddOpaqueDraw(draw.Pass(), rect_node->GetBounds());
+          } else {
+            AddTransparentDraw(draw.Pass(), rect_node->GetBounds());
+          }
         }
       } else {
         const render_tree::LinearGradientBrush* linear_brush =
             base::polymorphic_downcast<const render_tree::LinearGradientBrush*>
                 (brush.get());
         scoped_ptr<DrawObject> draw(new DrawRectLinearGradient(graphics_state_,
-            draw_state_, content_rect, *linear_brush));
+            draw_state_, data.rect, *linear_brush));
         // The draw may use transparent pixels to ensure only pixels in the
-        // content_rect are modified.
+        // specified area are modified.
         AddTransparentDraw(draw.Pass(), rect_node->GetBounds());
       }
     }
@@ -490,7 +596,7 @@
     math::RectF* out_content_rect) {
   // Default to telling the caller that nothing should be rendered.
   *out_content_cached = true;
-  out_content_rect->SetRect(0, 0, 0, 0);
+  out_content_rect->SetRect(0.0f, 0.0f, 0.0f, 0.0f);
 
   if (!allow_offscreen_targets_) {
     failed_offscreen_target_request_ = true;
@@ -506,48 +612,37 @@
   // Request a slightly larger render target than the calculated bounds. The
   // rasterizer may use an extra pixel along the edge of anti-aliased objects.
   const float kBorderWidth = 1.0f;
-
-  // The render target cache keys off the render_tree Node and target size.
-  // Since the size is rounded, it is possible to be a fraction of a pixel
-  // off. However, this in turn allows for a cache hit for "close-enough"
-  // renderings. To minimize offset errors, use the nearest full pixel offset.
-  const float kFractionPad = 1.0f;
-  float offset_x = std::floor(mapped_bounds.x() + 0.5f);
-  float offset_y = std::floor(mapped_bounds.y() + 0.5f);
   math::PointF content_offset(
-      offset_x - kBorderWidth - kFractionPad,
-      offset_y - kBorderWidth - kFractionPad);
+      std::floor(mapped_bounds.x() - kBorderWidth),
+      std::floor(mapped_bounds.y() - kBorderWidth));
   math::SizeF content_size(
-      std::ceil(mapped_bounds.width() + 2.0f * kBorderWidth + kFractionPad),
-      std::ceil(mapped_bounds.height() + 2.0f * kBorderWidth + kFractionPad));
+      std::ceil(mapped_bounds.right() + kBorderWidth - content_offset.x()),
+      std::ceil(mapped_bounds.bottom() + kBorderWidth - content_offset.y()));
+
+  // Get a suitable cache of the render tree node if one exists, or allocate
+  // a new offscreen target if possible. The OffscreenTargetErrorFunction will
+  // determine whether any caches are fit for use.
   *out_content_cached = offscreen_target_manager_->GetCachedOffscreenTarget(
-      node, content_size, out_target_info);
+      node, base::Bind(&OffscreenTargetErrorFunction, mapped_bounds),
+      out_target_info);
   if (!(*out_content_cached)) {
     offscreen_target_manager_->AllocateOffscreenTarget(node,
-        content_size, out_target_info);
+        content_size, mapped_bounds, out_target_info);
   }
 
-  // If no offscreen target was available, then set the content_rect as if
-  // rendering will occur on the current render target.
+  // If no offscreen target could be allocated, then the render tree node will
+  // be rendered directly onto the main framebuffer. Use the current scissor
+  // to minimize what has to be drawn.
   if (out_target_info->framebuffer == nullptr) {
-    mapped_bounds.Outset(kBorderWidth, kBorderWidth);
-    mapped_bounds.Intersect(draw_state_.scissor);
-    if (mapped_bounds.IsEmpty()) {
+    math::RectF content_bounds(content_offset, content_size);
+    content_bounds.Intersect(draw_state_.scissor);
+    if (content_bounds.IsEmpty()) {
       return;
     }
-    float left = std::floor(mapped_bounds.x());
-    float right = std::ceil(mapped_bounds.right());
-    float top = std::floor(mapped_bounds.y());
-    float bottom = std::ceil(mapped_bounds.bottom());
-    content_offset.SetPoint(left, top);
-    content_size.SetSize(right - left, bottom - top);
-  } else {
-    DCHECK_LE(content_size.width(), out_target_info->region.width());
-    DCHECK_LE(content_size.height(), out_target_info->region.height());
+    content_offset = content_bounds.origin();
+    content_size = content_bounds.size();
   }
 
-  out_target_info->region.set_size(content_size);
-
   out_content_rect->set_origin(content_offset);
   out_content_rect->set_size(content_size);
 }
diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_between_rrects.glsl b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_between_rrects.glsl
index 5e400d1..f2897ad 100644
--- a/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_between_rrects.glsl
+++ b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_between_rrects.glsl
@@ -26,43 +26,10 @@
 varying vec2 v_offset;

 varying vec4 v_color;

 

-// Return 0 if the current point is inside the rounded rect, or scale towards 1

-// as it goes outside a 1-pixel anti-aliasing border.

-float GetRRectScale(vec4 rect, mat4 corners) {

-  vec4 select_corner = vec4(

-      step(v_offset.x, corners[0].x) * step(v_offset.y, corners[0].y),

-      step(corners[1].x, v_offset.x) * step(v_offset.y, corners[1].y),

-      step(v_offset.x, corners[2].x) * step(corners[2].y, v_offset.y),

-      step(corners[3].x, v_offset.x) * step(corners[3].y, v_offset.y));

-  if (dot(select_corner, vec4(1.0)) > 0.5) {

-    // Estimate the amount of anti-aliasing that should be used by comparing

-    // x^2 / a^2 + y^2 / b^2 for the ellipse and ellipse + 1 pixel.

-    vec4 corner = corners * select_corner;

-    vec2 pixel_offset = v_offset - corner.xy;

-

-    if (corner.z * corner.w < 0.1) {

-      // This is a square corner.

-      return min(length(pixel_offset), 1.0);

-    }

-

-    vec2 offset_min = pixel_offset / corner.zw;

-    vec2 offset_max = pixel_offset / (corner.zw + vec2(1.0));

-    float result_min = dot(offset_min, offset_min);

-    float result_max = dot(offset_max, offset_max);

-

-    // Return 1.0 if outside, or interpolate if in the border, or 0 if inside.

-    return (result_max >= 1.0) ? 1.0 :

-        max(result_min - 1.0, 0.0) / (result_min - result_max);

-  }

-

-  return clamp(rect.x - v_offset.x, 0.0, 1.0) +

-         clamp(v_offset.x - rect.z, 0.0, 1.0) +

-         clamp(rect.y - v_offset.y, 0.0, 1.0) +

-         clamp(v_offset.y - rect.w, 0.0, 1.0);

-}

+#include "function_is_outside_rrect.inc"

 

 void main() {

-  float inner_scale = GetRRectScale(u_inner_rect, u_inner_corners);

-  float outer_scale = GetRRectScale(u_outer_rect, u_outer_corners);

-  gl_FragColor = v_color * inner_scale * (1.0 - outer_scale);

+  float inner_scale = IsOutsideRRect(v_offset, u_inner_rect, u_inner_corners);

+  float outer_scale = IsOutsideRRect(v_offset, u_outer_rect, u_outer_corners);

+  gl_FragColor = v_color * (inner_scale * (1.0 - outer_scale));

 }

diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur_rrects.glsl b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur_rrects.glsl
index 120b988..1d17a97 100644
--- a/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur_rrects.glsl
+++ b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur_rrects.glsl
@@ -41,40 +41,7 @@
 varying vec2 v_offset;

 varying vec4 v_color;

 

-// Return 0 if the current point is inside the rounded rect, or scale towards 1

-// as it goes outside a 1-pixel anti-aliasing border.

-float GetRRectScale(vec4 rect, mat4 corners) {

-  vec4 select_corner = vec4(

-      step(v_offset.x, corners[0].x) * step(v_offset.y, corners[0].y),

-      step(corners[1].x, v_offset.x) * step(v_offset.y, corners[1].y),

-      step(v_offset.x, corners[2].x) * step(corners[2].y, v_offset.y),

-      step(corners[3].x, v_offset.x) * step(corners[3].y, v_offset.y));

-  if (dot(select_corner, vec4(1.0)) > 0.5) {

-    // Estimate the amount of anti-aliasing that should be used by comparing

-    // x^2 / a^2 + y^2 / b^2 for the ellipse and ellipse + 1 pixel.

-    vec4 corner = corners * select_corner;

-    vec2 pixel_offset = v_offset - corner.xy;

-

-    if (corner.z * corner.w < 0.1) {

-      // This is a square corner.

-      return min(length(pixel_offset), 1.0);

-    }

-

-    vec2 offset_min = pixel_offset / corner.zw;

-    vec2 offset_max = pixel_offset / (corner.zw + vec2(1.0));

-    float result_min = dot(offset_min, offset_min);

-    float result_max = dot(offset_max, offset_max);

-

-    // Return 1.0 if outside, or interpolate if in the border, or 0 if inside.

-    return (result_max >= 1.0) ? 1.0 :

-        max(result_min - 1.0, 0.0) / (result_min - result_max);

-  }

-

-  return clamp(rect.x - v_offset.x, 0.0, 1.0) +

-         clamp(v_offset.x - rect.z, 0.0, 1.0) +

-         clamp(rect.y - v_offset.y, 0.0, 1.0) +

-         clamp(v_offset.y - rect.w, 0.0, 1.0);

-}

+#include "function_is_outside_rrect.inc"

 

 // Calculate the distance from a point in the first quadrant to an ellipse

 // centered at the origin.

@@ -161,8 +128,9 @@
 }

 

 void main() {

-  float scissor_scale = GetRRectScale(u_scissor_rect, u_scissor_corners) *

-                        u_scale_add.x + u_scale_add.y;

+  float scissor_scale =

+      IsOutsideRRect(v_offset, u_scissor_rect, u_scissor_corners) *

+      u_scale_add.x + u_scale_add.y;

 

   vec2 pos = GetBlurPosition(u_spread_rect, u_spread_corners) *

              u_sigma_scale + u_sigma_tweak;

diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_rrect.glsl b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_rrect.glsl
new file mode 100644
index 0000000..26549ed
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_rrect.glsl
@@ -0,0 +1,32 @@
+// Copyright 2017 Google Inc. All Rights Reserved.

+//

+// Licensed under the Apache License, Version 2.0 (the "License");

+// you may not use this file except in compliance with the License.

+// You may obtain a copy of the License at

+//

+//     http://www.apache.org/licenses/LICENSE-2.0

+//

+// Unless required by applicable law or agreed to in writing, software

+// distributed under the License is distributed on an "AS IS" BASIS,

+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+// See the License for the specific language governing permissions and

+// limitations under the License.

+

+precision mediump float;

+

+// A rounded rect is represented by a vec4 specifying (min.xy, max.xy), and a

+// matrix of corners. Each vector in the matrix represents a corner (order:

+// top left, top right, bottom left, bottom right). Each corner vec4 represents

+// (start.xy, radius.xy).

+uniform vec4 u_rect;

+uniform mat4 u_corners;

+

+varying vec2 v_offset;

+varying vec4 v_color;

+

+#include "function_is_outside_rrect.inc"

+

+void main() {

+  float scale = IsOutsideRRect(v_offset, u_rect, u_corners);

+  gl_FragColor = v_color * (1.0 - scale);

+}

diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/fragment_texcoord_color_rrect.glsl b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_texcoord_color_rrect.glsl
new file mode 100644
index 0000000..34a25ad
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_texcoord_color_rrect.glsl
@@ -0,0 +1,37 @@
+// Copyright 2017 Google Inc. All Rights Reserved.

+//

+// Licensed under the Apache License, Version 2.0 (the "License");

+// you may not use this file except in compliance with the License.

+// You may obtain a copy of the License at

+//

+//     http://www.apache.org/licenses/LICENSE-2.0

+//

+// Unless required by applicable law or agreed to in writing, software

+// distributed under the License is distributed on an "AS IS" BASIS,

+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+// See the License for the specific language governing permissions and

+// limitations under the License.

+

+precision mediump float;

+

+uniform vec4 u_color;

+uniform vec4 u_texcoord_clamp;

+uniform sampler2D u_texture;

+

+// A rounded rect is represented by a vec4 specifying (min.xy, max.xy), and a

+// matrix of corners. Each vector in the matrix represents a corner (order:

+// top left, top right, bottom left, bottom right). Each corner vec4 represents

+// (start.xy, radius.xy).

+uniform vec4 u_rect;

+uniform mat4 u_corners;

+

+varying vec2 v_offset;

+varying vec2 v_texcoord;

+

+#include "function_is_outside_rrect.inc"

+

+void main() {

+  float scale = IsOutsideRRect(v_offset, u_rect, u_corners);

+  gl_FragColor = u_color * (1.0 - scale) * texture2D(u_texture,

+      clamp(v_texcoord, u_texcoord_clamp.xy, u_texcoord_clamp.zw));

+}

diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/function_is_outside_rrect.inc b/src/cobalt/renderer/rasterizer/egl/shaders/function_is_outside_rrect.inc
new file mode 100644
index 0000000..e3e58b9
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/egl/shaders/function_is_outside_rrect.inc
@@ -0,0 +1,51 @@
+// Copyright 2017 Google Inc. All Rights Reserved.

+//

+// Licensed under the Apache License, Version 2.0 (the "License");

+// you may not use this file except in compliance with the License.

+// You may obtain a copy of the License at

+//

+//     http://www.apache.org/licenses/LICENSE-2.0

+//

+// Unless required by applicable law or agreed to in writing, software

+// distributed under the License is distributed on an "AS IS" BASIS,

+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+// See the License for the specific language governing permissions and

+// limitations under the License.

+

+// Return 0 if the given point is inside the rounded rect, or scale towards 1

+// as it goes outside a 1-pixel anti-aliasing border.

+// |rect| represents (min.xy, max.xy) of the encompassing rectangle.

+// |corners| is a matrix with each vec4 representing (start.xy, radius.xy) of

+//   a corner. The order is top left, top right, bottom left, bottom right.

+float IsOutsideRRect(vec2 point, vec4 rect, mat4 corners) {

+  vec4 select_corner = vec4(

+      step(point.x, corners[0].x) * step(point.y, corners[0].y),

+      step(corners[1].x, point.x) * step(point.y, corners[1].y),

+      step(point.x, corners[2].x) * step(corners[2].y, point.y),

+      step(corners[3].x, point.x) * step(corners[3].y, point.y));

+  if (dot(select_corner, vec4(1.0)) > 0.5) {

+    // Estimate the amount of anti-aliasing that should be used by comparing

+    // x^2 / a^2 + y^2 / b^2 for the ellipse and ellipse + 1 pixel.

+    vec4 corner = corners * select_corner;

+    vec2 pixel_offset = point - corner.xy;

+

+    if (abs(corner.z - corner.w) < 0.1) {

+      // This is a square or round corner.

+      return clamp(length(pixel_offset) - corner.z, 0.0, 1.0);

+    }

+

+    vec2 offset_min = pixel_offset / corner.zw;

+    vec2 offset_max = pixel_offset / (corner.zw + vec2(1.0));

+    float result_min = dot(offset_min, offset_min);

+    float result_max = dot(offset_max, offset_max);

+

+    // Return 1.0 if outside, or interpolate if in the border, or 0 if inside.

+    return (result_max >= 1.0) ? 1.0 :

+        max(result_min - 1.0, 0.0) / (result_min - result_max);

+  }

+

+  return clamp(rect.x - point.x, 0.0, 1.0) +

+         clamp(point.x - rect.z, 0.0, 1.0) +

+         clamp(rect.y - point.y, 0.0, 1.0) +

+         clamp(point.y - rect.w, 0.0, 1.0);

+}

diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/generate_shader_impl.py b/src/cobalt/renderer/rasterizer/egl/shaders/generate_shader_impl.py
index 30bdd79..d253ccd 100644
--- a/src/cobalt/renderer/rasterizer/egl/shaders/generate_shader_impl.py
+++ b/src/cobalt/renderer/rasterizer/egl/shaders/generate_shader_impl.py
@@ -70,42 +70,57 @@
   return 'Shader' + class_name
 
 
-def GetDataDefinitionStringForFile(filename):
-  """Returns a string containing C++ array definition for file contents."""
-  with open(filename, 'rb') as f:
-    # Read the file contents.
-    file_contents = f.read()
+def ReadShaderFile(filename):
+  """Parse the given shader file. Handle #include and strip comments."""
+  path_dir = os.path.dirname(filename)
 
-    # Strip comments and blank lines.
+  def HandleInclude(line):
+    # Handle #include directive if the given line specifies it.
+    if line.startswith('#include "') and line.endswith('"'):
+      include_filename = line[10:-1]
+      return ReadShaderFile(os.path.join(path_dir, include_filename))
+    else:
+      return line
+
+  with open(filename, 'rb') as f:
+    # Read the file and strip comments.
+    file_contents = f.read()
     file_contents = re.sub(r'/\*.*?\*/', '', file_contents, flags=re.DOTALL)
     file_contents = re.sub(r'(\s)*//.*', '', file_contents)
-    file_contents = re.sub('(^|\\n)(\\s)*\\n', '\\1', file_contents)
 
-    # Remove any carriage returns (apitrace doesn't handle shader sources with
-    # that character very well), and add a null terminator at the end.
-    file_contents = file_contents.replace('\r', '') + '\0'
+    # Parse #include directives. This must be done after stripping comments as
+    # it's possible to have multi-line comments that encompass #includes.
+    lines = [HandleInclude(x) for x in file_contents.splitlines()]
 
-    def GetChunk(contents, chunk_size):
-      # Yield successive |chunk_size|-sized chunks from |contents|.
-      for i in xrange(0, len(contents), chunk_size):
-        yield contents[i:i + chunk_size]
+    # Join non-empty lines.
+    return '\n'.join(filter(None, lines))
 
-    # Break up the data into chunk sizes such that the produced output lines
-    # representing the data in the .h file are less than 80 characters long.
-    length_of_output_byte_string = 6
-    max_characters_per_line = 80
-    chunk_size = max_characters_per_line / length_of_output_byte_string
 
-    # Convert each byte to ASCII hexadecimal form and output that to the C++
-    # header file, line-by-line.
-    data_definition_string = '{\n'
-    for output_line_data in GetChunk(file_contents, chunk_size):
-      data_definition_string += (
-          '  ' +
-          ' '.join(['0x%02x,' % ord(y) for y in output_line_data]) +
-          '\n')
-    data_definition_string += '};\n'
-    return data_definition_string
+def GetDataDefinitionStringForFile(filename):
+  """Returns a string containing C++ array definition for file contents."""
+  file_contents = ReadShaderFile(filename) + '\0'
+
+  def GetChunk(contents, chunk_size):
+    # Yield successive |chunk_size|-sized chunks from |contents|.
+    for i in xrange(0, len(contents), chunk_size):
+      yield contents[i:i + chunk_size]
+
+  # Break up the data into chunk sizes such that the produced output lines
+  # representing the data in the .h file are less than 80 characters long.
+  length_of_output_byte_string = 6
+  max_characters_per_line = 80
+  chunk_size = max_characters_per_line / length_of_output_byte_string
+
+  # Convert each byte to ASCII hexadecimal form and output that to the C++
+  # header file, line-by-line.
+  data_definition_string = '{\n'
+  for output_line_data in GetChunk(file_contents, chunk_size):
+    data_definition_string += (
+        '  ' +
+        ' '.join(['0x%02x,' % ord(y) for y in output_line_data]) +
+        '\n')
+  data_definition_string += '};\n'
+  return data_definition_string
 
 
 def GetShaderSourceDefinitions(files):
@@ -352,9 +367,11 @@
 def main(output_header_filename, output_source_filename, shader_files_file):
   all_shader_files = []
   with open(shader_files_file, 'r') as input_file:
-    shader_files = input_file.readlines()
+    shader_files = input_file.read().splitlines()
     for filename in shader_files:
-      all_shader_files.append(filename.strip())
+      # Ignore *.inc files. These are include files and not shader files.
+      if not filename.lower().endswith('.inc'):
+        all_shader_files.append(filename)
 
   GenerateSourceFile(output_source_filename, output_header_filename,
                      all_shader_files)
diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/shaders.gyp b/src/cobalt/renderer/rasterizer/egl/shaders/shaders.gyp
index c3419a6..444d630 100644
--- a/src/cobalt/renderer/rasterizer/egl/shaders/shaders.gyp
+++ b/src/cobalt/renderer/rasterizer/egl/shaders/shaders.gyp
@@ -19,17 +19,21 @@
     'shader_impl_source': '<(output_dir)/generated_shader_impl.cc',
     'generate_class_script': '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/generate_shader_impl.py',
     'shader_sources': [
-      '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_texcoord.glsl',
       '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_color.glsl',
       '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_color_between_rrects.glsl',
       '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur.glsl',
       '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur_rrects.glsl',
       '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_color_include.glsl',
+      '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_color_rrect.glsl',
       '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_color_texcoord.glsl',
-      '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/vertex_texcoord.glsl',
+      '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_texcoord.glsl',
+      '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_texcoord_color_rrect.glsl',
+      '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/function_is_outside_rrect.inc',
       '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/vertex_color.glsl',
       '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/vertex_color_offset.glsl',
       '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/vertex_color_texcoord.glsl',
+      '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/vertex_offset_texcoord.glsl',
+      '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/vertex_texcoord.glsl',
     ],
   },
 
diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/vertex_offset_texcoord.glsl b/src/cobalt/renderer/rasterizer/egl/shaders/vertex_offset_texcoord.glsl
new file mode 100644
index 0000000..df81d24
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/egl/shaders/vertex_offset_texcoord.glsl
@@ -0,0 +1,29 @@
+// Copyright 2017 Google Inc. All Rights Reserved.

+//

+// Licensed under the Apache License, Version 2.0 (the "License");

+// you may not use this file except in compliance with the License.

+// You may obtain a copy of the License at

+//

+//     http://www.apache.org/licenses/LICENSE-2.0

+//

+// Unless required by applicable law or agreed to in writing, software

+// distributed under the License is distributed on an "AS IS" BASIS,

+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+// See the License for the specific language governing permissions and

+// limitations under the License.

+

+uniform vec4 u_clip_adjustment;

+uniform mat3 u_view_matrix;

+attribute vec2 a_position;

+attribute vec2 a_offset;

+attribute vec2 a_texcoord;

+varying vec2 v_offset;

+varying vec2 v_texcoord;

+

+void main() {

+  vec3 pos2d = u_view_matrix * vec3(a_position, 1);

+  gl_Position = vec4(pos2d.xy * u_clip_adjustment.xy +

+                     u_clip_adjustment.zw, 0, pos2d.z);

+  v_offset = a_offset;

+  v_texcoord = a_texcoord;

+}

diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc
index 0becedb..7315496 100644
--- a/src/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -1890,6 +1890,18 @@
       new ImageNode(image)));
 }
 
+TEST_F(PixelTest, EllipticalViewportOverCompositionOfImages) {
+  scoped_refptr<Image> image =
+      CreateColoredCheckersImage(GetResourceProvider(), output_surface_size());
+
+  CompositionNode::Builder builder(Vector2dF(25, 50));
+  builder.AddChild(new ImageNode(image, RectF(0, 0, 75, 50)));
+  builder.AddChild(new ImageNode(image, RectF(75, 50, 75, 50)));
+  TestTree(new FilterNode(
+      ViewportFilter(RectF(25, 50, 150, 100), RoundedCorners(75, 50)),
+      new CompositionNode(builder.Pass())));
+}
+
 TEST_F(PixelTest, EllipticalViewportOverWrappingImage) {
   scoped_refptr<Image> image =
       CreateColoredCheckersImage(GetResourceProvider(), output_surface_size());
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
index 6ff0f21..c385813 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
@@ -54,6 +54,7 @@
       submit_offscreen_callback_(submit_offscreen_callback),
       purge_skia_font_caches_on_destruction_(
           purge_skia_font_caches_on_destruction),
+      max_texture_size_(gr_context->getMaxTextureSize()),
       self_message_loop_(MessageLoop::current()) {
   // Initialize the font manager now to ensure that it doesn't get initialized
   // on multiple threads simultaneously later.
@@ -67,8 +68,7 @@
   decode_target_graphics_context_provider_.gles_context_runner =
       &HardwareResourceProvider::GraphicsContextRunner;
   decode_target_graphics_context_provider_.gles_context_runner_context = this;
-#endif  // SB_API_VERSION >= 4 && \
-           SB_HAS(GRAPHICS)
+#endif  // SB_API_VERSION >= 4 && SB_HAS(GRAPHICS)
 }
 
 HardwareResourceProvider::~HardwareResourceProvider() {
@@ -110,6 +110,10 @@
   DCHECK(PixelFormatSupported(pixel_format));
   DCHECK(AlphaFormatSupported(alpha_format));
 
+  if (size.width() > max_texture_size_ || size.height() > max_texture_size_) {
+    return scoped_ptr<ImageData>(nullptr);
+  }
+
   return scoped_ptr<ImageData>(new HardwareImageData(
       cobalt_context_->system_egl()->AllocateTextureData(
           size, ConvertRenderTreeFormatToGL(pixel_format)),
@@ -347,8 +351,7 @@
   }
 }
 
-#endif  // SB_API_VERSION >= 4 && \
-           SB_HAS(GRAPHICS)
+#endif  // SB_API_VERSION >= 4 && SB_HAS(GRAPHICS)
 
 scoped_ptr<RawImageMemory> HardwareResourceProvider::AllocateRawImageMemory(
     size_t size_in_bytes, size_t alignment) {
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
index d5540a8..33ed4d2 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
@@ -145,6 +145,7 @@
   const bool purge_skia_font_caches_on_destruction_;
 
   TextShaper text_shaper_;
+  int max_texture_size_;
 
 #if SB_API_VERSION >= 4 && SB_HAS(GRAPHICS)
   static void GraphicsContextRunner(
@@ -154,8 +155,7 @@
 
   SbDecodeTargetGraphicsContextProvider
       decode_target_graphics_context_provider_;
-#endif  // SB_API_VERSION >= 4 && \
-           SB_HAS(GRAPHICS)
+#endif  // SB_API_VERSION >= 4 && SB_HAS(GRAPHICS)
 
   // We keep a handle to the message loop that this resource provider was
   // created on.  This message loop is used whenever we need to issue graphics
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi b/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi
index 71ac5a6..b6714f6 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi
+++ b/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi
@@ -31,6 +31,8 @@
     'src/ports/SkFontStyleSet_cobalt.h',
     'src/ports/SkFontUtil_cobalt.cc',
     'src/ports/SkFontUtil_cobalt.h',
+    'src/ports/SkFreeType_cobalt.cc',
+    'src/ports/SkFreeType_cobalt.h',
     'src/ports/SkOSFile_cobalt.cc',
     'src/ports/SkStream_cobalt.cc',
     'src/ports/SkStream_cobalt.h',
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/skia_common.gypi b/src/cobalt/renderer/rasterizer/skia/skia/skia_common.gypi
index a256e78..cff46c8 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/skia_common.gypi
+++ b/src/cobalt/renderer/rasterizer/skia/skia/skia_common.gypi
@@ -62,7 +62,7 @@
         ],
       },
     }],
-    ['actual_target_arch == "win" or target_arch == "xb360"', {
+    ['target_arch == "win"', {
       'variables': {
         'skia_export_defines': [
           # Required define by Skia to take certain code paths, such
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
index d26d31e..67576ee 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
@@ -14,14 +14,15 @@
 
 #include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h"
 
-#include "base/debug/trace_event.h"
-#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.h"
-#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h"
 #include "SkData.h"
 #include "SkGraphics.h"
 #include "SkStream.h"
 #include "SkString.h"
 #include "SkTSearch.h"
+#include "base/debug/trace_event.h"
+#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.h"
+#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFreeType_cobalt.h"
+#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h"
 
 SkFontMgr_Cobalt::SkFontMgr_Cobalt(
     const char* cobalt_font_config_directory,
@@ -236,8 +237,8 @@
   bool is_fixed_pitch;
   SkTypeface::Style style;
   SkString name;
-  if (!SkTypeface_FreeType::ScanFont(stream, face_index, &name, &style,
-                                     &is_fixed_pitch)) {
+  if (!sk_freetype_cobalt::ScanFont(stream, face_index, &name, &style,
+                                    &is_fixed_pitch)) {
     return NULL;
   }
   return SkNEW_ARGS(SkTypeface_CobaltStream,
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc
index 6196cc6..36315ef 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc
@@ -14,17 +14,15 @@
 
 #include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.h"
 
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
 #include <cmath>
 #include <limits>
 
+#include "SkOSFile.h"
 #include "base/debug/trace_event.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFreeType_cobalt.h"
 #include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h"
-#include "SkOSFile.h"
 
 namespace {
 
@@ -70,22 +68,6 @@
 
 }  // namespace
 
-// These functions are used by FreeType during FT_Open_Face.
-extern "C" {
-
-static unsigned long sk_cobalt_ft_stream_io(FT_Stream ftStream,
-                                            unsigned long offset,
-                                            unsigned char* buffer,
-                                            unsigned long count) {
-  SkStreamAsset* stream =
-      static_cast<SkStreamAsset*>(ftStream->descriptor.pointer);
-  stream->seek(offset);
-  return stream->read(buffer, count);
-}
-
-static void sk_cobalt_ft_stream_close(FT_Stream) {}
-}
-
 SkFontStyleSet_Cobalt::SkFontStyleSet_Cobalt(
     const FontFamilyInfo& family_info, const char* base_path,
     SkFileMemoryChunkStreamManager* const local_typeface_stream_manager,
@@ -319,73 +301,19 @@
     return true;
   }
 
-  TRACE_EVENT0("cobalt::renderer", "GenerateStyleFaceInfo()");
+  // Providing a pointer to the character map will cause it to be generated
+  // during ScanFont. Only provide it if it hasn't already been generated.
+  font_character_map::CharacterMap* character_map =
+      !is_character_map_generated_ ? &character_map_ : NULL;
 
-  FT_Library freetype_lib;
-  if (FT_Init_FreeType(&freetype_lib) != 0) {
+  if (!sk_freetype_cobalt::ScanFont(
+          stream, style->face_index, &style->face_name, &style->face_style,
+          &style->face_is_fixed_pitch, character_map)) {
     return false;
   }
 
-  FT_StreamRec streamRec;
-  memset(&streamRec, 0, sizeof(streamRec));
-  streamRec.size = stream->getLength();
-  streamRec.descriptor.pointer = stream;
-  streamRec.read = sk_cobalt_ft_stream_io;
-  streamRec.close = sk_cobalt_ft_stream_close;
-
-  FT_Open_Args args;
-  memset(&args, 0, sizeof(args));
-  args.flags = FT_OPEN_STREAM;
-  args.stream = &streamRec;
-
-  FT_Face face;
-  FT_Error err = FT_Open_Face(freetype_lib, &args, style->face_index, &face);
-  if (err) {
-    FT_Done_FreeType(freetype_lib);
-    return false;
-  }
-
-  int face_style = SkTypeface::kNormal;
-  if (face->style_flags & FT_STYLE_FLAG_BOLD) {
-    face_style |= SkTypeface::kBold;
-  }
-  if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
-    face_style |= SkTypeface::kItalic;
-  }
-
-  style->face_name.set(face->family_name);
-  style->face_style = static_cast<SkTypeface::Style>(face_style);
-  style->face_is_fixed_pitch = FT_IS_FIXED_WIDTH(face);
   style->is_face_info_generated = true;
-
-  // Map out this family's characters if they haven't been generated yet.
-  if (!is_character_map_generated_) {
-    FT_UInt glyph_index;
-
-    int last_page = -1;
-    font_character_map::PageCharacters* page_characters = NULL;
-
-    SkUnichar code_point = FT_Get_First_Char(face, &glyph_index);
-    while (glyph_index) {
-      int page = font_character_map::GetPage(code_point);
-      if (page != last_page) {
-        page_characters = &character_map_[page];
-        last_page = page;
-      }
-      page_characters->set(
-          font_character_map::GetPageCharacterIndex(code_point));
-
-      code_point = FT_Get_Next_Char(face, code_point, &glyph_index);
-    }
-
-    is_character_map_generated_ = true;
-  }
-
-  // release this font.
-  FT_Done_Face(face);
-
-  // shut down FreeType.
-  FT_Done_FreeType(freetype_lib);
+  is_character_map_generated_ = true;
   return true;
 }
 
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFreeType_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFreeType_cobalt.cc
new file mode 100644
index 0000000..6abacb8
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFreeType_cobalt.cc
@@ -0,0 +1,182 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFreeType_cobalt.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_TYPE1_TABLES_H
+
+#include "SkFontStyle.h"
+#include "SkTSearch.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+
+namespace {
+
+// This logic is taken from SkTypeface_FreeType::ScanFont() and should be kept
+// in sync with it.
+SkTypeface::Style GenerateSkTypefaceStyleFromFace(FT_Face face) {
+  int weight = SkFontStyle::kNormal_Weight;
+  if (face->style_flags & FT_STYLE_FLAG_BOLD) {
+    weight = SkFontStyle::kBold_Weight;
+  }
+
+  PS_FontInfoRec psFontInfo;
+  TT_OS2* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face, ft_sfnt_os2));
+  if (os2 && os2->version != 0xffff) {
+    weight = os2->usWeightClass;
+  } else if (0 == FT_Get_PS_Font_Info(face, &psFontInfo) && psFontInfo.weight) {
+    static const struct {
+      char const* const name;
+      int const weight;
+    } commonWeights[] = {
+        // There are probably more common names, but these are known to exist.
+        {"all", SkFontStyle::kNormal_Weight},  // Multiple Masters usually
+                                               // default to normal.
+        {"black", SkFontStyle::kBlack_Weight},
+        {"bold", SkFontStyle::kBold_Weight},
+        {"book",
+         (SkFontStyle::kNormal_Weight + SkFontStyle::kLight_Weight) / 2},
+        {"demi", SkFontStyle::kSemiBold_Weight},
+        {"demibold", SkFontStyle::kSemiBold_Weight},
+        {"extra", SkFontStyle::kExtraBold_Weight},
+        {"extrabold", SkFontStyle::kExtraBold_Weight},
+        {"extralight", SkFontStyle::kExtraLight_Weight},
+        {"hairline", SkFontStyle::kThin_Weight},
+        {"heavy", SkFontStyle::kBlack_Weight},
+        {"light", SkFontStyle::kLight_Weight},
+        {"medium", SkFontStyle::kMedium_Weight},
+        {"normal", SkFontStyle::kNormal_Weight},
+        {"plain", SkFontStyle::kNormal_Weight},
+        {"regular", SkFontStyle::kNormal_Weight},
+        {"roman", SkFontStyle::kNormal_Weight},
+        {"semibold", SkFontStyle::kSemiBold_Weight},
+        {"standard", SkFontStyle::kNormal_Weight},
+        {"thin", SkFontStyle::kThin_Weight},
+        {"ultra", SkFontStyle::kExtraBold_Weight},
+        {"ultrabold", SkFontStyle::kExtraBold_Weight},
+        {"ultralight", SkFontStyle::kExtraLight_Weight},
+    };
+    int const index =
+        SkStrLCSearch(&commonWeights[0].name, SK_ARRAY_COUNT(commonWeights),
+                      psFontInfo.weight, sizeof(commonWeights[0]));
+    if (index >= 0) {
+      weight = commonWeights[index].weight;
+    } else {
+      DLOG(ERROR) << "Do not recognize weight for:" << face->family_name << "("
+                  << psFontInfo.weight << ")";
+    }
+  }
+
+  int face_style = SkTypeface::kNormal;
+  if (weight > 500) {
+    face_style |= SkTypeface::kBold;
+  }
+  if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
+    face_style |= SkTypeface::kItalic;
+  }
+
+  return static_cast<SkTypeface::Style>(face_style);
+}
+
+void GenerateCharacterMapFromFace(
+    FT_Face face, font_character_map::CharacterMap* character_map) {
+  TRACE_EVENT0("cobalt::renderer", "GenerateCharacterMapFromFace");
+
+  FT_UInt glyph_index;
+
+  int last_page = -1;
+  font_character_map::PageCharacters* page_characters = NULL;
+
+  SkUnichar code_point = FT_Get_First_Char(face, &glyph_index);
+  while (glyph_index) {
+    int page = font_character_map::GetPage(code_point);
+    if (page != last_page) {
+      page_characters = &(*character_map)[page];
+      last_page = page;
+    }
+    page_characters->set(font_character_map::GetPageCharacterIndex(code_point));
+
+    code_point = FT_Get_Next_Char(face, code_point, &glyph_index);
+  }
+}
+
+}  // namespace
+
+// These functions are used by FreeType during FT_Open_Face.
+extern "C" {
+
+static unsigned long sk_freetype_cobalt_stream_io(FT_Stream ftStream,
+                                                  unsigned long offset,
+                                                  unsigned char* buffer,
+                                                  unsigned long count) {
+  SkStreamAsset* stream =
+      static_cast<SkStreamAsset*>(ftStream->descriptor.pointer);
+  stream->seek(offset);
+  return stream->read(buffer, count);
+}
+
+static void sk_freetype_cobalt_stream_close(FT_Stream) {}
+}
+
+namespace sk_freetype_cobalt {
+
+bool ScanFont(SkStreamAsset* stream, int face_index, SkString* name,
+              SkTypeface::Style* style, bool* is_fixed_pitch,
+              font_character_map::CharacterMap* maybe_character_map /*=NULL*/) {
+  TRACE_EVENT0("cobalt::renderer", "SkFreeTypeUtil::ScanFont()");
+
+  FT_Library freetype_lib;
+  if (FT_Init_FreeType(&freetype_lib) != 0) {
+    return false;
+  }
+
+  FT_StreamRec streamRec;
+  memset(&streamRec, 0, sizeof(streamRec));
+  streamRec.size = stream->getLength();
+  streamRec.descriptor.pointer = stream;
+  streamRec.read = sk_freetype_cobalt_stream_io;
+  streamRec.close = sk_freetype_cobalt_stream_close;
+
+  FT_Open_Args args;
+  memset(&args, 0, sizeof(args));
+  args.flags = FT_OPEN_STREAM;
+  args.stream = &streamRec;
+
+  FT_Face face;
+  FT_Error err = FT_Open_Face(freetype_lib, &args, face_index, &face);
+  if (err) {
+    FT_Done_FreeType(freetype_lib);
+    return false;
+  }
+
+  name->set(face->family_name);
+  *style = GenerateSkTypefaceStyleFromFace(face);
+  *is_fixed_pitch = FT_IS_FIXED_WIDTH(face);
+
+  if (maybe_character_map) {
+    GenerateCharacterMapFromFace(face, maybe_character_map);
+  }
+
+  // release this font.
+  FT_Done_Face(face);
+
+  // shut down FreeType.
+  FT_Done_FreeType(freetype_lib);
+  return true;
+}
+
+}  // namespace sk_freetype_cobalt
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFreeType_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFreeType_cobalt.h
new file mode 100644
index 0000000..70abeeb
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFreeType_cobalt.h
@@ -0,0 +1,33 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_RENDERER_RASTERIZER_SKIA_SKIA_SRC_PORTS_SKFREETYPE_COBALT_H_
+#define COBALT_RENDERER_RASTERIZER_SKIA_SKIA_SRC_PORTS_SKFREETYPE_COBALT_H_
+
+#include "SkStream.h"
+#include "SkTypeface.h"
+#include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h"
+
+namespace sk_freetype_cobalt {
+
+// Scans the font stream using FreeType, setting its name, style and whether or
+// not it has a fixed pitch. It also generates the font's character map if that
+// optional parameter is provided.
+bool ScanFont(SkStreamAsset* stream, int face_index, SkString* name,
+              SkTypeface::Style* style, bool* is_fixed_pitch,
+              font_character_map::CharacterMap* maybe_character_map = NULL);
+
+}  // namespace sk_freetype_cobalt
+
+#endif  // COBALT_RENDERER_RASTERIZER_SKIA_SKIA_SRC_PORTS_SKFREETYPE_COBALT_H_
diff --git a/src/cobalt/renderer/rasterizer/testdata/EllipticalViewportOverCompositionOfImages-expected.png b/src/cobalt/renderer/rasterizer/testdata/EllipticalViewportOverCompositionOfImages-expected.png
new file mode 100644
index 0000000..337f162
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/EllipticalViewportOverCompositionOfImages-expected.png
Binary files differ
diff --git a/src/cobalt/script/javascript_engine.h b/src/cobalt/script/javascript_engine.h
index 4ea8881..c8e4f72 100644
--- a/src/cobalt/script/javascript_engine.h
+++ b/src/cobalt/script/javascript_engine.h
@@ -70,6 +70,9 @@
   // Returns true if the error handler could be installed. False otherwise.
   virtual bool RegisterErrorHandler(ErrorHandler handler) = 0;
 
+  // Adjusts the memory threshold to force garbage collection.
+  virtual void SetGcThreshold(int64_t bytes) = 0;
+
  protected:
   virtual ~JavaScriptEngine() {}
   friend class scoped_ptr<JavaScriptEngine>;
diff --git a/src/cobalt/script/mozjs-45/mozjs_engine.cc b/src/cobalt/script/mozjs-45/mozjs_engine.cc
index 720e71f..6a09beb 100644
--- a/src/cobalt/script/mozjs-45/mozjs_engine.cc
+++ b/src/cobalt/script/mozjs-45/mozjs_engine.cc
@@ -235,6 +235,10 @@
   return true;
 }
 
+void MozjsEngine::SetGcThreshold(int64_t bytes) {
+  runtime_->gc.setMaxMallocBytes(static_cast<size_t>(bytes));
+}
+
 void MozjsEngine::TimerGarbageCollect() {
   TRACE_EVENT0("cobalt::script", "MozjsEngine::TimerGarbageCollect()");
   CollectGarbage();
diff --git a/src/cobalt/script/mozjs-45/mozjs_engine.h b/src/cobalt/script/mozjs-45/mozjs_engine.h
index 9adb4e2..98094f1 100644
--- a/src/cobalt/script/mozjs-45/mozjs_engine.h
+++ b/src/cobalt/script/mozjs-45/mozjs_engine.h
@@ -40,6 +40,7 @@
   void CollectGarbage() OVERRIDE;
   void ReportExtraMemoryCost(size_t bytes) OVERRIDE;
   bool RegisterErrorHandler(JavaScriptEngine::ErrorHandler handler) OVERRIDE;
+  void SetGcThreshold(int64_t bytes) OVERRIDE;
 
  private:
   void TimerGarbageCollect();
diff --git a/src/cobalt/script/mozjs-45/mozjs_global_environment.cc b/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
index 7f100d0..a075221 100644
--- a/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
+++ b/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
@@ -250,17 +250,20 @@
           context_, JS::UTF8Chars(script.c_str(), length), &length)
           .get();
 
-  bool success = false;
-  if (inflated_buffer) {
-    JS::CompileOptions options(context_);
-    options.setFileAndLine(location.file_path.c_str(), location.line_number);
-    success =
-        JS::Evaluate(context_, options, inflated_buffer, length, out_result);
-    js_free(inflated_buffer);
-  } else {
+  if (!inflated_buffer) {
     DLOG(ERROR) << "Malformed UTF-8 script.";
+    return false;
   }
 
+  JS::CompileOptions options(context_);
+  options.setFileAndLine(location.file_path.c_str(), location.line_number);
+  bool success =
+      JS::Evaluate(context_, options, inflated_buffer, length, out_result);
+  if (!success && context_->isExceptionPending()) {
+    JS_ReportPendingException(context_);
+  }
+  js_free(inflated_buffer);
+
   return success;
 }
 
diff --git a/src/cobalt/script/mozjs/mozjs_engine.cc b/src/cobalt/script/mozjs/mozjs_engine.cc
index 0f1760e..cfc1c5e 100644
--- a/src/cobalt/script/mozjs/mozjs_engine.cc
+++ b/src/cobalt/script/mozjs/mozjs_engine.cc
@@ -27,6 +27,7 @@
 #include "cobalt/script/mozjs/util/stack_trace_helpers.h"
 #include "third_party/mozjs/cobalt_config/include/jscustomallocator.h"
 #include "third_party/mozjs/js/src/jsapi.h"
+#include "third_party/mozjs/js/src/jscntxt.h"
 #include "third_party/mozjs/js/src/jsdbgapi.h"
 
 namespace cobalt {
@@ -184,6 +185,10 @@
   return true;
 }
 
+void MozjsEngine::SetGcThreshold(int64_t bytes) {
+  runtime_->setGCMaxMallocBytes(static_cast<size_t>(bytes));
+}
+
 void MozjsEngine::TimerGarbageCollect() {
   TRACE_EVENT0("cobalt::script", "MozjsEngine::TimerGarbageCollect()");
   CollectGarbage();
diff --git a/src/cobalt/script/mozjs/mozjs_engine.h b/src/cobalt/script/mozjs/mozjs_engine.h
index 5c3d460..9dda81a 100644
--- a/src/cobalt/script/mozjs/mozjs_engine.h
+++ b/src/cobalt/script/mozjs/mozjs_engine.h
@@ -42,6 +42,7 @@
   void CollectGarbage() OVERRIDE;
   void ReportExtraMemoryCost(size_t bytes) OVERRIDE;
   bool RegisterErrorHandler(JavaScriptEngine::ErrorHandler handler) OVERRIDE;
+  void SetGcThreshold(int64_t bytes) OVERRIDE;
 
  private:
   void TimerGarbageCollect();
diff --git a/src/cobalt/script/mozjs/mozjs_global_environment.cc b/src/cobalt/script/mozjs/mozjs_global_environment.cc
index 200095f..71b593d 100644
--- a/src/cobalt/script/mozjs/mozjs_global_environment.cc
+++ b/src/cobalt/script/mozjs/mozjs_global_environment.cc
@@ -268,16 +268,22 @@
   size_t length = script.size();
   jschar* inflated_buffer =
       js::InflateUTF8String(context_, script.c_str(), &length);
-  bool success = false;
-  if (inflated_buffer) {
-    success = JS_EvaluateUCScript(context_, global_object, inflated_buffer,
-                                  length, location.file_path.c_str(),
-                                  location.line_number, out_result.address());
-    js_free(inflated_buffer);
-  } else {
+
+  if (!inflated_buffer) {
     DLOG(ERROR) << "Malformed UTF-8 script.";
+    return false;
   }
 
+  JS::CompileOptions options(context_);
+  options.setFileAndLine(location.file_path.c_str(), location.line_number);
+  bool success = JS_EvaluateUCScript(
+      context_, global_object, inflated_buffer, length,
+      location.file_path.c_str(), location.line_number, out_result.address());
+  if (!success && context_->isExceptionPending()) {
+    JS_ReportPendingException(context_);
+  }
+  js_free(inflated_buffer);
+
   return success;
 }
 
diff --git a/src/cobalt/storage/storage.gyp b/src/cobalt/storage/storage.gyp
index 94bfd46..6f18bc9 100644
--- a/src/cobalt/storage/storage.gyp
+++ b/src/cobalt/storage/storage.gyp
@@ -30,6 +30,7 @@
         'sql_vfs.cc',
         'sql_vfs.h',
         'savegame_fake.cc',
+        'savegame_starboard.cc',
         'storage_manager.cc',
         'storage_manager.h',
         'upgrade/upgrade_reader.cc',
@@ -45,28 +46,6 @@
         '<(DEPTH)/net/net.gyp:net',
         '<(DEPTH)/sql/sql.gyp:sql',
       ],
-      'conditions': [
-        ['OS=="starboard"', {
-          'sources': [
-            'savegame_starboard.cc',
-          ],
-        }],
-        ['OS!="starboard" and target_arch=="ps3"', {
-          'sources': [
-            'savegame_ps3.cc',
-          ],
-          'copies': [
-          {
-            'destination': '<(static_contents_output_data_dir)',
-            'files': ['<(static_contents_source_dir)/platform/ps3/USRDIR/SAVE_ICON.PNG'],
-          }],
-        }],
-        ['OS!="starboard" and actual_target_arch=="win"', {
-          'sources': [
-            'savegame_file.cc',
-          ],
-        }],
-      ],
     },
     {
       'target_name': 'storage_test',
diff --git a/src/cobalt/system_window/system_window.cc b/src/cobalt/system_window/system_window.cc
index 444b411..399e107 100644
--- a/src/cobalt/system_window/system_window.cc
+++ b/src/cobalt/system_window/system_window.cc
@@ -180,7 +180,8 @@
 
 void SystemWindow::ShowDialog(
     const SystemWindow::DialogOptions& options) {
-  SbSystemPlatformErrorType error_type;
+  SbSystemPlatformErrorType error_type =
+      kSbSystemPlatformErrorTypeConnectionError;
   switch (options.message_code) {
     case kDialogConnectionError:
       error_type = kSbSystemPlatformErrorTypeConnectionError;
diff --git a/src/cobalt/webdriver/algorithms.cc b/src/cobalt/webdriver/algorithms.cc
index 83379cf..a2fd622 100644
--- a/src/cobalt/webdriver/algorithms.cc
+++ b/src/cobalt/webdriver/algorithms.cc
@@ -41,26 +41,20 @@
 // Note that non-breaking space is at the beginning to simplify definition of
 // kWhitespaceCharsExcludingNonBreakingSpace below.
 const char kWhitespaceChars[] =
-    "\u00a0 "
-    "\f\n\r\t\v\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006"
-    "\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff";
+    u8"\u00a0 "
+    u8"\f\n\r\t\v\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006"
+    u8"\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff";
 const char* kWhitespaceCharsExcludingNonBreakingSpace = kWhitespaceChars + 1;
 
 // Defined in https://www.w3.org/TR/webdriver/#text.horizontal
-const char kHorizontalWhitespaceChars[] = " \f\t\v\u2028\u2029";
+const char kHorizontalWhitespaceChars[] = u8" \f\t\v\u2028\u2029";
 
 // Defined in step 2.1 of the getElementText() algorithm in
 // https://www.w3.org/TR/webdriver/#getelementtext
-const char kZeroWidthSpacesAndFeeds[] = "\f\v\u200b\u200e\u200f";
+const char kZeroWidthSpacesAndFeeds[] = u8"\f\v\u200b\u200e\u200f";
 
 const char kNonBreakingSpace = '\xa0';
 
-bool IsWhitespace(char c) {
-  DCHECK_NE(c, '\0');
-  // strchr matches the nul-character, which is not a whitespace character.
-  return strchr(kWhitespaceChars, c) != NULL;
-}
-
 bool IsHorizontalWhitespace(char c) {
   DCHECK_NE(c, '\0');
   return strchr(kHorizontalWhitespaceChars, c) != NULL;
diff --git a/src/cobalt/webdriver/dispatcher.cc b/src/cobalt/webdriver/dispatcher.cc
index 6d1d408..5ea6726 100644
--- a/src/cobalt/webdriver/dispatcher.cc
+++ b/src/cobalt/webdriver/dispatcher.cc
@@ -145,8 +145,9 @@
   CommandMapping* mapping = GetMappingForPath(tokenized_path, kMatchExact);
   if (!mapping) {
     // No commands registered for this path yet, so create a new CommandMapping.
+    int tokenized_path_size = static_cast<int>(tokenized_path.size());
     CommandMappingLookup::iterator it = command_lookup_.insert(
-        std::make_pair(tokenized_path.size(), CommandMapping(tokenized_path)));
+        std::make_pair(tokenized_path_size, CommandMapping(tokenized_path)));
     mapping = &it->second;
   }
 
diff --git a/src/cobalt/webdriver/get_element_text_test.cc b/src/cobalt/webdriver/get_element_text_test.cc
index a25c693..65036fe 100644
--- a/src/cobalt/webdriver/get_element_text_test.cc
+++ b/src/cobalt/webdriver/get_element_text_test.cc
@@ -83,7 +83,7 @@
 }  // namespace
 
 TEST_F(GetElementTextTest, ZeroSpaceWidthIsRemoved) {
-  AppendText("a\u200bb\u200ec\u200fd");
+  AppendText(u8"a\u200bb\u200ec\u200fd");
   EXPECT_STREQ("abcd", algorithms::GetElementText(div_.get()).c_str());
 }
 
@@ -94,7 +94,7 @@
 
 TEST_F(GetElementTextTest, NoWrapStyle) {
   div_->style()->set_white_space("nowrap", NULL);
-  AppendText("a\n\nb\nc\td\u2028e\u2029f\xa0g");
+  AppendText(u8"a\n\nb\nc\td\u2028e\u2029f\xa0g");
   EXPECT_STREQ("a b c d e f g", algorithms::GetElementText(div_.get()).c_str());
 }
 
diff --git a/src/cobalt/webdriver/keyboard_test.cc b/src/cobalt/webdriver/keyboard_test.cc
index b961587..db1e7b7 100644
--- a/src/cobalt/webdriver/keyboard_test.cc
+++ b/src/cobalt/webdriver/keyboard_test.cc
@@ -174,7 +174,7 @@
 
 TEST_F(KeyboardTest, Modifier) {
   // \uE00A is the Alt-key modifier.
-  std::string keys = "\uE00A";
+  std::string keys = u8"\uE00A";
   Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_);
 
   ASSERT_EQ(events_.size(), 1);
@@ -189,7 +189,7 @@
 TEST_F(KeyboardTest, ModifiersAreKept) {
   // \uE00A is the Alt-key modifier.
   // \uE008 is the Shift-key modifier.
-  std::string keys = "\uE00A\uE008";
+  std::string keys = u8"\uE00A\uE008";
   Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_);
 
   ASSERT_EQ(events_.size(), 2);
@@ -205,7 +205,7 @@
 TEST_F(KeyboardTest, ModifiersAreReleased) {
   // \uE00A is the Alt-key modifier.
   // \uE008 is the Shift-key modifier.
-  std::string keys = "\uE00A\uE008";
+  std::string keys = u8"\uE00A\uE008";
   Keyboard::TranslateToKeyEvents(keys, Keyboard::kReleaseModifiers, &events_);
 
   ASSERT_EQ(events_.size(), 4);
@@ -223,7 +223,7 @@
 
 TEST_F(KeyboardTest, SpecialCharacter) {
   // \uE012 is the Left-arrow key.
-  std::string keys = "\uE012";
+  std::string keys = u8"\uE012";
   Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_);
 
   ASSERT_EQ(events_.size(), 2);
@@ -236,7 +236,7 @@
 
 TEST_F(KeyboardTest, ModifierIsSticky) {
   // \uE00A is the Alt-key modifier. Corresponds to the kMenu key code.
-  std::string keys = "\uE00AaB";
+  std::string keys = u8"\uE00AaB";
   Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_);
 
   // keydown(alt)
@@ -264,7 +264,7 @@
 
 TEST_F(KeyboardTest, ToggleModifier) {
   // \uE008 is the Shift-key modifier.
-  std::string keys = "\uE008a\uE008a";
+  std::string keys = u8"\uE008a\uE008a";
   Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_);
 
   // keydown(shift)
@@ -289,7 +289,7 @@
 }
 
 TEST_F(KeyboardTest, NullClearsModifiers) {
-  std::string keys = "\uE008\uE00A\uE000a";
+  std::string keys = u8"\uE008\uE00A\uE000a";
   Keyboard::TranslateToKeyEvents(keys, Keyboard::kKeepModifiers, &events_);
 
   // keydown(shift)
diff --git a/src/cobalt/websocket/web_socket_test.cc b/src/cobalt/websocket/web_socket_test.cc
index ebca33f..d2803e7 100644
--- a/src/cobalt/websocket/web_socket_test.cc
+++ b/src/cobalt/websocket/web_socket_test.cc
@@ -108,7 +108,6 @@
 }
 
 TEST_F(WebSocketTest, TestInitialReadyState) {
-  scoped_ptr<FakeSettings> settings_;
   scoped_refptr<WebSocket> ws(
       new WebSocket(settings(), "ws://example.com", &exception_state_, false));
   EXPECT_EQ(ws->ready_state(), WebSocket::kConnecting);
diff --git a/src/cobalt/xhr/xml_http_request.cc b/src/cobalt/xhr/xml_http_request.cc
index fb2b97d..7af4b99 100644
--- a/src/cobalt/xhr/xml_http_request.cc
+++ b/src/cobalt/xhr/xml_http_request.cc
@@ -163,8 +163,7 @@
       error_(false),
       sent_(false),
       stop_timeout_(false),
-      upload_complete_(false),
-      did_add_ref_(false) {
+      upload_complete_(false) {
   DCHECK(settings_);
   dom::GlobalStats::GetInstance()->Add(this);
   xhr_id_ = ++s_xhr_sequence_num_;
@@ -860,13 +859,9 @@
 void XMLHttpRequest::PreventGarbageCollection() {
   settings_->global_environment()->PreventGarbageCollection(
       make_scoped_refptr(this));
-  DCHECK(!did_add_ref_);
-  did_add_ref_ = true;
 }
 
 void XMLHttpRequest::AllowGarbageCollection() {
-  DCHECK(did_add_ref_);
-
   bool is_active = (state_ == kOpened && sent_) || state_ == kHeadersReceived ||
                    state_ == kLoading;
   bool has_event_listeners =
@@ -880,7 +875,6 @@
 
   DCHECK_EQ((is_active && has_event_listeners), false);
 
-  did_add_ref_ = false;
   settings_->javascript_engine()->ReportExtraMemoryCost(
       response_body_.capacity());
   settings_->global_environment()->AllowGarbageCollection(
diff --git a/src/cobalt/xhr/xml_http_request.h b/src/cobalt/xhr/xml_http_request.h
index 6646e05..ab9a5e4 100644
--- a/src/cobalt/xhr/xml_http_request.h
+++ b/src/cobalt/xhr/xml_http_request.h
@@ -272,9 +272,6 @@
   bool stop_timeout_;
   bool upload_complete_;
 
-  // For debugging our reference count manipulations.
-  bool did_add_ref_;
-
   static bool verbose_;
   // Unique ID for debugging.
   int xhr_id_;
diff --git a/src/googleurl/googleurl.gyp b/src/googleurl/googleurl.gyp
index 093a61d..4d44cf2 100644
--- a/src/googleurl/googleurl.gyp
+++ b/src/googleurl/googleurl.gyp
@@ -67,11 +67,6 @@
             ],
           },
         }],
-        ['OS=="lb_shell"', {
-          'dependencies': [
-            '<(lbshell_root)/build/projects/posix_emulation.gyp:posix_emulation',
-          ],
-        }],
         ['OS=="starboard"', {
           'dependencies': [
             '<(DEPTH)/starboard/starboard.gyp:starboard',
diff --git a/src/media/audio/shell_audio_streamer_starboard.cc b/src/media/audio/shell_audio_streamer_starboard.cc
deleted file mode 100644
index 22a143f..0000000
--- a/src/media/audio/shell_audio_streamer_starboard.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "media/audio/shell_audio_streamer.h"
-
-namespace media {
-
-void ShellAudioStreamer::Initialize() {}
-
-void ShellAudioStreamer::Terminate() {}
-
-ShellAudioStreamer* ShellAudioStreamer::Instance() {
-  return NULL;
-}
-
-}  // namespace media
diff --git a/src/media/base/decoder_buffer_cache.cc b/src/media/base/decoder_buffer_cache.cc
deleted file mode 100644
index 92d35ee..0000000
--- a/src/media/base/decoder_buffer_cache.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "media/base/decoder_buffer_cache.h"
-
-namespace media {
-
-DecoderBufferCache::DecoderBufferCache()
-    : audio_buffer_index_(0), video_buffer_index_(0) {}
-
-void DecoderBufferCache::AddBuffer(DemuxerStream::Type type,
-                                   const scoped_refptr<DecoderBuffer>& buffer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (type == DemuxerStream::AUDIO) {
-    audio_buffers_.push_back(buffer);
-    if (buffer->IsKeyframe()) {
-      audio_key_frame_timestamps_.push_back(buffer->GetTimestamp());
-    }
-  } else {
-    DCHECK_EQ(type, DemuxerStream::VIDEO);
-    video_buffers_.push_back(buffer);
-    if (buffer->IsKeyframe()) {
-      video_key_frame_timestamps_.push_back(buffer->GetTimestamp());
-    }
-  }
-}
-
-void DecoderBufferCache::ClearSegmentsBeforeMediaTime(
-    base::TimeDelta media_time) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  ClearSegmentsBeforeMediaTime(media_time, &audio_buffers_,
-                               &audio_key_frame_timestamps_);
-  ClearSegmentsBeforeMediaTime(media_time, &video_buffers_,
-                               &video_key_frame_timestamps_);
-}
-
-void DecoderBufferCache::ClearAll() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  audio_buffers_.clear();
-  audio_key_frame_timestamps_.clear();
-  video_buffers_.clear();
-  video_key_frame_timestamps_.clear();
-}
-
-void DecoderBufferCache::StartResuming() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  audio_buffer_index_ = 0;
-  video_buffer_index_ = 0;
-}
-
-scoped_refptr<DecoderBuffer> DecoderBufferCache::GetBuffer(
-    DemuxerStream::Type type) const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (type == DemuxerStream::AUDIO) {
-    if (audio_buffer_index_ < audio_buffers_.size()) {
-      return audio_buffers_[audio_buffer_index_];
-    }
-    return NULL;
-  }
-
-  DCHECK_EQ(type, DemuxerStream::VIDEO);
-  if (video_buffer_index_ < video_buffers_.size()) {
-    return video_buffers_[video_buffer_index_];
-  }
-  return NULL;
-}
-
-void DecoderBufferCache::AdvanceToNextBuffer(DemuxerStream::Type type) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (type == DemuxerStream::AUDIO) {
-    ++audio_buffer_index_;
-  } else {
-    DCHECK_EQ(type, DemuxerStream::VIDEO);
-    ++video_buffer_index_;
-  }
-}
-
-// static
-void DecoderBufferCache::ClearSegmentsBeforeMediaTime(
-    base::TimeDelta media_time,
-    Buffers* buffers,
-    KeyFrameTimestamps* key_frame_timestamps) {
-  // Use K to denote a key frame and N for non-key frame.  If the cache contains
-  // K N N N N N N N N K N N N N N N N N K N N N N N N N N
-  //                     |
-  //                 media_time
-  // Then we should remove everything before the key frame before the
-  // |media_time| and turn the cache into:
-  //                   K N N N N N N N N K N N N N N N N N
-  //                     |
-  //                 media_time
-  // So we need at least two keyframes before we can remove any frames.
-  while (key_frame_timestamps->size() > 1 &&
-         key_frame_timestamps->at(1) <= media_time) {
-    key_frame_timestamps->erase(key_frame_timestamps->begin());
-  }
-  if (key_frame_timestamps->empty()) {
-    return;
-  }
-  while (scoped_refptr<DecoderBuffer> buffer = buffers->front()) {
-    if (buffer->IsKeyframe() &&
-        buffer->GetTimestamp() == key_frame_timestamps->front()) {
-      break;
-    }
-    buffers->pop_front();
-  }
-}
-
-}  // namespace media
diff --git a/src/media/base/decoder_buffer_cache.h b/src/media/base/decoder_buffer_cache.h
deleted file mode 100644
index 49ba5ec..0000000
--- a/src/media/base/decoder_buffer_cache.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef MEDIA_BASE_DECODER_BUFFER_CACHE_H_
-#define MEDIA_BASE_DECODER_BUFFER_CACHE_H_
-
-#include <deque>
-
-#include "base/memory/ref_counted.h"
-#include "base/threading/thread_checker.h"
-#include "base/time.h"
-#include "media/base/decoder_buffer.h"
-#include "media/base/demuxer_stream.h"
-
-namespace media {
-
-// This class can be used to hold media buffers in decoding order.  It also
-// provides function that given a media time, the function will find a key frame
-// before the media time and clear all buffers before the key frame.  This class
-// can be used to "replay" the video from the current playback position and can
-// be useful to implement suspend/resume.
-class DecoderBufferCache {
- public:
-  DecoderBufferCache();
-
-  void AddBuffer(DemuxerStream::Type type,
-                 const scoped_refptr<DecoderBuffer>& buffer);
-  void ClearSegmentsBeforeMediaTime(base::TimeDelta media_time);
-  void ClearAll();
-
-  // Start resuming, reset indices to audio/video buffers to the very beginning.
-  void StartResuming();
-  scoped_refptr<DecoderBuffer> GetBuffer(DemuxerStream::Type type) const;
-  void AdvanceToNextBuffer(DemuxerStream::Type type);
-
- private:
-  typedef std::deque<scoped_refptr<DecoderBuffer> > Buffers;
-  typedef std::deque<base::TimeDelta> KeyFrameTimestamps;
-
-  static void ClearSegmentsBeforeMediaTime(
-      base::TimeDelta media_time,
-      Buffers* buffers,
-      KeyFrameTimestamps* key_frame_timestamps);
-
-  base::ThreadChecker thread_checker_;
-
-  Buffers audio_buffers_;
-  KeyFrameTimestamps audio_key_frame_timestamps_;
-
-  Buffers video_buffers_;
-  KeyFrameTimestamps video_key_frame_timestamps_;
-
-  size_t audio_buffer_index_;
-  size_t video_buffer_index_;
-};
-
-}  // namespace media
-
-#endif  // MEDIA_BASE_DECODER_BUFFER_CACHE_H_
diff --git a/src/media/base/sbplayer_pipeline.cc b/src/media/base/sbplayer_pipeline.cc
deleted file mode 100644
index aaaff86..0000000
--- a/src/media/base/sbplayer_pipeline.cc
+++ /dev/null
@@ -1,846 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <vector>
-
-#include "base/basictypes.h"  // For COMPILE_ASSERT
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop.h"
-#include "base/optional.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/time.h"
-#include "media/base/audio_decoder_config.h"
-#include "media/base/bind_to_loop.h"
-#include "media/base/channel_layout.h"
-#include "media/base/decoder_buffer.h"
-#include "media/base/demuxer.h"
-#include "media/base/demuxer_stream.h"
-#include "media/base/filter_collection.h"
-#include "media/base/media_export.h"
-#include "media/base/media_log.h"
-#include "media/base/pipeline.h"
-#include "media/base/pipeline_status.h"
-#include "media/base/ranges.h"
-#include "media/base/sbplayer_set_bounds_helper.h"
-#include "media/base/starboard_player.h"
-#include "media/base/starboard_utils.h"
-#include "media/base/video_decoder_config.h"
-#include "media/crypto/starboard_decryptor.h"
-#include "ui/gfx/size.h"
-
-namespace media {
-
-#if SB_HAS(PLAYER)
-
-using base::Time;
-using base::TimeDelta;
-
-namespace {
-
-// Used to post parameters to SbPlayerPipeline::StartTask() as the number of
-// parameters exceed what base::Bind() can support.
-struct StartTaskParameters {
-  scoped_refptr<Demuxer> demuxer;
-  SetDecryptorReadyCB decryptor_ready_cb;
-  PipelineStatusCB ended_cb;
-  PipelineStatusCB error_cb;
-  PipelineStatusCB seek_cb;
-  Pipeline::BufferingStateCB buffering_state_cb;
-  base::Closure duration_change_cb;
-};
-
-// SbPlayerPipeline is a PipelineBase implementation that uses the SbPlayer
-// interface internally.
-class MEDIA_EXPORT SbPlayerPipeline : public Pipeline,
-                                      public DemuxerHost,
-                                      public StarboardPlayer::Host {
- public:
-  // Constructs a media pipeline that will execute on |message_loop|.
-  SbPlayerPipeline(PipelineWindow window,
-                   const scoped_refptr<base::MessageLoopProxy>& message_loop,
-                   MediaLog* media_log);
-  ~SbPlayerPipeline() OVERRIDE;
-
-  void Suspend() OVERRIDE;
-  void Resume() OVERRIDE;
-  void Start(scoped_ptr<FilterCollection> filter_collection,
-             const SetDecryptorReadyCB& decryptor_ready_cb,
-             const PipelineStatusCB& ended_cb,
-             const PipelineStatusCB& error_cb,
-             const PipelineStatusCB& seek_cb,
-             const BufferingStateCB& buffering_state_cb,
-             const base::Closure& duration_change_cb) OVERRIDE;
-
-  void Stop(const base::Closure& stop_cb) OVERRIDE;
-  void Seek(TimeDelta time, const PipelineStatusCB& seek_cb);
-  bool HasAudio() const OVERRIDE;
-  bool HasVideo() const OVERRIDE;
-
-  float GetPlaybackRate() const OVERRIDE;
-  void SetPlaybackRate(float playback_rate) OVERRIDE;
-  float GetVolume() const OVERRIDE;
-  void SetVolume(float volume) OVERRIDE;
-
-  TimeDelta GetMediaTime() const OVERRIDE;
-  Ranges<TimeDelta> GetBufferedTimeRanges() OVERRIDE;
-  TimeDelta GetMediaDuration() const OVERRIDE;
-  int64 GetTotalBytes() const OVERRIDE;
-  void GetNaturalVideoSize(gfx::Size* out_size) const OVERRIDE;
-
-  bool DidLoadingProgress() const OVERRIDE;
-  PipelineStatistics GetStatistics() const OVERRIDE;
-  SetBoundsCB GetSetBoundsCB() OVERRIDE;
-  void SetDecodeToTextureOutputMode(bool preference) OVERRIDE;
-
- private:
-  void StartTask(const StartTaskParameters& parameters);
-  void SetVolumeTask(float volume);
-  void SetPlaybackRateTask(float volume);
-  void SetDurationTask(TimeDelta duration);
-
-  // DataSourceHost (by way of DemuxerHost) implementation.
-  void SetTotalBytes(int64 total_bytes) OVERRIDE;
-  void AddBufferedByteRange(int64 start, int64 end) OVERRIDE;
-  void AddBufferedTimeRange(TimeDelta start, TimeDelta end) OVERRIDE;
-
-  // DemuxerHost implementaion.
-  void SetDuration(TimeDelta duration) OVERRIDE;
-  void OnDemuxerError(PipelineStatus error) OVERRIDE;
-
-  void CreatePlayer(SbDrmSystem drm_system);
-  void SetDecryptor(Decryptor* decryptor);
-  void OnDemuxerInitialized(PipelineStatus status);
-  void OnDemuxerSeeked(PipelineStatus status);
-  void OnDemuxerStopped();
-  void OnDemuxerStreamRead(DemuxerStream::Type type,
-                           DemuxerStream::Status status,
-                           const scoped_refptr<DecoderBuffer>& buffer);
-
-  // StarboardPlayer::Host implementation.
-  void OnNeedData(DemuxerStream::Type type) OVERRIDE;
-  void OnPlayerStatus(SbPlayerState state) OVERRIDE;
-
-  void UpdateDecoderConfig(const scoped_refptr<DemuxerStream>& stream);
-
-  void SuspendTask(base::WaitableEvent* done_event);
-  void ResumeTask(base::WaitableEvent* done_event);
-
-  // Message loop used to execute pipeline tasks.  It is thread-safe.
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
-
-  // The window this player associates with.  It should only be assigned in the
-  // dtor and accesed once by SbPlayerCreate().
-  PipelineWindow window_;
-
-  // Lock used to serialize access for the following member variables.
-  mutable base::Lock lock_;
-
-  // Amount of available buffered data.  Set by filters.
-  Ranges<int64> buffered_byte_ranges_;
-  Ranges<TimeDelta> buffered_time_ranges_;
-
-  // True when AddBufferedByteRange() has been called more recently than
-  // DidLoadingProgress().
-  mutable bool did_loading_progress_;
-
-  // Total size of the media.  Set by filters.
-  int64 total_bytes_;
-
-  // Video's natural width and height.  Set by filters.
-  gfx::Size natural_size_;
-
-  // Current volume level (from 0.0f to 1.0f).  This value is set immediately
-  // via SetVolume() and a task is dispatched on the message loop to notify the
-  // filters.
-  float volume_;
-
-  // Current playback rate (>= 0.0f).  This value is set immediately via
-  // SetPlaybackRate() and a task is dispatched on the message loop to notify
-  // the filters.
-  float playback_rate_;
-
-  // Whether the media contains rendered audio and video streams.
-  // TODO(fischman,scherkus): replace these with checks for
-  // {audio,video}_decoder_ once extraction of {Audio,Video}Decoder from the
-  // Filter heirarchy is done.
-  bool has_audio_;
-  bool has_video_;
-
-  mutable PipelineStatistics statistics_;
-
-  // The following member variables are only accessed by tasks posted to
-  // |message_loop_|.
-
-  // Temporary callback used for Stop().
-  base::Closure stop_cb_;
-
-  // Permanent callbacks passed in via Start().
-  SetDecryptorReadyCB decryptor_ready_cb_;
-  PipelineStatusCB ended_cb_;
-  PipelineStatusCB error_cb_;
-  BufferingStateCB buffering_state_cb_;
-  base::Closure duration_change_cb_;
-  base::optional<bool> decode_to_texture_output_mode_;
-
-  // Demuxer reference used for setting the preload value.
-  scoped_refptr<Demuxer> demuxer_;
-  bool audio_read_in_progress_;
-  bool video_read_in_progress_;
-  TimeDelta duration_;
-
-  scoped_refptr<SbPlayerSetBoundsHelper> set_bounds_helper_;
-
-  // The following member variables can be accessed from WMPI thread but all
-  // modifications to them happens on the pipeline thread.  So any access of
-  // them from the WMPI thread and any modification to them on the pipeline
-  // thread has to guarded by lock.  Access to them from the pipeline thread
-  // needn't to be guarded.
-
-  // Temporary callback used for Start() and Seek().
-  PipelineStatusCB seek_cb_;
-  base::TimeDelta seek_time_;
-  scoped_ptr<StarboardPlayer> player_;
-  bool suspended_;
-
-  DISALLOW_COPY_AND_ASSIGN(SbPlayerPipeline);
-};
-
-SbPlayerPipeline::SbPlayerPipeline(
-    PipelineWindow window,
-    const scoped_refptr<base::MessageLoopProxy>& message_loop,
-    MediaLog* media_log)
-    : window_(window),
-      message_loop_(message_loop),
-      total_bytes_(0),
-      natural_size_(0, 0),
-      volume_(1.f),
-      playback_rate_(0.f),
-      has_audio_(false),
-      has_video_(false),
-      audio_read_in_progress_(false),
-      video_read_in_progress_(false),
-      set_bounds_helper_(new SbPlayerSetBoundsHelper),
-      suspended_(false) {}
-
-SbPlayerPipeline::~SbPlayerPipeline() {
-  DCHECK(!player_);
-}
-
-void SbPlayerPipeline::Suspend() {
-  DCHECK(!message_loop_->BelongsToCurrentThread());
-
-  base::WaitableEvent waitable_event(true, /* manual_reset */
-                                     false /* initially_signaled */);
-  message_loop_->PostTask(FROM_HERE,
-                          base::Bind(&SbPlayerPipeline::SuspendTask,
-                                     base::Unretained(this), &waitable_event));
-  waitable_event.Wait();
-}
-
-void SbPlayerPipeline::Resume() {
-  DCHECK(!message_loop_->BelongsToCurrentThread());
-
-  base::WaitableEvent waitable_event(true, /* manual_reset */
-                                     false /* initially_signaled */);
-  message_loop_->PostTask(FROM_HERE,
-                          base::Bind(&SbPlayerPipeline::ResumeTask,
-                                     base::Unretained(this), &waitable_event));
-  waitable_event.Wait();
-}
-
-void SbPlayerPipeline::Start(scoped_ptr<FilterCollection> filter_collection,
-                             const SetDecryptorReadyCB& decryptor_ready_cb,
-                             const PipelineStatusCB& ended_cb,
-                             const PipelineStatusCB& error_cb,
-                             const PipelineStatusCB& seek_cb,
-                             const BufferingStateCB& buffering_state_cb,
-                             const base::Closure& duration_change_cb) {
-  DCHECK(filter_collection);
-
-  StartTaskParameters parameters;
-  parameters.demuxer = filter_collection->GetDemuxer();
-  parameters.decryptor_ready_cb = decryptor_ready_cb;
-  parameters.ended_cb = ended_cb;
-  parameters.error_cb = error_cb;
-  parameters.seek_cb = seek_cb;
-  parameters.buffering_state_cb = buffering_state_cb;
-  parameters.duration_change_cb = duration_change_cb;
-
-  message_loop_->PostTask(
-      FROM_HERE, base::Bind(&SbPlayerPipeline::StartTask, this, parameters));
-}
-
-void SbPlayerPipeline::Stop(const base::Closure& stop_cb) {
-  if (!message_loop_->BelongsToCurrentThread()) {
-    message_loop_->PostTask(FROM_HERE,
-                            base::Bind(&SbPlayerPipeline::Stop, this, stop_cb));
-    return;
-  }
-
-  DCHECK(stop_cb_.is_null());
-  DCHECK(!stop_cb.is_null());
-
-  if (player_) {
-    scoped_ptr<StarboardPlayer> player;
-    {
-      base::AutoLock auto_lock(lock_);
-      player = player_.Pass();
-    }
-
-    DLOG(INFO) << "Destroying SbPlayer.";
-    player.reset();
-    DLOG(INFO) << "SbPlayer destroyed.";
-  }
-
-  // When Stop() is in progress, we no longer need to call |error_cb_|.
-  error_cb_.Reset();
-  if (demuxer_) {
-    stop_cb_ = stop_cb;
-    demuxer_->Stop(base::Bind(&SbPlayerPipeline::OnDemuxerStopped, this));
-  } else {
-    stop_cb.Run();
-  }
-}
-
-void SbPlayerPipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) {
-  if (!message_loop_->BelongsToCurrentThread()) {
-    message_loop_->PostTask(
-        FROM_HERE, base::Bind(&SbPlayerPipeline::Seek, this, time, seek_cb));
-    return;
-  }
-
-  if (!player_) {
-    seek_cb.Run(PIPELINE_ERROR_INVALID_STATE);
-    return;
-  }
-
-  player_->PrepareForSeek();
-
-  DCHECK(seek_cb_.is_null());
-  DCHECK(!seek_cb.is_null());
-
-  if (audio_read_in_progress_ || video_read_in_progress_) {
-    message_loop_->PostTask(
-        FROM_HERE, base::Bind(&SbPlayerPipeline::Seek, this, time, seek_cb));
-    return;
-  }
-
-  {
-    base::AutoLock auto_lock(lock_);
-    seek_cb_ = seek_cb;
-    seek_time_ = time;
-  }
-  demuxer_->Seek(time, BindToCurrentLoop(base::Bind(
-                           &SbPlayerPipeline::OnDemuxerSeeked, this)));
-}
-
-bool SbPlayerPipeline::HasAudio() const {
-  base::AutoLock auto_lock(lock_);
-  return has_audio_;
-}
-
-bool SbPlayerPipeline::HasVideo() const {
-  base::AutoLock auto_lock(lock_);
-  return has_video_;
-}
-
-float SbPlayerPipeline::GetPlaybackRate() const {
-  base::AutoLock auto_lock(lock_);
-  return playback_rate_;
-}
-
-void SbPlayerPipeline::SetPlaybackRate(float playback_rate) {
-  base::AutoLock auto_lock(lock_);
-  playback_rate_ = playback_rate;
-  message_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&SbPlayerPipeline::SetPlaybackRateTask, this, playback_rate));
-}
-
-float SbPlayerPipeline::GetVolume() const {
-  base::AutoLock auto_lock(lock_);
-  return volume_;
-}
-
-void SbPlayerPipeline::SetVolume(float volume) {
-  if (volume < 0.0f || volume > 1.0f)
-    return;
-
-  base::AutoLock auto_lock(lock_);
-  volume_ = volume;
-  message_loop_->PostTask(
-      FROM_HERE, base::Bind(&SbPlayerPipeline::SetVolumeTask, this, volume));
-}
-
-TimeDelta SbPlayerPipeline::GetMediaTime() const {
-  base::AutoLock auto_lock(lock_);
-
-  if (!seek_cb_.is_null()) {
-    return seek_time_;
-  }
-  if (!player_) {
-    return TimeDelta();
-  }
-  base::TimeDelta media_time;
-  player_->GetInfo(&statistics_.video_frames_decoded,
-                   &statistics_.video_frames_dropped, &media_time);
-  return media_time;
-}
-
-Ranges<TimeDelta> SbPlayerPipeline::GetBufferedTimeRanges() {
-  base::AutoLock auto_lock(lock_);
-  Ranges<TimeDelta> time_ranges;
-  for (size_t i = 0; i < buffered_time_ranges_.size(); ++i) {
-    time_ranges.Add(buffered_time_ranges_.start(i),
-                    buffered_time_ranges_.end(i));
-  }
-  NOTIMPLEMENTED();
-  /*if (clock_->Duration() == TimeDelta() || total_bytes_ == 0)
-    return time_ranges;
-  for (size_t i = 0; i < buffered_byte_ranges_.size(); ++i) {
-    TimeDelta start = TimeForByteOffset_Locked(buffered_byte_ranges_.start(i));
-    TimeDelta end = TimeForByteOffset_Locked(buffered_byte_ranges_.end(i));
-    // Cap approximated buffered time at the length of the video.
-    end = std::min(end, clock_->Duration());
-    time_ranges.Add(start, end);
-  }*/
-
-  return time_ranges;
-}
-
-TimeDelta SbPlayerPipeline::GetMediaDuration() const {
-  base::AutoLock auto_lock(lock_);
-  return duration_;
-}
-
-int64 SbPlayerPipeline::GetTotalBytes() const {
-  base::AutoLock auto_lock(lock_);
-  return total_bytes_;
-}
-
-void SbPlayerPipeline::GetNaturalVideoSize(gfx::Size* out_size) const {
-  CHECK(out_size);
-  base::AutoLock auto_lock(lock_);
-  *out_size = natural_size_;
-}
-
-bool SbPlayerPipeline::DidLoadingProgress() const {
-  base::AutoLock auto_lock(lock_);
-  bool ret = did_loading_progress_;
-  did_loading_progress_ = false;
-  return ret;
-}
-
-PipelineStatistics SbPlayerPipeline::GetStatistics() const {
-  base::AutoLock auto_lock(lock_);
-  return statistics_;
-}
-
-Pipeline::SetBoundsCB SbPlayerPipeline::GetSetBoundsCB() {
-  return base::Bind(&SbPlayerSetBoundsHelper::SetBounds, set_bounds_helper_);
-}
-
-void SbPlayerPipeline::SetDecodeToTextureOutputMode(bool enabled) {
-  if (!message_loop_->BelongsToCurrentThread()) {
-    message_loop_->PostTask(
-        FROM_HERE, base::Bind(&SbPlayerPipeline::SetDecodeToTextureOutputMode,
-                              this, enabled));
-    return;
-  }
-
-  decode_to_texture_output_mode_ = enabled;
-}
-
-void SbPlayerPipeline::StartTask(const StartTaskParameters& parameters) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  DCHECK(!demuxer_);
-
-  demuxer_ = parameters.demuxer;
-  decryptor_ready_cb_ = parameters.decryptor_ready_cb;
-  ended_cb_ = parameters.ended_cb;
-  error_cb_ = parameters.error_cb;
-  {
-    base::AutoLock auto_lock(lock_);
-    seek_cb_ = parameters.seek_cb;
-  }
-  buffering_state_cb_ = parameters.buffering_state_cb;
-  duration_change_cb_ = parameters.duration_change_cb;
-
-  demuxer_->Initialize(
-      this, BindToCurrentLoop(
-                base::Bind(&SbPlayerPipeline::OnDemuxerInitialized, this)));
-}
-
-void SbPlayerPipeline::SetVolumeTask(float volume) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  if (player_) {
-    player_->SetVolume(volume_);
-  }
-}
-
-void SbPlayerPipeline::SetPlaybackRateTask(float volume) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  if (player_) {
-    player_->SetPlaybackRate(playback_rate_);
-  }
-}
-
-void SbPlayerPipeline::SetDurationTask(TimeDelta duration) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-  if (!duration_change_cb_.is_null()) {
-    duration_change_cb_.Run();
-  }
-}
-
-void SbPlayerPipeline::SetTotalBytes(int64 total_bytes) {
-  base::AutoLock auto_lock(lock_);
-  total_bytes_ = total_bytes;
-}
-
-void SbPlayerPipeline::SetDuration(TimeDelta duration) {
-  base::AutoLock auto_lock(lock_);
-  duration_ = duration;
-  message_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&SbPlayerPipeline::SetDurationTask, this, duration));
-}
-
-void SbPlayerPipeline::OnDemuxerError(PipelineStatus error) {
-  if (!message_loop_->BelongsToCurrentThread()) {
-    message_loop_->PostTask(
-        FROM_HERE, base::Bind(&SbPlayerPipeline::OnDemuxerError, this, error));
-    return;
-  }
-
-  if (error != PIPELINE_OK) {
-    ResetAndRunIfNotNull(&error_cb_, error);
-  }
-}
-
-void SbPlayerPipeline::AddBufferedByteRange(int64 start, int64 end) {
-  base::AutoLock auto_lock(lock_);
-  buffered_byte_ranges_.Add(start, end);
-  did_loading_progress_ = true;
-}
-
-void SbPlayerPipeline::AddBufferedTimeRange(TimeDelta start, TimeDelta end) {
-  base::AutoLock auto_lock(lock_);
-  buffered_time_ranges_.Add(start, end);
-  did_loading_progress_ = true;
-}
-
-void SbPlayerPipeline::CreatePlayer(SbDrmSystem drm_system) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  if (suspended_) {
-    message_loop_->PostTask(
-        FROM_HERE,
-        base::Bind(&SbPlayerPipeline::CreatePlayer, this, drm_system));
-    return;
-  }
-
-  // TODO:  Check |suspended_| here as the pipeline can be suspended before the
-  // player is created.  In this case we should delay creating the player as the
-  // creation of player may fail.
-  const AudioDecoderConfig& audio_config =
-      demuxer_->GetStream(DemuxerStream::AUDIO)->audio_decoder_config();
-  const VideoDecoderConfig& video_config =
-      demuxer_->GetStream(DemuxerStream::VIDEO)->video_decoder_config();
-
-  {
-    base::AutoLock auto_lock(lock_);
-    player_.reset(new StarboardPlayer(
-        message_loop_, audio_config, video_config, window_, drm_system, this,
-        set_bounds_helper_.get(), *decode_to_texture_output_mode_));
-    SetPlaybackRateTask(playback_rate_);
-    SetVolumeTask(volume_);
-  }
-
-  if (player_->IsValid()) {
-    return;
-  }
-
-  player_.reset();
-
-  PipelineStatusCB seek_cb;
-  {
-    base::AutoLock auto_lock(lock_);
-    DCHECK(!seek_cb_.is_null());
-    seek_cb = base::ResetAndReturn(&seek_cb_);
-  }
-  seek_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
-}
-
-void SbPlayerPipeline::SetDecryptor(Decryptor* decryptor) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  if (!decryptor) {
-    return;
-  }
-  StarboardDecryptor* sb_decryptor =
-      reinterpret_cast<StarboardDecryptor*>(decryptor);
-  CreatePlayer(sb_decryptor->drm_system());
-}
-
-void SbPlayerPipeline::OnDemuxerInitialized(PipelineStatus status) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  if (status != PIPELINE_OK) {
-    ResetAndRunIfNotNull(&error_cb_, status);
-    return;
-  }
-
-  if (demuxer_->GetStream(DemuxerStream::AUDIO) == NULL ||
-      demuxer_->GetStream(DemuxerStream::VIDEO) == NULL) {
-    ResetAndRunIfNotNull(&error_cb_, DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
-    return;
-  }
-
-  {
-    base::AutoLock auto_lock(lock_);
-    has_audio_ = demuxer_->GetStream(DemuxerStream::AUDIO) != NULL;
-    DCHECK(has_audio_);
-    has_video_ = demuxer_->GetStream(DemuxerStream::VIDEO) != NULL;
-
-    buffering_state_cb_.Run(kHaveMetadata);
-
-    const AudioDecoderConfig& audio_config =
-        demuxer_->GetStream(DemuxerStream::AUDIO)->audio_decoder_config();
-    bool is_encrypted = audio_config.is_encrypted();
-    if (has_video_) {
-      const VideoDecoderConfig& video_config =
-          demuxer_->GetStream(DemuxerStream::VIDEO)->video_decoder_config();
-      natural_size_ = video_config.natural_size();
-      is_encrypted |= video_config.is_encrypted();
-    }
-    if (is_encrypted) {
-      decryptor_ready_cb_.Run(
-          BindToCurrentLoop(base::Bind(&SbPlayerPipeline::SetDecryptor, this)));
-      return;
-    }
-  }
-
-  CreatePlayer(kSbDrmSystemInvalid);
-}
-
-void SbPlayerPipeline::OnDemuxerSeeked(PipelineStatus status) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  if (status == PIPELINE_OK) {
-    player_->Seek(seek_time_);
-  }
-}
-
-void SbPlayerPipeline::OnDemuxerStopped() {
-  if (!message_loop_->BelongsToCurrentThread()) {
-    message_loop_->PostTask(
-        FROM_HERE, base::Bind(&SbPlayerPipeline::OnDemuxerStopped, this));
-    return;
-  }
-
-  base::ResetAndReturn(&stop_cb_).Run();
-}
-
-void SbPlayerPipeline::OnDemuxerStreamRead(
-    DemuxerStream::Type type,
-    DemuxerStream::Status status,
-    const scoped_refptr<DecoderBuffer>& buffer) {
-  DCHECK(type == DemuxerStream::AUDIO || type == DemuxerStream::VIDEO)
-      << "Unsupported DemuxerStream::Type " << type;
-
-  if (!message_loop_->BelongsToCurrentThread()) {
-    message_loop_->PostTask(
-        FROM_HERE, base::Bind(&SbPlayerPipeline::OnDemuxerStreamRead, this,
-                              type, status, buffer));
-    return;
-  }
-
-  scoped_refptr<DemuxerStream> stream = demuxer_->GetStream(type);
-
-  // In case if Stop() has been called.
-  if (!player_) {
-    return;
-  }
-
-  if (status == DemuxerStream::kAborted) {
-    if (type == DemuxerStream::AUDIO) {
-      DCHECK(audio_read_in_progress_);
-      audio_read_in_progress_ = false;
-    } else {
-      DCHECK(video_read_in_progress_);
-      video_read_in_progress_ = false;
-    }
-    if (!seek_cb_.is_null()) {
-      PipelineStatusCB seek_cb;
-      {
-        base::AutoLock auto_lock(lock_);
-        seek_cb = base::ResetAndReturn(&seek_cb_);
-      }
-      seek_cb.Run(PIPELINE_OK);
-    }
-    return;
-  }
-
-  if (status == DemuxerStream::kConfigChanged) {
-    UpdateDecoderConfig(stream);
-    stream->Read(
-        base::Bind(&SbPlayerPipeline::OnDemuxerStreamRead, this, type));
-    return;
-  }
-
-  if (type == DemuxerStream::AUDIO) {
-    audio_read_in_progress_ = false;
-  } else {
-    video_read_in_progress_ = false;
-  }
-
-  player_->WriteBuffer(type, buffer);
-}
-
-void SbPlayerPipeline::OnNeedData(DemuxerStream::Type type) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  // In case if Stop() has been called.
-  if (!player_) {
-    return;
-  }
-
-  if (type == DemuxerStream::AUDIO) {
-    if (audio_read_in_progress_) {
-      return;
-    }
-    audio_read_in_progress_ = true;
-  } else {
-    DCHECK_EQ(type, DemuxerStream::VIDEO);
-    if (video_read_in_progress_) {
-      return;
-    }
-    video_read_in_progress_ = true;
-  }
-  scoped_refptr<DemuxerStream> stream = demuxer_->GetStream(type);
-  stream->Read(base::Bind(&SbPlayerPipeline::OnDemuxerStreamRead, this, type));
-}
-
-void SbPlayerPipeline::OnPlayerStatus(SbPlayerState state) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  // In case if Stop() has been called.
-  if (!player_) {
-    return;
-  }
-  switch (state) {
-    case kSbPlayerStateInitialized:
-      NOTREACHED();
-      break;
-    case kSbPlayerStatePrerolling:
-      break;
-    case kSbPlayerStatePresenting:
-      buffering_state_cb_.Run(kPrerollCompleted);
-      if (!seek_cb_.is_null()) {
-        PipelineStatusCB seek_cb;
-        {
-          base::AutoLock auto_lock(lock_);
-          seek_cb = base::ResetAndReturn(&seek_cb_);
-        }
-        seek_cb.Run(PIPELINE_OK);
-      }
-      break;
-    case kSbPlayerStateEndOfStream:
-      ended_cb_.Run(PIPELINE_OK);
-      break;
-    case kSbPlayerStateDestroyed:
-      break;
-    case kSbPlayerStateError:
-      ResetAndRunIfNotNull(&error_cb_, PIPELINE_ERROR_DECODE);
-      break;
-  }
-}
-
-void SbPlayerPipeline::UpdateDecoderConfig(
-    const scoped_refptr<DemuxerStream>& stream) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  if (stream->type() == DemuxerStream::AUDIO) {
-    stream->audio_decoder_config();
-  } else {
-    DCHECK_EQ(stream->type(), DemuxerStream::VIDEO);
-    const VideoDecoderConfig& decoder_config = stream->video_decoder_config();
-    base::AutoLock auto_lock(lock_);
-    natural_size_ = decoder_config.natural_size();
-    player_->UpdateVideoResolution(static_cast<int>(natural_size_.width()),
-                                   static_cast<int>(natural_size_.height()));
-  }
-}
-
-void SbPlayerPipeline::SuspendTask(base::WaitableEvent* done_event) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-  DCHECK(done_event);
-  DCHECK(!suspended_);
-
-  if (suspended_) {
-    done_event->Signal();
-    return;
-  }
-
-  if (player_) {
-    player_->Suspend();
-  }
-
-  suspended_ = true;
-
-  done_event->Signal();
-}
-
-void SbPlayerPipeline::ResumeTask(base::WaitableEvent* done_event) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-  DCHECK(done_event);
-  DCHECK(suspended_);
-
-  if (!suspended_) {
-    done_event->Signal();
-    return;
-  }
-
-  if (player_) {
-    player_->Resume();
-  }
-
-  suspended_ = false;
-
-  done_event->Signal();
-}
-
-}  // namespace
-
-#endif  // SB_HAS(PLAYER)
-
-scoped_refptr<Pipeline> Pipeline::Create(
-    PipelineWindow window,
-    const scoped_refptr<base::MessageLoopProxy>& message_loop,
-    MediaLog* media_log) {
-#if SB_HAS(PLAYER)
-  return new SbPlayerPipeline(window, message_loop, media_log);
-#else
-  return NULL;
-#endif
-}
-
-}  // namespace media
diff --git a/src/media/base/sbplayer_set_bounds_helper.cc b/src/media/base/sbplayer_set_bounds_helper.cc
deleted file mode 100644
index 5e96a94..0000000
--- a/src/media/base/sbplayer_set_bounds_helper.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "media/base/sbplayer_set_bounds_helper.h"
-
-#include "media/base/starboard_player.h"
-
-namespace media {
-
-void SbPlayerSetBoundsHelper::SetPlayer(StarboardPlayer* player) {
-  base::Lock lock_;
-  player_ = player;
-}
-
-bool SbPlayerSetBoundsHelper::SetBounds(const gfx::Rect& rect) {
-  base::AutoLock auto_lock(lock_);
-  if (!player_) {
-    return false;
-  }
-  player_->SetBounds(rect);
-  return true;
-}
-
-}  // namespace media
diff --git a/src/media/base/sbplayer_set_bounds_helper.h b/src/media/base/sbplayer_set_bounds_helper.h
deleted file mode 100644
index 06affcf..0000000
--- a/src/media/base/sbplayer_set_bounds_helper.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef MEDIA_BASE_SBPLAYER_SET_BOUNDS_HELPER_H_
-#define MEDIA_BASE_SBPLAYER_SET_BOUNDS_HELPER_H_
-
-#include "base/memory/ref_counted.h"
-#include "base/synchronization/lock.h"
-#include "ui/gfx/rect.h"
-
-namespace media {
-
-class StarboardPlayer;
-
-class SbPlayerSetBoundsHelper
-    : public base::RefCountedThreadSafe<SbPlayerSetBoundsHelper> {
- public:
-  SbPlayerSetBoundsHelper() : player_(NULL) {}
-
-  void SetPlayer(StarboardPlayer* player);
-  bool SetBounds(const gfx::Rect& rect);
-
- private:
-  base::Lock lock_;
-  StarboardPlayer* player_;
-
-  DISALLOW_COPY_AND_ASSIGN(SbPlayerSetBoundsHelper);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_BASE_SBPLAYER_SET_BOUNDS_HELPER_H_
diff --git a/src/media/base/starboard_player.cc b/src/media/base/starboard_player.cc
deleted file mode 100644
index 55d813b..0000000
--- a/src/media/base/starboard_player.cc
+++ /dev/null
@@ -1,596 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "media/base/starboard_player.h"
-
-#error This implementation of StarboardPlayer is deprecated and will be removed
-#error in the next release.  You should upgrade to Starboard version 4 and
-#error Cobalt 9 to use the StarboardPlayer implementation in cobalt/media.
-#error Please contact us *immediately* if the upcoming removal of this file
-#error will break your port.
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "media/base/shell_media_platform.h"
-#include "media/base/starboard_utils.h"
-#include "starboard/configuration.h"
-#include "starboard/memory.h"
-
-namespace media {
-
-StarboardPlayer::StarboardPlayer(
-    const scoped_refptr<base::MessageLoopProxy>& message_loop,
-    const AudioDecoderConfig& audio_config,
-    const VideoDecoderConfig& video_config,
-    SbWindow window,
-    SbDrmSystem drm_system,
-    Host* host,
-    SbPlayerSetBoundsHelper* set_bounds_helper,
-    bool prefer_decode_to_texture)
-    : message_loop_(message_loop),
-      window_(window),
-      drm_system_(drm_system),
-      host_(host),
-      set_bounds_helper_(set_bounds_helper),
-      weak_this_(AsWeakPtr()),
-      frame_width_(1),
-      frame_height_(1),
-      ticket_(SB_PLAYER_INITIAL_TICKET),
-      volume_(1.0),
-      playback_rate_(0.0),
-      seek_pending_(false),
-      state_(kPlaying) {
-  DCHECK(audio_config.IsValidConfig());
-  DCHECK(video_config.IsValidConfig());
-  DCHECK(host_);
-  DCHECK(set_bounds_helper_);
-
-  audio_config_.CopyFrom(audio_config);
-  video_config_.CopyFrom(video_config);
-
-#if SB_API_VERSION >= 4
-  output_mode_ = ComputeSbPlayerOutputMode(
-      MediaVideoCodecToSbMediaVideoCodec(video_config.codec()), drm_system,
-      prefer_decode_to_texture);
-#endif  // SB_API_VERSION >= 4
-  CreatePlayer();
-
-  message_loop->PostTask(
-      FROM_HERE,
-      base::Bind(&StarboardPlayer::ClearDecoderBufferCache, weak_this_));
-}
-
-StarboardPlayer::~StarboardPlayer() {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  set_bounds_helper_->SetPlayer(NULL);
-
-  ShellMediaPlatform::Instance()->GetVideoFrameProvider()->SetOutputMode(
-      ShellVideoFrameProvider::kOutputModeInvalid);
-#if SB_API_VERSION >= 4
-  ShellMediaPlatform::Instance()
-      ->GetVideoFrameProvider()
-      ->ResetGetCurrentSbDecodeTargetFunction();
-#endif  // SB_API_VERSION >= 4
-
-  SbPlayerDestroy(player_);
-}
-
-void StarboardPlayer::UpdateVideoResolution(int frame_width, int frame_height) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  frame_width_ = frame_width;
-  frame_height_ = frame_height;
-}
-
-void StarboardPlayer::WriteBuffer(DemuxerStream::Type type,
-                                  const scoped_refptr<DecoderBuffer>& buffer) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  // When |state_| is kPlaying, cache all buffer appended.  When |state_| is
-  // kSuspended, there may still be left-over buffers appended from the pipeline
-  // so they also should be cached.
-  // When |state_| is resuming, all buffers come from the cache and shouldn't be
-  // cached.
-  if (state_ != kResuming) {
-    decoder_buffer_cache_.AddBuffer(type, buffer);
-  }
-
-  if (state_ == kSuspended) {
-    DCHECK(!SbPlayerIsValid(player_));
-    return;
-  }
-
-  DCHECK(SbPlayerIsValid(player_));
-
-  if (buffer->IsEndOfStream()) {
-    SbPlayerWriteEndOfStream(player_, DemuxerStreamTypeToSbMediaType(type));
-    return;
-  }
-
-  DecodingBuffers::iterator iter = decoding_buffers_.find(buffer->GetData());
-  if (iter == decoding_buffers_.end()) {
-    decoding_buffers_[buffer->GetData()] = std::make_pair(buffer, 1);
-  } else {
-    ++iter->second.second;
-  }
-
-  SbDrmSampleInfo drm_info;
-  SbDrmSubSampleMapping subsample_mapping;
-  bool is_encrypted = buffer->GetDecryptConfig();
-  SbMediaVideoSampleInfo video_info;
-
-  drm_info.subsample_count = 0;
-  video_info.is_key_frame = buffer->IsKeyframe();
-  video_info.frame_width = frame_width_;
-  video_info.frame_height = frame_height_;
-
-#if SB_API_VERSION >= 4
-  SbMediaColorMetadata sb_media_color_metadata =
-      MediaToSbMediaColorMetadata(video_config_.webm_color_metadata());
-  video_info.color_metadata = &sb_media_color_metadata;
-#endif
-  if (is_encrypted) {
-    FillDrmSampleInfo(buffer, &drm_info, &subsample_mapping);
-  }
-#if SB_API_VERSION >= 4
-  const void* sample_buffers[] = {buffer->GetData()};
-  int sample_buffer_sizes[] = {buffer->GetDataSize()};
-  SbPlayerWriteSample(player_, DemuxerStreamTypeToSbMediaType(type),
-                      sample_buffers, sample_buffer_sizes, 1,
-                      TimeDeltaToSbMediaTime(buffer->GetTimestamp()),
-                      type == DemuxerStream::VIDEO ? &video_info : NULL,
-                      drm_info.subsample_count > 0 ? &drm_info : NULL);
-#else   // SB_API_VERSION >= 4
-  SbPlayerWriteSample(player_, DemuxerStreamTypeToSbMediaType(type),
-                      buffer->GetData(), buffer->GetDataSize(),
-                      TimeDeltaToSbMediaTime(buffer->GetTimestamp()),
-                      type == DemuxerStream::VIDEO ? &video_info : NULL,
-                      drm_info.subsample_count > 0 ? &drm_info : NULL);
-#endif  // SB_API_VERSION >= 4
-}
-
-void StarboardPlayer::SetBounds(const gfx::Rect& rect) {
-  DCHECK(SbPlayerIsValid(player_));
-
-#if SB_API_VERSION >= 4
-  const int kZIndex = 0;
-  SbPlayerSetBounds(player_, kZIndex, rect.x(), rect.y(), rect.width(),
-                    rect.height());
-#else   // SB_API_VERSION >= 4
-  SbPlayerSetBounds(player_, rect.x(), rect.y(), rect.width(), rect.height());
-#endif  // SB_API_VERSION >= 4
-}
-
-void StarboardPlayer::PrepareForSeek() {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-  ++ticket_;
-#if SB_API_VERSION < 4
-  SbPlayerSetPause(player_, true);
-#else   // SB_API_VERSION < 4
-  SbPlayerSetPlaybackRate(player_, 0.f);
-#endif  // SB_API_VERSION < 4
-  seek_pending_ = true;
-}
-
-void StarboardPlayer::Seek(base::TimeDelta time) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  decoder_buffer_cache_.ClearAll();
-
-  if (state_ == kSuspended) {
-    DCHECK(!SbPlayerIsValid(player_));
-    preroll_timestamp_ = time;
-    return;
-  }
-
-  // If a seek happens during resuming, the pipeline will write samples from the
-  // seek target time again so resuming can be aborted.
-  if (state_ == kResuming) {
-    state_ = kPlaying;
-  }
-
-  DCHECK(SbPlayerIsValid(player_));
-
-  ++ticket_;
-  SbPlayerSeek(player_, TimeDeltaToSbMediaTime(time), ticket_);
-  seek_pending_ = false;
-#if SB_API_VERSION < 4
-  SbPlayerSetPause(player_, playback_rate_ == 0.0);
-#else  // SB_API_VERSION < 4
-  SbPlayerSetPlaybackRate(player_, playback_rate_);
-#endif  // SB_API_VERSION < 4
-}
-
-void StarboardPlayer::SetVolume(float volume) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  volume_ = volume;
-
-  if (state_ == kSuspended) {
-    DCHECK(!SbPlayerIsValid(player_));
-    return;
-  }
-
-  DCHECK(SbPlayerIsValid(player_));
-  SbPlayerSetVolume(player_, volume);
-}
-
-void StarboardPlayer::SetPlaybackRate(double playback_rate) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-  DCHECK(SbPlayerIsValid(player_));
-
-  playback_rate_ = playback_rate;
-
-  if (seek_pending_) {
-    return;
-  }
-
-#if SB_API_VERSION < 4
-  SbPlayerSetPause(player_, playback_rate == 0.0);
-#else   // SB_API_VERSION < 4
-  SbPlayerSetPlaybackRate(player_, playback_rate);
-#endif  // SB_API_VERSION < 4
-}
-
-void StarboardPlayer::GetInfo(uint32* video_frames_decoded,
-                              uint32* video_frames_dropped,
-                              base::TimeDelta* media_time) {
-  DCHECK(video_frames_decoded || video_frames_dropped || media_time);
-
-  base::AutoLock auto_lock(lock_);
-  if (state_ == kSuspended) {
-    DCHECK(!SbPlayerIsValid(player_));
-
-    if (video_frames_decoded) {
-      *video_frames_decoded = cached_video_frames_decoded_;
-    }
-    if (video_frames_dropped) {
-      *video_frames_dropped = cached_video_frames_dropped_;
-    }
-    if (media_time) {
-      *media_time = preroll_timestamp_;
-    }
-    return;
-  }
-
-  DCHECK(SbPlayerIsValid(player_));
-
-  SbPlayerInfo info;
-  SbPlayerGetInfo(player_, &info);
-  if (video_frames_decoded) {
-    *video_frames_decoded = info.total_video_frames;
-  }
-  if (video_frames_dropped) {
-    *video_frames_dropped = info.dropped_video_frames;
-  }
-  if (media_time) {
-    *media_time = SbMediaTimeToTimeDelta(info.current_media_pts);
-  }
-}
-
-void StarboardPlayer::Suspend() {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  // Check if the player is already suspended.
-  if (state_ == kSuspended) {
-    DCHECK(!SbPlayerIsValid(player_));
-    return;
-  }
-
-  DCHECK(SbPlayerIsValid(player_));
-
-#if SB_API_VERSION < 4
-  SbPlayerSetPause(player_, true);
-#else   // SB_API_VERSION < 4
-  SbPlayerSetPlaybackRate(player_, 0.0);
-#endif  // SB_API_VERSION < 4
-
-  base::AutoLock auto_lock(lock_);
-
-  state_ = kSuspended;
-
-  SbPlayerInfo info;
-  SbPlayerGetInfo(player_, &info);
-  cached_video_frames_decoded_ = info.total_video_frames;
-  cached_video_frames_dropped_ = info.dropped_video_frames;
-  preroll_timestamp_ = SbMediaTimeToTimeDelta(info.current_media_pts);
-
-  set_bounds_helper_->SetPlayer(NULL);
-  SbPlayerDestroy(player_);
-
-  player_ = kSbPlayerInvalid;
-}
-
-void StarboardPlayer::Resume() {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  // Check if the player is already resumed.
-  if (state_ != kSuspended) {
-    DCHECK(SbPlayerIsValid(player_));
-    return;
-  }
-
-  DCHECK(!SbPlayerIsValid(player_));
-
-  decoder_buffer_cache_.StartResuming();
-
-  CreatePlayer();
-
-  base::AutoLock auto_lock(lock_);
-  state_ = kResuming;
-}
-
-namespace {
-#if SB_API_VERSION >= 4
-ShellVideoFrameProvider::OutputMode ToVideoFrameProviderOutputMode(
-    SbPlayerOutputMode output_mode) {
-  switch (output_mode) {
-    case kSbPlayerOutputModeDecodeToTexture:
-      return ShellVideoFrameProvider::kOutputModeDecodeToTexture;
-    case kSbPlayerOutputModePunchOut:
-      return ShellVideoFrameProvider::kOutputModePunchOut;
-    case kSbPlayerOutputModeInvalid:
-      return ShellVideoFrameProvider::kOutputModeInvalid;
-  }
-
-  NOTREACHED();
-  return ShellVideoFrameProvider::kOutputModeInvalid;
-}
-#endif  // #if SB_API_VERSION >= 4
-}  // namespace
-
-void StarboardPlayer::CreatePlayer() {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  SbMediaAudioHeader audio_header;
-  // TODO: Make this work with non AAC audio.
-  audio_header.format_tag = 0x00ff;
-  audio_header.number_of_channels =
-      ChannelLayoutToChannelCount(audio_config_.channel_layout());
-  audio_header.samples_per_second = audio_config_.samples_per_second();
-  audio_header.average_bytes_per_second = 1;
-  audio_header.block_alignment = 4;
-  audio_header.bits_per_sample = audio_config_.bits_per_channel();
-#if SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
-  audio_header.audio_specific_config_size =
-      static_cast<uint16_t>(audio_config_.extra_data_size());
-  if (audio_header.audio_specific_config_size == 0) {
-    audio_header.audio_specific_config = NULL;
-  } else {
-    audio_header.audio_specific_config =
-        static_cast<int16_t*>(&audio_config_.extra_data()[0]);
-  }
-#else   // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
-  audio_header.audio_specific_config_size = static_cast<uint16_t>(
-      std::min(audio_config_.extra_data_size(),
-               sizeof(audio_header.audio_specific_config)));
-  if (audio_header.audio_specific_config_size > 0) {
-    SbMemoryCopy(audio_header.audio_specific_config, audio_config_.extra_data(),
-                 audio_header.audio_specific_config_size);
-  }
-#endif  // SB_API_VERSION >= SB_AUDIO_SPECIFIC_CONFIG_AS_POINTER
-
-  SbMediaAudioCodec audio_codec =
-      MediaAudioCodecToSbMediaAudioCodec(audio_config_.codec());
-  SbMediaVideoCodec video_codec =
-      MediaVideoCodecToSbMediaVideoCodec(video_config_.codec());
-
-#if SB_API_VERSION >= 4
-  DCHECK(SbPlayerOutputModeSupported(output_mode_, video_codec, drm_system_));
-#endif  // SB_API_VERSION >= 4
-
-  player_ = SbPlayerCreate(
-      window_, video_codec, audio_codec, SB_PLAYER_NO_DURATION, drm_system_,
-      &audio_header, &StarboardPlayer::DeallocateSampleCB,
-      &StarboardPlayer::DecoderStatusCB, &StarboardPlayer::PlayerStatusCB, this
-#if SB_API_VERSION >= 4
-      ,
-      output_mode_,
-      ShellMediaPlatform::Instance()->GetSbDecodeTargetGraphicsContextProvider()
-#elif SB_API_VERSION >= 3
-      ,
-      ShellMediaPlatform::Instance()->GetSbDecodeTargetProvider()  // provider
-#endif  // SB_API_VERSION >= 3
-          );
-
-#if SB_API_VERSION >= 4
-  if (output_mode_ == kSbPlayerOutputModeDecodeToTexture) {
-    // If the player is setup to decode to texture, then provide Cobalt with
-    // a method of querying that texture.
-    ShellMediaPlatform::Instance()
-        ->GetVideoFrameProvider()
-        ->SetGetCurrentSbDecodeTargetFunction(
-            base::Bind(&StarboardPlayer::GetCurrentSbDecodeTarget,
-                       base::Unretained(this)));
-  }
-  ShellMediaPlatform::Instance()->GetVideoFrameProvider()->SetOutputMode(
-      ToVideoFrameProviderOutputMode(output_mode_));
-#else   // SB_API_VERSION >= 4
-  ShellMediaPlatform::Instance()->GetVideoFrameProvider()->SetOutputMode(
-      ShellVideoFrameProvider::kOutputModePunchOut);
-#endif  // SB_API_VERSION >= 4
-  set_bounds_helper_->SetPlayer(this);
-}
-
-#if SB_API_VERSION >= 4
-SbDecodeTarget StarboardPlayer::GetCurrentSbDecodeTarget() {
-  return SbPlayerGetCurrentFrame(player_);
-}
-SbPlayerOutputMode StarboardPlayer::GetSbPlayerOutputMode() {
-  return output_mode_;
-}
-#endif  // SB_API_VERSION >= 4
-
-void StarboardPlayer::ClearDecoderBufferCache() {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  base::TimeDelta media_time;
-  GetInfo(NULL, NULL, &media_time);
-  decoder_buffer_cache_.ClearSegmentsBeforeMediaTime(media_time);
-
-  message_loop_->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&StarboardPlayer::ClearDecoderBufferCache, weak_this_),
-      base::TimeDelta::FromMilliseconds(
-          kClearDecoderCacheIntervalInMilliseconds));
-}
-
-void StarboardPlayer::OnDecoderStatus(SbPlayer player,
-                                      SbMediaType type,
-                                      SbPlayerDecoderState state,
-                                      int ticket) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  if (player_ != player || ticket != ticket_) {
-    return;
-  }
-
-  DCHECK_NE(state_, kSuspended);
-
-  switch (state) {
-    case kSbPlayerDecoderStateNeedsData:
-      break;
-    case kSbPlayerDecoderStateBufferFull:
-      DLOG(WARNING) << "kSbPlayerDecoderStateBufferFull has been deprecated.";
-      return;
-    case kSbPlayerDecoderStateDestroyed:
-      return;
-  }
-
-  if (state_ == kResuming) {
-    DemuxerStream::Type stream_type = SbMediaTypeToDemuxerStreamType(type);
-    if (decoder_buffer_cache_.GetBuffer(stream_type)) {
-      WriteBuffer(stream_type, decoder_buffer_cache_.GetBuffer(stream_type));
-      decoder_buffer_cache_.AdvanceToNextBuffer(stream_type);
-      return;
-    }
-    if (!decoder_buffer_cache_.GetBuffer(DemuxerStream::AUDIO) &&
-        !decoder_buffer_cache_.GetBuffer(DemuxerStream::VIDEO)) {
-      state_ = kPlaying;
-    }
-  }
-
-  host_->OnNeedData(SbMediaTypeToDemuxerStreamType(type));
-}
-
-void StarboardPlayer::OnPlayerStatus(SbPlayer player,
-                                     SbPlayerState state,
-                                     int ticket) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  if (player_ != player) {
-    return;
-  }
-
-  DCHECK_NE(state_, kSuspended);
-
-  if (ticket != SB_PLAYER_INITIAL_TICKET && ticket != ticket_) {
-    return;
-  }
-
-  if (state == kSbPlayerStateInitialized) {
-    if (ticket_ == SB_PLAYER_INITIAL_TICKET) {
-      ++ticket_;
-    }
-    SbPlayerSeek(player_, TimeDeltaToSbMediaTime(preroll_timestamp_), ticket_);
-    SetVolume(volume_);
-#if SB_API_VERSION < 4
-    SbPlayerSetPause(player_, playback_rate_ == 0.0);
-#else  // SB_API_VERSION < 4
-    SbPlayerSetPlaybackRate(player_, playback_rate_);
-#endif  // SB_API_VERSION < 4
-    return;
-  }
-  host_->OnPlayerStatus(state);
-}
-
-void StarboardPlayer::OnDeallocateSample(const void* sample_buffer) {
-  DCHECK(message_loop_->BelongsToCurrentThread());
-
-  DecodingBuffers::iterator iter = decoding_buffers_.find(sample_buffer);
-  DCHECK(iter != decoding_buffers_.end());
-  if (iter == decoding_buffers_.end()) {
-    LOG(ERROR) << "StarboardPlayer::OnDeallocateSample encounters unknown "
-               << "sample_buffer " << sample_buffer;
-    return;
-  }
-  --iter->second.second;
-  if (iter->second.second == 0) {
-    decoding_buffers_.erase(iter);
-  }
-}
-
-// static
-void StarboardPlayer::DecoderStatusCB(SbPlayer player,
-                                      void* context,
-                                      SbMediaType type,
-                                      SbPlayerDecoderState state,
-                                      int ticket) {
-  StarboardPlayer* helper = reinterpret_cast<StarboardPlayer*>(context);
-  helper->message_loop_->PostTask(
-      FROM_HERE, base::Bind(&StarboardPlayer::OnDecoderStatus,
-                            helper->weak_this_, player, type, state, ticket));
-}
-
-// static
-void StarboardPlayer::PlayerStatusCB(SbPlayer player,
-                                     void* context,
-                                     SbPlayerState state,
-                                     int ticket) {
-  StarboardPlayer* helper = reinterpret_cast<StarboardPlayer*>(context);
-  helper->message_loop_->PostTask(
-      FROM_HERE, base::Bind(&StarboardPlayer::OnPlayerStatus,
-                            helper->weak_this_, player, state, ticket));
-}
-
-// static
-void StarboardPlayer::DeallocateSampleCB(SbPlayer player,
-                                         void* context,
-                                         const void* sample_buffer) {
-  StarboardPlayer* helper = reinterpret_cast<StarboardPlayer*>(context);
-  helper->message_loop_->PostTask(
-      FROM_HERE, base::Bind(&StarboardPlayer::OnDeallocateSample,
-                            helper->weak_this_, sample_buffer));
-}
-
-#if SB_API_VERSION >= 4
-// static
-SbPlayerOutputMode StarboardPlayer::ComputeSbPlayerOutputMode(
-    SbMediaVideoCodec codec,
-    SbDrmSystem drm_system,
-    bool prefer_decode_to_texture) {
-  // Try to choose the output mode according to the passed in value of
-  // |prefer_decode_to_texture|.  If the preferred output mode is unavailable
-  // though, fallback to an output mode that is available.
-  SbPlayerOutputMode output_mode = kSbPlayerOutputModeInvalid;
-  if (SbPlayerOutputModeSupported(kSbPlayerOutputModePunchOut, codec,
-                                  drm_system)) {
-    output_mode = kSbPlayerOutputModePunchOut;
-  }
-  if ((prefer_decode_to_texture || output_mode == kSbPlayerOutputModeInvalid) &&
-      SbPlayerOutputModeSupported(kSbPlayerOutputModeDecodeToTexture, codec,
-                                  drm_system)) {
-    output_mode = kSbPlayerOutputModeDecodeToTexture;
-  }
-  CHECK_NE(kSbPlayerOutputModeInvalid, output_mode);
-
-  return output_mode;
-}
-#endif  // SB_API_VERSION >= 4
-
-}  // namespace media
diff --git a/src/media/base/starboard_player.h b/src/media/base/starboard_player.h
deleted file mode 100644
index 521065a..0000000
--- a/src/media/base/starboard_player.h
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef MEDIA_BASE_STARBOARD_PLAYER_H_
-#define MEDIA_BASE_STARBOARD_PLAYER_H_
-
-#include <map>
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop_proxy.h"
-#include "base/synchronization/lock.h"
-#include "base/time.h"
-#include "media/base/audio_decoder_config.h"
-#include "media/base/decoder_buffer.h"
-#include "media/base/decoder_buffer_cache.h"
-#include "media/base/demuxer_stream.h"
-#include "media/base/sbplayer_set_bounds_helper.h"
-#include "media/base/video_decoder_config.h"
-#include "starboard/media.h"
-#include "starboard/player.h"
-
-namespace media {
-
-// TODO: Add switch to disable caching
-class StarboardPlayer : public base::SupportsWeakPtr<StarboardPlayer> {
- public:
-  class Host {
-   public:
-    virtual void OnNeedData(DemuxerStream::Type type) = 0;
-    virtual void OnPlayerStatus(SbPlayerState state) = 0;
-
-   protected:
-    ~Host() {}
-  };
-
-  StarboardPlayer(const scoped_refptr<base::MessageLoopProxy>& message_loop,
-                  const AudioDecoderConfig& audio_config,
-                  const VideoDecoderConfig& video_config,
-                  SbWindow window,
-                  SbDrmSystem drm_system,
-                  Host* host,
-                  SbPlayerSetBoundsHelper* set_bounds_helper,
-                  bool prefer_decode_to_texture);
-  ~StarboardPlayer();
-
-  bool IsValid() const { return SbPlayerIsValid(player_); }
-
-  void UpdateVideoResolution(int frame_width, int frame_height);
-
-  void WriteBuffer(DemuxerStream::Type type,
-                   const scoped_refptr<DecoderBuffer>& buffer);
-  void SetBounds(const gfx::Rect& rect);
-
-  void PrepareForSeek();
-  void Seek(base::TimeDelta time);
-
-  void SetVolume(float volume);
-  void SetPlaybackRate(double playback_rate);
-  void GetInfo(uint32* video_frames_decoded,
-               uint32* video_frames_dropped,
-               base::TimeDelta* media_time);
-
-  void Suspend();
-  void Resume();
-
-#if SB_API_VERSION >= 4
-  SbDecodeTarget GetCurrentSbDecodeTarget();
-  SbPlayerOutputMode GetSbPlayerOutputMode();
-#endif  // SB_API_VERSION >= 4
-
- private:
-  enum State {
-    kPlaying,
-    kSuspended,
-    kResuming,
-  };
-
-  static const int64 kClearDecoderCacheIntervalInMilliseconds = 1000;
-
-  // A map from raw data pointer returned by DecoderBuffer::GetData() to the
-  // DecoderBuffer and a reference count.  The reference count indicates how
-  // many instances of the DecoderBuffer is currently being decoded in the
-  // pipeline.
-  typedef std::map<const void*, std::pair<scoped_refptr<DecoderBuffer>, int> >
-      DecodingBuffers;
-
-  void CreatePlayer();
-  void ClearDecoderBufferCache();
-
-  void OnDecoderStatus(SbPlayer player,
-                       SbMediaType type,
-                       SbPlayerDecoderState state,
-                       int ticket);
-  void OnPlayerStatus(SbPlayer player, SbPlayerState state, int ticket);
-  void OnDeallocateSample(const void* sample_buffer);
-
-  static void DecoderStatusCB(SbPlayer player,
-                              void* context,
-                              SbMediaType type,
-                              SbPlayerDecoderState state,
-                              int ticket);
-  static void PlayerStatusCB(SbPlayer player,
-                             void* context,
-                             SbPlayerState state,
-                             int ticket);
-  static void DeallocateSampleCB(SbPlayer player,
-                                 void* context,
-                                 const void* sample_buffer);
-
-#if SB_API_VERSION >= 4
-  // Returns the output mode that should be used for a video with the given
-  // specifications.
-  static SbPlayerOutputMode ComputeSbPlayerOutputMode(
-      SbMediaVideoCodec codec,
-      SbDrmSystem drm_system,
-      bool prefer_decode_to_texture);
-#endif  // SB_API_VERSION >= 4
-
-  // The following variables are initialized in the ctor and never changed.
-  const scoped_refptr<base::MessageLoopProxy> message_loop_;
-  AudioDecoderConfig audio_config_;
-  VideoDecoderConfig video_config_;
-  const SbWindow window_;
-  const SbDrmSystem drm_system_;
-  Host* const host_;
-  SbPlayerSetBoundsHelper* const set_bounds_helper_;
-  const base::WeakPtr<StarboardPlayer> weak_this_;
-
-  // The following variables are only changed or accessed from the
-  // |message_loop_|.
-  int frame_width_;
-  int frame_height_;
-  DecodingBuffers decoding_buffers_;
-  int ticket_;
-  float volume_;
-  double playback_rate_;
-  bool seek_pending_;
-  DecoderBufferCache decoder_buffer_cache_;
-
-  // The following variables can be accessed from GetInfo(), which can be called
-  // from any threads.  So some of their usages have to be guarded by |lock_|.
-  base::Lock lock_;
-  State state_;
-  SbPlayer player_;
-  uint32 cached_video_frames_decoded_;
-  uint32 cached_video_frames_dropped_;
-  base::TimeDelta preroll_timestamp_;
-
-#if SB_API_VERSION >= 4
-  // Keep track of the output mode we are supposed to output to.
-  SbPlayerOutputMode output_mode_;
-#endif  // SB_API_VERSION >= 4
-};
-
-}  // namespace media
-
-#endif  // MEDIA_BASE_STARBOARD_PLAYER_H_
diff --git a/src/media/base/starboard_utils.cc b/src/media/base/starboard_utils.cc
deleted file mode 100644
index c66d3a6..0000000
--- a/src/media/base/starboard_utils.cc
+++ /dev/null
@@ -1,281 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "media/base/starboard_utils.h"
-
-#include "base/logging.h"
-
-using base::Time;
-using base::TimeDelta;
-
-namespace media {
-
-SbMediaAudioCodec MediaAudioCodecToSbMediaAudioCodec(AudioCodec codec) {
-  if (codec == kCodecAAC) {
-    return kSbMediaAudioCodecAac;
-  } else if (codec == kCodecVorbis) {
-    return kSbMediaAudioCodecVorbis;
-  } else if (codec == kCodecOpus) {
-    return kSbMediaAudioCodecOpus;
-  }
-  DLOG(ERROR) << "Unsupported audio codec " << codec;
-  return kSbMediaAudioCodecNone;
-}
-
-SbMediaVideoCodec MediaVideoCodecToSbMediaVideoCodec(VideoCodec codec) {
-  if (codec == kCodecH264) {
-    return kSbMediaVideoCodecH264;
-  } else if (codec == kCodecVC1) {
-    return kSbMediaVideoCodecVc1;
-  } else if (codec == kCodecMPEG2) {
-    return kSbMediaVideoCodecMpeg2;
-  } else if (codec == kCodecTheora) {
-    return kSbMediaVideoCodecTheora;
-  } else if (codec == kCodecVP8) {
-    return kSbMediaVideoCodecVp8;
-  } else if (codec == kCodecVP9) {
-    return kSbMediaVideoCodecVp9;
-  }
-  DLOG(ERROR) << "Unsupported video codec " << codec;
-  return kSbMediaVideoCodecNone;
-}
-
-TimeDelta SbMediaTimeToTimeDelta(SbMediaTime timestamp) {
-  return TimeDelta::FromMicroseconds(timestamp * Time::kMicrosecondsPerSecond /
-                                     kSbMediaTimeSecond);
-}
-
-SbMediaTime TimeDeltaToSbMediaTime(TimeDelta timedelta) {
-  return timedelta.InMicroseconds() * kSbMediaTimeSecond /
-         Time::kMicrosecondsPerSecond;
-}
-
-DemuxerStream::Type SbMediaTypeToDemuxerStreamType(SbMediaType type) {
-  if (type == kSbMediaTypeAudio) {
-    return DemuxerStream::AUDIO;
-  }
-  DCHECK_EQ(type, kSbMediaTypeVideo);
-  return DemuxerStream::VIDEO;
-}
-
-SbMediaType DemuxerStreamTypeToSbMediaType(DemuxerStream::Type type) {
-  if (type == DemuxerStream::AUDIO) {
-    return kSbMediaTypeAudio;
-  }
-  DCHECK_EQ(type, DemuxerStream::VIDEO);
-  return kSbMediaTypeVideo;
-}
-
-void FillDrmSampleInfo(const scoped_refptr<DecoderBuffer>& buffer,
-                       SbDrmSampleInfo* drm_info,
-                       SbDrmSubSampleMapping* subsample_mapping) {
-  DCHECK(drm_info);
-  DCHECK(subsample_mapping);
-
-  const DecryptConfig* config = buffer->GetDecryptConfig();
-  if (!config || config->iv().empty() || config->key_id().empty()) {
-    drm_info->initialization_vector_size = 0;
-    drm_info->identifier_size = 0;
-    drm_info->subsample_count = 0;
-    drm_info->subsample_mapping = NULL;
-    return;
-  }
-
-  DCHECK_LE(config->iv().size(), sizeof(drm_info->initialization_vector));
-  DCHECK_LE(config->key_id().size(), sizeof(drm_info->identifier));
-
-  if (config->iv().size() > sizeof(drm_info->initialization_vector) ||
-      config->key_id().size() > sizeof(drm_info->identifier)) {
-    drm_info->initialization_vector_size = 0;
-    drm_info->identifier_size = 0;
-    drm_info->subsample_count = 0;
-    drm_info->subsample_mapping = NULL;
-    return;
-  }
-
-  memcpy(drm_info->initialization_vector, &config->iv()[0],
-         config->iv().size());
-  drm_info->initialization_vector_size = config->iv().size();
-  memcpy(drm_info->identifier, &config->key_id()[0], config->key_id().size());
-  drm_info->identifier_size = config->key_id().size();
-  drm_info->subsample_count = config->subsamples().size();
-
-  if (drm_info->subsample_count > 0) {
-    COMPILE_ASSERT(sizeof(SbDrmSubSampleMapping) == sizeof(SubsampleEntry),
-                   SubSampleEntrySizesMatch);
-    drm_info->subsample_mapping =
-        reinterpret_cast<const SbDrmSubSampleMapping*>(
-            &config->subsamples()[0]);
-  } else {
-    drm_info->subsample_count = 1;
-    drm_info->subsample_mapping = subsample_mapping;
-    subsample_mapping->clear_byte_count = 0;
-    subsample_mapping->encrypted_byte_count = buffer->GetDataSize();
-  }
-}
-
-#if SB_API_VERSION >= 4
-// Ensure that the enums in starboard/media.h match enums in gfx::ColorSpace.
-#define ENUM_EQ(a, b) \
-  COMPILE_ASSERT(static_cast<int>(a) == static_cast<int>(b), mismatching_enums)
-
-// Ensure PrimaryId enums convert correctly.
-ENUM_EQ(kSbMediaPrimaryIdReserved0, gfx::ColorSpace::kPrimaryIdReserved0);
-ENUM_EQ(kSbMediaPrimaryIdBt709, gfx::ColorSpace::kPrimaryIdBt709);
-ENUM_EQ(kSbMediaPrimaryIdUnspecified, gfx::ColorSpace::kPrimaryIdUnspecified);
-ENUM_EQ(kSbMediaPrimaryIdReserved, gfx::ColorSpace::kPrimaryIdReserved);
-ENUM_EQ(kSbMediaPrimaryIdBt470M, gfx::ColorSpace::kPrimaryIdBt470M);
-ENUM_EQ(kSbMediaPrimaryIdBt470Bg, gfx::ColorSpace::kPrimaryIdBt470Bg);
-ENUM_EQ(kSbMediaPrimaryIdSmpte170M, gfx::ColorSpace::kPrimaryIdSmpte170M);
-ENUM_EQ(kSbMediaPrimaryIdSmpte240M, gfx::ColorSpace::kPrimaryIdSmpte240M);
-ENUM_EQ(kSbMediaPrimaryIdFilm, gfx::ColorSpace::kPrimaryIdFilm);
-ENUM_EQ(kSbMediaPrimaryIdBt2020, gfx::ColorSpace::kPrimaryIdBt2020);
-ENUM_EQ(kSbMediaPrimaryIdSmpteSt4281, gfx::ColorSpace::kPrimaryIdSmpteSt4281);
-ENUM_EQ(kSbMediaPrimaryIdSmpteSt4312, gfx::ColorSpace::kPrimaryIdSmpteSt4312);
-ENUM_EQ(kSbMediaPrimaryIdSmpteSt4321, gfx::ColorSpace::kPrimaryIdSmpteSt4321);
-ENUM_EQ(kSbMediaPrimaryIdLastStandardValue,
-        gfx::ColorSpace::kPrimaryIdLastStandardValue);
-ENUM_EQ(kSbMediaPrimaryIdUnknown, gfx::ColorSpace::kPrimaryIdUnknown);
-ENUM_EQ(kSbMediaPrimaryIdXyzD50, gfx::ColorSpace::kPrimaryIdXyzD50);
-ENUM_EQ(kSbMediaPrimaryIdCustom, gfx::ColorSpace::kPrimaryIdCustom);
-ENUM_EQ(kSbMediaPrimaryIdLast, gfx::ColorSpace::kPrimaryIdLast);
-
-// Ensure TransferId enums convert correctly.
-ENUM_EQ(kSbMediaTransferIdReserved0, gfx::ColorSpace::kTransferIdReserved0);
-ENUM_EQ(kSbMediaTransferIdBt709, gfx::ColorSpace::kTransferIdBt709);
-ENUM_EQ(kSbMediaTransferIdUnspecified, gfx::ColorSpace::kTransferIdUnspecified);
-ENUM_EQ(kSbMediaTransferIdReserved, gfx::ColorSpace::kTransferIdReserved);
-ENUM_EQ(kSbMediaTransferIdGamma22, gfx::ColorSpace::kTransferIdGamma22);
-ENUM_EQ(kSbMediaTransferIdGamma28, gfx::ColorSpace::kTransferIdGamma28);
-ENUM_EQ(kSbMediaTransferIdSmpte170M, gfx::ColorSpace::kTransferIdSmpte170M);
-ENUM_EQ(kSbMediaTransferIdSmpte240M, gfx::ColorSpace::kTransferIdSmpte240M);
-ENUM_EQ(kSbMediaTransferIdLinear, gfx::ColorSpace::kTransferIdLinear);
-ENUM_EQ(kSbMediaTransferIdLog, gfx::ColorSpace::kTransferIdLog);
-ENUM_EQ(kSbMediaTransferIdLogSqrt, gfx::ColorSpace::kTransferIdLogSqrt);
-ENUM_EQ(kSbMediaTransferIdIec6196624, gfx::ColorSpace::kTransferIdIec6196624);
-ENUM_EQ(kSbMediaTransferIdBt1361Ecg, gfx::ColorSpace::kTransferIdBt1361Ecg);
-ENUM_EQ(kSbMediaTransferIdIec6196621, gfx::ColorSpace::kTransferIdIec6196621);
-ENUM_EQ(kSbMediaTransferId10BitBt2020, gfx::ColorSpace::kTransferId10BitBt2020);
-ENUM_EQ(kSbMediaTransferId12BitBt2020, gfx::ColorSpace::kTransferId12BitBt2020);
-ENUM_EQ(kSbMediaTransferIdSmpteSt2084, gfx::ColorSpace::kTransferIdSmpteSt2084);
-ENUM_EQ(kSbMediaTransferIdSmpteSt4281, gfx::ColorSpace::kTransferIdSmpteSt4281);
-ENUM_EQ(kSbMediaTransferIdAribStdB67, gfx::ColorSpace::kTransferIdAribStdB67);
-ENUM_EQ(kSbMediaTransferIdLastStandardValue,
-        gfx::ColorSpace::kTransferIdLastStandardValue);
-ENUM_EQ(kSbMediaTransferIdUnknown, gfx::ColorSpace::kTransferIdUnknown);
-ENUM_EQ(kSbMediaTransferIdGamma24, gfx::ColorSpace::kTransferIdGamma24);
-ENUM_EQ(kSbMediaTransferIdSmpteSt2084NonHdr,
-        gfx::ColorSpace::kTransferIdSmpteSt2084NonHdr);
-ENUM_EQ(kSbMediaTransferIdCustom, gfx::ColorSpace::kTransferIdCustom);
-ENUM_EQ(kSbMediaTransferIdLast, gfx::ColorSpace::kTransferIdLast);
-
-// Ensure MatrixId enums convert correctly.
-ENUM_EQ(kSbMediaMatrixIdRgb, gfx::ColorSpace::kMatrixIdRgb);
-ENUM_EQ(kSbMediaMatrixIdBt709, gfx::ColorSpace::kMatrixIdBt709);
-ENUM_EQ(kSbMediaMatrixIdUnspecified, gfx::ColorSpace::kMatrixIdUnspecified);
-ENUM_EQ(kSbMediaMatrixIdReserved, gfx::ColorSpace::kMatrixIdReserved);
-ENUM_EQ(kSbMediaMatrixIdFcc, gfx::ColorSpace::kMatrixIdFcc);
-ENUM_EQ(kSbMediaMatrixIdBt470Bg, gfx::ColorSpace::kMatrixIdBt470Bg);
-ENUM_EQ(kSbMediaMatrixIdSmpte170M, gfx::ColorSpace::kMatrixIdSmpte170M);
-ENUM_EQ(kSbMediaMatrixIdSmpte240M, gfx::ColorSpace::kMatrixIdSmpte240M);
-ENUM_EQ(kSbMediaMatrixIdYCgCo, gfx::ColorSpace::kMatrixIdYCgCo);
-ENUM_EQ(kSbMediaMatrixIdBt2020NonconstantLuminance,
-        gfx::ColorSpace::kMatrixIdBt2020NonconstantLuminance);
-ENUM_EQ(kSbMediaMatrixIdBt2020ConstantLuminance,
-        gfx::ColorSpace::kMatrixIdBt2020ConstantLuminance);
-ENUM_EQ(kSbMediaMatrixIdYDzDx, gfx::ColorSpace::kMatrixIdYDzDx);
-ENUM_EQ(kSbMediaMatrixIdLastStandardValue,
-        gfx::ColorSpace::kMatrixIdLastStandardValue);
-ENUM_EQ(kSbMediaMatrixIdUnknown, gfx::ColorSpace::kMatrixIdUnknown);
-ENUM_EQ(kSbMediaMatrixIdLast, gfx::ColorSpace::kMatrixIdLast);
-
-// Ensure RangeId enums convert correctly.
-ENUM_EQ(kSbMediaRangeIdUnspecified, gfx::ColorSpace::kRangeIdUnspecified);
-ENUM_EQ(kSbMediaRangeIdLimited, gfx::ColorSpace::kRangeIdLimited);
-ENUM_EQ(kSbMediaRangeIdFull, gfx::ColorSpace::kRangeIdFull);
-ENUM_EQ(kSbMediaRangeIdDerived, gfx::ColorSpace::kRangeIdDerived);
-ENUM_EQ(kSbMediaRangeIdLast, gfx::ColorSpace::kRangeIdLast);
-
-SbMediaColorMetadata MediaToSbMediaColorMetadata(
-    const WebMColorMetadata& webm_color_metadata) {
-  SbMediaColorMetadata sb_media_color_metadata;
-
-  // Copy the other color metadata below.
-  sb_media_color_metadata.bits_per_channel = webm_color_metadata.BitsPerChannel;
-  sb_media_color_metadata.chroma_subsampling_horizontal =
-      webm_color_metadata.ChromaSubsamplingHorz;
-  sb_media_color_metadata.chroma_subsampling_vertical =
-      webm_color_metadata.ChromaSubsamplingVert;
-  sb_media_color_metadata.cb_subsampling_horizontal =
-      webm_color_metadata.CbSubsamplingHorz;
-  sb_media_color_metadata.cb_subsampling_vertical =
-      webm_color_metadata.CbSubsamplingVert;
-  sb_media_color_metadata.chroma_siting_horizontal =
-      webm_color_metadata.ChromaSitingHorz;
-  sb_media_color_metadata.chroma_siting_vertical =
-      webm_color_metadata.ChromaSitingVert;
-
-  // Copy the HDR Metadata below.
-  SbMediaMasteringMetadata sb_media_mastering_metadata;
-  HDRMetadata hdr_metadata = webm_color_metadata.hdr_metadata;
-  MasteringMetadata mastering_metadata = hdr_metadata.mastering_metadata;
-
-  sb_media_mastering_metadata.primary_r_chromaticity_x =
-      mastering_metadata.primary_r_chromaticity_x;
-  sb_media_mastering_metadata.primary_r_chromaticity_y =
-      mastering_metadata.primary_r_chromaticity_y;
-
-  sb_media_mastering_metadata.primary_g_chromaticity_x =
-      mastering_metadata.primary_g_chromaticity_x;
-  sb_media_mastering_metadata.primary_g_chromaticity_y =
-      mastering_metadata.primary_g_chromaticity_y;
-
-  sb_media_mastering_metadata.primary_b_chromaticity_x =
-      mastering_metadata.primary_b_chromaticity_x;
-  sb_media_mastering_metadata.primary_b_chromaticity_y =
-      mastering_metadata.primary_b_chromaticity_y;
-
-  sb_media_mastering_metadata.white_point_chromaticity_x =
-      mastering_metadata.white_point_chromaticity_x;
-  sb_media_mastering_metadata.white_point_chromaticity_y =
-      mastering_metadata.white_point_chromaticity_y;
-
-  sb_media_mastering_metadata.luminance_max = mastering_metadata.luminance_max;
-  sb_media_mastering_metadata.luminance_min = mastering_metadata.luminance_min;
-
-  sb_media_color_metadata.mastering_metadata = sb_media_mastering_metadata;
-  sb_media_color_metadata.max_cll = hdr_metadata.max_cll;
-  sb_media_color_metadata.max_fall = hdr_metadata.max_fall;
-
-  // Copy the color space below.
-  gfx::ColorSpace color_space = webm_color_metadata.color_space;
-  sb_media_color_metadata.primaries =
-      static_cast<SbMediaPrimaryId>(color_space.primaries());
-  sb_media_color_metadata.transfer =
-      static_cast<SbMediaTransferId>(color_space.transfer());
-  sb_media_color_metadata.matrix =
-      static_cast<SbMediaMatrixId>(color_space.matrix());
-  sb_media_color_metadata.range =
-      static_cast<SbMediaRangeId>(color_space.range());
-  if (sb_media_color_metadata.primaries == kSbMediaPrimaryIdCustom) {
-    const float* custom_primary_matrix = color_space.custom_primary_matrix();
-    SbMemoryCopy(sb_media_color_metadata.custom_primary_matrix,
-                 custom_primary_matrix, sizeof(custom_primary_matrix));
-  }
-
-  return sb_media_color_metadata;
-}
-#endif  // SB_API_VERSION >= 4
-
-}  // namespace media
diff --git a/src/media/base/starboard_utils.h b/src/media/base/starboard_utils.h
deleted file mode 100644
index e5112d1..0000000
--- a/src/media/base/starboard_utils.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef MEDIA_BASE_STARBOARD_UTILS_H_
-#define MEDIA_BASE_STARBOARD_UTILS_H_
-
-#include "media/base/audio_decoder_config.h"
-#include "media/base/decoder_buffer.h"
-#include "media/base/demuxer_stream.h"
-#include "media/base/video_decoder_config.h"
-#include "starboard/drm.h"
-#include "starboard/media.h"
-
-namespace media {
-
-SbMediaAudioCodec MediaAudioCodecToSbMediaAudioCodec(AudioCodec codec);
-SbMediaVideoCodec MediaVideoCodecToSbMediaVideoCodec(VideoCodec codec);
-
-base::TimeDelta SbMediaTimeToTimeDelta(SbMediaTime timestamp);
-SbMediaTime TimeDeltaToSbMediaTime(base::TimeDelta timedelta);
-
-DemuxerStream::Type SbMediaTypeToDemuxerStreamType(SbMediaType type);
-SbMediaType DemuxerStreamTypeToSbMediaType(DemuxerStream::Type type);
-
-void FillDrmSampleInfo(const scoped_refptr<DecoderBuffer>& buffer,
-                       SbDrmSampleInfo* drm_info,
-                       SbDrmSubSampleMapping* subsample_mapping);
-
-#if SB_API_VERSION >= 4
-SbMediaColorMetadata MediaToSbMediaColorMetadata(
-    const WebMColorMetadata& webm_color_metadata);
-#endif
-
-}  // namespace media
-
-#endif  // MEDIA_BASE_STARBOARD_UTILS_H_
diff --git a/src/media/crypto/shell_decryptor_factory.cc b/src/media/crypto/shell_decryptor_factory.cc
index 5fc5a59..ceaf4d2 100644
--- a/src/media/crypto/shell_decryptor_factory.cc
+++ b/src/media/crypto/shell_decryptor_factory.cc
@@ -16,39 +16,8 @@
 
 #include "media/crypto/shell_decryptor_factory.h"
 
-#if defined(OS_STARBOARD)
-#include "media/crypto/starboard_decryptor.h"
-#include "starboard/configuration.h"
-#include "starboard/drm.h"
-#include "starboard/media.h"
-#endif  // defined(OS_STARBOARD)
-
 namespace media {
 
-#if defined(OS_STARBOARD)
-#if SB_CAN(MEDIA_USE_STARBOARD_PIPELINE)
-
-#define USE_STARBOARD_DECRYPTOR 1
-
-#endif  // SB_CAN(MEDIA_USE_STARBOARD_PIPELINE)
-#endif  // defined(OS_STARBOARD)
-
-#if defined(USE_STARBOARD_DECRYPTOR)
-// static
-bool ShellDecryptorFactory::Supports(const std::string& key_system) {
-  // TODO: Hook up with codecs.
-  return SbMediaIsSupported(kSbMediaVideoCodecNone, kSbMediaAudioCodecNone,
-                            key_system.c_str());
-}
-
-// static
-Decryptor* ShellDecryptorFactory::Create(const std::string& key_system,
-                                         DecryptorClient* client) {
-  return new StarboardDecryptor(key_system.c_str(), client);
-}
-
-#else  // defined(USE_STARBOARD_DECRYPTOR)
-
 // static
 ShellDecryptorFactory::DecryptorRegistry ShellDecryptorFactory::registry_;
 
@@ -74,6 +43,4 @@
   registry_[key_system] = create_cb;
 }
 
-#endif  // defined(USE_STARBOARD_DECRYPTOR)
-
 }  // namespace media
diff --git a/src/media/crypto/starboard_decryptor.cc b/src/media/crypto/starboard_decryptor.cc
deleted file mode 100644
index 9ee01d0..0000000
--- a/src/media/crypto/starboard_decryptor.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Definitions that allow for DRM support, common between Player and Decoder
-// interfaces.
-
-#include "media/crypto/starboard_decryptor.h"
-
-#include "base/logging.h"
-#include "media/base/decrypt_config.h"
-
-namespace media {
-
-namespace {
-
-std::string ToString(const void* buffer, int size) {
-  const char* char_buffer = reinterpret_cast<const char*>(buffer);
-  return std::string(char_buffer, char_buffer + size);
-}
-
-}  // namespace
-
-StarboardDecryptor::StarboardDecryptor(const char* key_system,
-                                       DecryptorClient* decryptor_client)
-    : client_(decryptor_client) {
-  drm_system_ =
-      SbDrmCreateSystem(key_system, this, KeyRequestFunc, KeyAddedFunc);
-}
-
-StarboardDecryptor::~StarboardDecryptor() {
-  SbDrmDestroySystem(drm_system_);
-}
-
-bool StarboardDecryptor::GenerateKeyRequest(const std::string& key_system,
-                                            const std::string& type,
-                                            const uint8_t* init_data,
-                                            int init_data_length) {
-  if (drm_system_ == kSbDrmSystemInvalid) {
-    return false;
-  }
-  if (key_system_.empty()) {
-    key_system_ = key_system;
-  }
-  DCHECK_EQ(key_system_, key_system);
-  SbDrmGenerateSessionUpdateRequest(drm_system_,
-#if SB_API_VERSION >= 4
-                                    0,  // No need to distinguish between
-                                        // callbacks in EME 0.1b implementation.
-#endif                                  // SB_API_VERSION >= 4
-                                    type.c_str(), init_data, init_data_length);
-  return true;
-}
-
-void StarboardDecryptor::AddKey(const std::string& key_system,
-                                const uint8_t* key,
-                                int key_length,
-                                const uint8_t* init_data,
-                                int init_data_length,
-                                const std::string& session_id) {
-  SbDrmUpdateSession(drm_system_, key, key_length, session_id.c_str(),
-                     session_id.size());
-}
-
-void StarboardDecryptor::CancelKeyRequest(const std::string& key_system,
-                                          const std::string& session_id) {
-  SbDrmCloseSession(drm_system_, session_id.c_str(), session_id.size());
-}
-
-void StarboardDecryptor::RegisterKeyAddedCB(StreamType stream_type,
-                                            const KeyAddedCB& key_added_cb) {
-  NOTREACHED();
-}
-
-void StarboardDecryptor::Decrypt(StreamType stream_type,
-                                 const scoped_refptr<DecoderBuffer>& encrypted,
-                                 const DecryptCB& decrypt_cb) {
-  decrypt_cb.Run(kSuccess, encrypted);
-}
-
-void StarboardDecryptor::CancelDecrypt(StreamType stream_type) {
-  // no-op
-}
-
-void StarboardDecryptor::InitializeAudioDecoder(
-    scoped_ptr<AudioDecoderConfig> config,
-    const DecoderInitCB& init_cb) {
-  // StarboardDecryptor does not support audio decoding.
-  // This puts us in "decrypt only" mode.
-  // Decoding is handled by the system default decoders.
-  init_cb.Run(false);
-}
-
-void StarboardDecryptor::InitializeVideoDecoder(
-    scoped_ptr<VideoDecoderConfig> config,
-    const DecoderInitCB& init_cb) {
-  // StarboardDecryptor does not support video decoding.
-  // This puts us in "decrypt only" mode.
-  // Decoding is handled by the system default decoders.
-  init_cb.Run(false);
-}
-
-void StarboardDecryptor::DecryptAndDecodeAudio(
-    const scoped_refptr<DecoderBuffer>& encrypted,
-    const AudioDecodeCB& audio_decode_cb) {
-  NOTREACHED();
-}
-
-void StarboardDecryptor::DecryptAndDecodeVideo(
-    const scoped_refptr<DecoderBuffer>& encrypted,
-    const VideoDecodeCB& video_decode_cb) {
-  NOTREACHED();
-}
-
-void StarboardDecryptor::ResetDecoder(StreamType stream_type) {
-  NOTREACHED();
-}
-
-void StarboardDecryptor::DeinitializeDecoder(StreamType stream_type) {
-  NOTREACHED();
-}
-
-void StarboardDecryptor::OnKeyRequest(const void* session_id,
-                                      int session_id_size,
-                                      const void* content,
-                                      int content_size,
-                                      const char* url) {
-  if (session_id) {
-    client_->KeyMessage(key_system_, ToString(session_id, session_id_size),
-                        ToString(content, content_size), url);
-  } else {
-    client_->KeyError(key_system_, "", Decryptor::kUnknownError, 0);
-  }
-}
-
-void StarboardDecryptor::OnKeyAdded(const void* session_id,
-                                    int session_id_length,
-                                    bool succeeded) {
-  std::string session(
-      reinterpret_cast<const char*>(session_id),
-      reinterpret_cast<const char*>(session_id) + session_id_length);
-
-  if (succeeded) {
-    client_->KeyAdded(key_system_, session);
-  } else {
-    client_->KeyError(key_system_, session, Decryptor::kUnknownError, 0);
-  }
-}
-
-// static
-void StarboardDecryptor::KeyRequestFunc(SbDrmSystem drm_system,
-                                        void* context,
-#if SB_API_VERSION >= 4
-                                        int /*ticket*/,
-#endif  // SB_API_VERSION >= 4
-                                        const void* session_id,
-                                        int session_id_size,
-                                        const void* content,
-                                        int content_size,
-                                        const char* url) {
-  DCHECK(context);
-  StarboardDecryptor* decryptor =
-      reinterpret_cast<StarboardDecryptor*>(context);
-  DCHECK_EQ(drm_system, decryptor->drm_system_);
-
-  decryptor->OnKeyRequest(session_id, session_id_size, content, content_size,
-                          url);
-}
-
-// static
-void StarboardDecryptor::KeyAddedFunc(SbDrmSystem drm_system,
-                                      void* context,
-                                      const void* session_id,
-                                      int session_id_length,
-                                      bool succeeded) {
-  DCHECK(context);
-  StarboardDecryptor* decryptor =
-      reinterpret_cast<StarboardDecryptor*>(context);
-  DCHECK_EQ(drm_system, decryptor->drm_system_);
-  decryptor->OnKeyAdded(session_id, session_id_length, succeeded);
-}
-
-}  // namespace media
diff --git a/src/media/crypto/starboard_decryptor.h b/src/media/crypto/starboard_decryptor.h
deleted file mode 100644
index a2ffc17..0000000
--- a/src/media/crypto/starboard_decryptor.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Definitions that allow for DRM support, common between Player and Decoder
-// interfaces.
-
-#ifndef MEDIA_CRYPTO_STARBOARD_DECRYPTOR_H_
-#define MEDIA_CRYPTO_STARBOARD_DECRYPTOR_H_
-
-#include "build/build_config.h"
-
-#if !defined(OS_STARBOARD)
-#error "This class only works in Starboard!"
-#endif  // !defined(OS_STARBOARD)
-
-#include <set>
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "media/base/decryptor.h"
-#include "media/base/decryptor_client.h"
-#include "starboard/drm.h"
-
-namespace media {
-
-// This class implements the Decryptor interface based on Starboard DRM
-// functions provided in drm.h and media.h.
-class StarboardDecryptor : public Decryptor {
- public:
-  StarboardDecryptor(const char* key_system, DecryptorClient* decryptor_client);
-  ~StarboardDecryptor() OVERRIDE;
-
-  SbDrmSystem drm_system() { return drm_system_; }
-
-  // Decryptor implementation.
-  bool GenerateKeyRequest(const std::string& key_system,
-                          const std::string& type,
-                          const uint8_t* init_data,
-                          int init_data_length) OVERRIDE;
-  void AddKey(const std::string& key_system,
-              const uint8_t* key,
-              int key_length,
-              const uint8_t* init_data,
-              int init_data_length,
-              const std::string& session_id) OVERRIDE;
-  void CancelKeyRequest(const std::string& key_system,
-                        const std::string& session_id) OVERRIDE;
-  void RegisterKeyAddedCB(StreamType stream_type,
-                          const KeyAddedCB& key_added_cb) OVERRIDE;
-  void Decrypt(StreamType stream_type,
-               const scoped_refptr<DecoderBuffer>& encrypted,
-               const DecryptCB& decrypt_cb) OVERRIDE;
-  void CancelDecrypt(StreamType stream_type) OVERRIDE;
-  void InitializeAudioDecoder(scoped_ptr<AudioDecoderConfig> config,
-                              const DecoderInitCB& init_cb) OVERRIDE;
-  void InitializeVideoDecoder(scoped_ptr<VideoDecoderConfig> config,
-                              const DecoderInitCB& init_cb) OVERRIDE;
-  void DecryptAndDecodeAudio(const scoped_refptr<DecoderBuffer>& encrypted,
-                             const AudioDecodeCB& audio_decode_cb) OVERRIDE;
-  void DecryptAndDecodeVideo(const scoped_refptr<DecoderBuffer>& encrypted,
-                             const VideoDecodeCB& video_decode_cb) OVERRIDE;
-  void ResetDecoder(StreamType stream_type) OVERRIDE;
-  void DeinitializeDecoder(StreamType stream_type) OVERRIDE;
-
- private:
-  void OnKeyRequest(const void* session_id,
-                    int session_id_size,
-                    const void* content,
-                    int content_size,
-                    const char* url);
-  void OnKeyAdded(const void* session_id,
-                  int session_id_length,
-                  bool succeeded);
-
-  static void KeyRequestFunc(SbDrmSystem drm_system,
-                             void* context,
-#if SB_API_VERSION >= 4
-                             int ticket,
-#endif  // SB_API_VERSION >= 4
-                             const void* session_id,
-                             int session_id_size,
-                             const void* content,
-                             int content_size,
-                             const char* url);
-  static void KeyAddedFunc(SbDrmSystem drm_system,
-                           void* context,
-                           const void* session_id,
-                           int session_id_length,
-                           bool succeeded);
-
-  // DecryptorClient through which key events are fired.
-  // Calls to the client are both cheap and thread-safe.
-  DecryptorClient* client_;
-  SbDrmSystem drm_system_;
-  std::string key_system_;
-
-  std::set<std::string> keys_;
-
-  DISALLOW_COPY_AND_ASSIGN(StarboardDecryptor);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_CRYPTO_STARBOARD_DECRYPTOR_H_
diff --git a/src/media/filters/shell_audio_renderer_starboard.cc b/src/media/filters/shell_audio_renderer_starboard.cc
deleted file mode 100644
index 4c9dcea..0000000
--- a/src/media/filters/shell_audio_renderer_starboard.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-/*

- * Copyright 2017 Google Inc. All Rights Reserved.

- *

- * Licensed under the Apache License, Version 2.0 (the "License");

- * you may not use this file except in compliance with the License.

- * You may obtain a copy of the License at

- *

- *     http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing, software

- * distributed under the License is distributed on an "AS IS" BASIS,

- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

- * See the License for the specific language governing permissions and

- * limitations under the License.

- */

-

-#include "media/filters/shell_audio_renderer.h"

-

-namespace media {

-

-// static

-ShellAudioRenderer* ShellAudioRenderer::Create(

-    media::AudioRendererSink* sink,

-    const SetDecryptorReadyCB& set_decryptor_ready_cb,

-    const scoped_refptr<base::MessageLoopProxy>& message_loop) {

-  return NULL;

-}

-

-}  // namespace media

diff --git a/src/media/media.gyp b/src/media/media.gyp
index 5757809..7aff606 100644
--- a/src/media/media.gyp
+++ b/src/media/media.gyp
@@ -575,17 +575,6 @@
             ['exclude', 'video/capture/fake_video_capture_device'],
           ],
           'conditions': [
-            ['target_arch=="xb1" and actual_target_arch!="win"', {
-              'dependencies' : [
-                '../third_party/modp_b64/modp_b64.gyp:modp_b64',
-                '<(lbshell_root)/build/projects/shell_scheme_handler.gyp:shell_scheme_handler',
-              ],
-              'msvs_settings': {
-                'VCCLCompilerTool': {
-                  'ComponentExtensions': 'true'
-                },
-              },
-            }],
             ['target_arch=="linux"', {
               'sources': [
                 'audio/shell_audio_streamer_linux.cc',
@@ -721,22 +710,6 @@
             ['exclude', 'shell_'],
           ],
         }],  # OS != "lb_shell" and OS != "starboard"
-        ['OS == "lb_shell"', {
-          'include_dirs': [
-            '<(lbshell_root)/src/platform/<(target_arch)/chromium',
-            '<(lbshell_root)/src/platform/<(target_arch)/lb_shell',
-          ],
-          'dependencies': [
-            '<(lbshell_root)/build/projects/posix_emulation.gyp:posix_emulation',
-          ],
-          'conditions': [
-            ['(target_arch=="xb1" and actual_target_arch!="win") or target_arch=="xb360"', {
-              'sources': [
-                '<!@(find <(lbshell_root)/src/platform/<(target_arch)/chromium/media -type f)',
-              ],
-            }],
-          ],
-        }],  # OS == "lb_shell"
         ['OS == "starboard"', {
           'dependencies': [
             '<(DEPTH)/starboard/starboard.gyp:starboard',
@@ -745,30 +718,6 @@
             'base/shell_cached_decoder_buffer.cc',
             'base/shell_cached_decoder_buffer.h',
           ],
-          'conditions': [
-            ['sb_media_platform == "starboard"', {
-              'sources': [
-                'audio/shell_audio_streamer_starboard.cc',
-                'base/decoder_buffer_cache.cc',
-                'base/decoder_buffer_cache.h',
-                'base/sbplayer_pipeline.cc',
-                'base/sbplayer_set_bounds_helper.cc',
-                'base/sbplayer_set_bounds_helper.h',
-                'base/starboard_player.cc',
-                'base/starboard_player.h',
-                'base/starboard_utils.cc',
-                'base/starboard_utils.h',
-                'crypto/starboard_decryptor.cc',
-                'crypto/starboard_decryptor.h',
-                'filters/shell_audio_renderer_starboard.cc',
-              ],
-              'sources/': [
-                ['exclude', '^base/pipeline_impl.cc'],
-                ['exclude', '^filters/shell_audio_renderer_impl.cc'],
-                ['exclude', '^filters/shell_video_renderer_impl.cc'],
-              ],
-            }],
-          ],
         }],  # OS == "starboard"
         ['OS == "ios"', {
           'includes': [
diff --git a/src/nb/analytics/memory_tracker_impl.cc b/src/nb/analytics/memory_tracker_impl.cc
index 3273bd8..8f4392b 100644
--- a/src/nb/analytics/memory_tracker_impl.cc
+++ b/src/nb/analytics/memory_tracker_impl.cc
@@ -227,7 +227,7 @@
 
 void MemoryTrackerImpl::SetMemoryTrackerDebugCallback(
     MemoryTrackerDebugCallback* cb) {
-  debug_callback_ = cb;
+  debug_callback_.swap(cb);
 }
 
 MemoryTrackerImpl::DisableDeletionInScope::DisableDeletionInScope(
@@ -242,7 +242,7 @@
 }
 
 MemoryTrackerImpl::MemoryTrackerImpl()
-    : thread_filter_id_(kSbThreadInvalidId), debug_callback_(NULL) {
+    : thread_filter_id_(kSbThreadInvalidId), debug_callback_(nullptr) {
   total_bytes_allocated_.store(0);
   global_hooks_installed_ = false;
   Initialize(&sb_memory_tracker_, &nb_memory_scope_reporter_);
@@ -302,13 +302,15 @@
   if (added) {
     AddAllocationBytes(size);
     group->AddAllocation(size);
-    // Useful for investigating what the heck is being allocated. For example
-    // the developer may want to track certain allocations that meet a certain
-    // criteria.
-    if (debug_callback_) {
+    ConcurrentPtr<MemoryTrackerDebugCallback>::Access access_ptr =
+        debug_callback_.access_ptr(SbThreadId());
+
+    // If access_ptr is valid then it is guaranteed to be alive for the
+    // duration of the scope.
+    if (access_ptr) {
       const CallStack& callstack = *(callstack_tls_.GetOrCreate());
       DisableDeletionInScope disable_deletion_tracking(this);
-      debug_callback_->OnMemoryAllocation(memory, alloc_record, callstack);
+      access_ptr->OnMemoryAllocation(memory, alloc_record, callstack);
     }
   } else {
     // Handles the case where the memory hasn't been properly been reported
@@ -348,15 +350,14 @@
   AllocationRecord alloc_record;
   bool removed = false;
 
-  // Useful for investigating what the heck is being deallocated. For example
-  // the developer may want to track certain allocations that meet a certain
-  // criteria.
-  if (debug_callback_) {
+  ConcurrentPtr<MemoryTrackerDebugCallback>::Access access_ptr =
+      debug_callback_.access_ptr(SbThreadId());
+
+  if (access_ptr) {
     if (atomic_allocation_map_.Get(memory, &alloc_record)) {
       DisableMemoryTrackingInScope no_memory_tracking(this);
       const CallStack& callstack = (*callstack_tls_.GetOrCreate());
-      debug_callback_->OnMemoryDeallocation(memory, alloc_record,
-                                            callstack);
+      access_ptr->OnMemoryDeallocation(memory, alloc_record, callstack);
     }
   }
 
diff --git a/src/nb/analytics/memory_tracker_impl.h b/src/nb/analytics/memory_tracker_impl.h
index b45b1a3..f9abe92 100644
--- a/src/nb/analytics/memory_tracker_impl.h
+++ b/src/nb/analytics/memory_tracker_impl.h
@@ -17,14 +17,15 @@
 #ifndef NB_MEMORY_TRACKER_IMPL_H_
 #define NB_MEMORY_TRACKER_IMPL_H_
 
-#include "nb/analytics/memory_tracker_helpers.h"
 #include "nb/analytics/memory_tracker.h"
+#include "nb/analytics/memory_tracker_helpers.h"
+#include "nb/concurrent_ptr.h"
 #include "nb/memory_scope.h"
 #include "nb/scoped_ptr.h"
 #include "nb/thread_local_object.h"
 #include "starboard/configuration.h"
-#include "starboard/memory_reporter.h"
 #include "starboard/memory.h"
+#include "starboard/memory_reporter.h"
 #include "starboard/mutex.h"
 #include "starboard/time.h"
 
@@ -172,7 +173,7 @@
   AtomicStringAllocationGroupMap alloc_group_map_;
 
   atomic_int64_t total_bytes_allocated_;
-  MemoryTrackerDebugCallback* debug_callback_;
+  ConcurrentPtr<MemoryTrackerDebugCallback> debug_callback_;
 
   // THREAD LOCAL SECTION.
   ThreadLocalBoolean memory_deletion_enabled_tls_;
diff --git a/src/nb/concurrent_ptr.h b/src/nb/concurrent_ptr.h
new file mode 100644
index 0000000..6f48bce
--- /dev/null
+++ b/src/nb/concurrent_ptr.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2017 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NB_CONCURRENT_PTR_H_
+#define NB_CONCURRENT_PTR_H_
+
+#include <algorithm>
+#include <atomic>
+#include <functional>
+#include <iostream>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "starboard/atomic.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/mutex.h"
+#include "starboard/types.h"
+
+namespace nb {
+namespace detail {
+class AtomicPointerBase;
+
+template <typename T>
+class AtomicPointer;
+
+template <typename T>
+class Access;
+}  // namespace detail
+
+// ConcurrentPtr is similar to a scoped_ptr<> but with additional thread safe
+//  guarantees on the lifespan of the owned pointer. Threads can get access
+//  to the owned pointer using class ConcurrentPtr<T>::Access, which will lock
+//  the lifetime of the pointer for the duration that ConcurrentPtr<T>::Access
+//  object will remain in scope. Operations on the object pointed to by the
+//  owned pointer has no additional thread safety guarantees.
+//
+//
+// ConcurrentPtr<T>::access_ptr(...) will take in an arbitrary id value and
+//  will hash this id value to select one of the buckets. Good id's to pass in
+//  include input from SbThreadGetId() or random numbers (std::rand() is known
+//  to use internal locks on some implementations!).
+//
+// Performance:
+//  To increase performance, the lifespan of ConcurrentPtr<T>::Access instance
+//  should be as short as possible.
+//
+//  The number of buckets has a large effect on performance. More buckets will
+//  result in lower contention.
+//
+//  A hashing function with good distribution will produce less contention.
+//
+// Example:
+//  class MyClass { void Run(); };
+//  ConcurrentPtr<MyClass> shared_concurrent_ptr_(new MyClass);
+//
+//  // From all other threads.
+//  ConcurrentPtr<MyClass>::Access access_ptr =
+//      shared_concurrent_ptr_.access_ptr(SbThreadGetId());
+//  // access_ptr now either holds a valid object pointer or either nullptr.
+//  if (access_ptr) {
+//    access_ptr->Run();
+//  }
+template <typename T, typename KeyT = int64_t, typename HashT = std::hash<KeyT>>
+class ConcurrentPtr {
+ public:
+  ConcurrentPtr(T* ptr, size_t number_locks = 31) : ptr_(NULL) {
+    internal_construct(ptr, number_locks);
+  }
+  ~ConcurrentPtr() { internal_destruct(); }
+
+  // Used to access the underlying pointer to perform operations. The lifetime
+  //  of the accessed pointer is guaranteed to be alive for the duration of the
+  //  lifetime of this access object.
+  //
+  // Example
+  //  ConcurrentPtr<MyClass>::Access access_ptr =
+  //      shared_concurrent_ptr_.access_ptr(SbThreadGetId());
+  //  if (access_ptr) {
+  //    access_ptr->Run();
+  //  }
+  using Access = nb::detail::Access<T>;
+
+  // Provides read access to the underlying pointer in a thread safe way.
+  inline Access access_ptr(const KeyT& seed) {
+    const size_t index = hasher_(seed) % table_.size();
+    AtomicPointer* atomic_ptr = table_[index];
+    return atomic_ptr->access_ptr();
+  }
+
+  void reset(T* value) { delete SetAllThenSwap(value); }
+  T* release() { return SetAllThenSwap(nullptr); }
+  T* swap(T* new_value) { return SetAllThenSwap(new_value); }
+
+ private:
+  using Mutex = starboard::Mutex;
+  using ScopedLock = starboard::ScopedLock;
+  using AtomicPointer = nb::detail::AtomicPointer<T>;
+
+  // Change all buckets to the new pointer. The old pointer is returned.
+  T* SetAllThenSwap(T* new_ptr) {
+    ScopedLock write_lock(pointer_write_mutex_);
+    for (auto it = table_.begin(); it != table_.end(); ++it) {
+      AtomicPointer* atomic_ptr = *it;
+      atomic_ptr->swap(new_ptr);
+    }
+    T* old_ptr = ptr_;
+    ptr_ = new_ptr;
+    return old_ptr;
+  }
+
+  void internal_construct(T* ptr, size_t number_locks) {
+    table_.resize(number_locks);
+    for (auto it = table_.begin(); it != table_.end(); ++it) {
+      *it = new AtomicPointer;
+    }
+    reset(ptr);
+  }
+
+  void internal_destruct() {
+    reset(nullptr);
+    for (auto it = table_.begin(); it != table_.end(); ++it) {
+      delete *it;
+    }
+    table_.clear();
+  }
+  HashT hasher_;
+  Mutex pointer_write_mutex_;
+  std::vector<AtomicPointer*> table_;
+  T* ptr_;
+};
+
+/////////////////////////// Implementation Details ////////////////////////////
+namespace detail {
+
+// Access is a smart pointer type which holds a lock to the underlying pointer
+// returned by ConcurrentPtr and AtomicPointer.
+template <typename T>
+class Access {
+ public:
+  Access() = delete;
+  // It's assumed that ref_count is incremented before being passed
+  // to this constructor.
+  inline Access(T* ptr, starboard::atomic_int32_t* ref_count)
+      : ref_count_(ref_count), ptr_(ptr) {}
+
+  Access(const Access& other) = delete;
+  // Allow move construction.
+  Access(Access&& other) = default;
+
+  inline ~Access() { release(); }
+
+  inline operator bool() const { return valid(); }
+  inline operator T*() const { return get(); }
+  inline T* operator->() { return get(); }
+  inline T* get() const { return ptr_; }
+  inline bool valid() const { return !!get(); }
+  inline void release() { internal_release(); }
+
+ private:
+  inline void internal_release() {
+    if (ref_count_) {
+      ref_count_->decrement();
+      ref_count_ = nullptr;
+    }
+    ptr_ = nullptr;
+  }
+  starboard::atomic_int32_t* ref_count_;
+  T* ptr_;
+};
+
+// AtomicPointer allows read access to a pointer through access_ptr()
+// and a form of atomic swap.
+template <typename T>
+class AtomicPointer {
+ public:
+  // Customer new/delete operators align AtomicPointers to cache
+  // lines for improved performance.
+  static void* operator new(std::size_t count) {
+    const int kCacheLineSize = 64;
+    return SbMemoryAllocateAligned(kCacheLineSize, count);
+  }
+  static void operator delete(void* ptr) { SbMemoryDeallocateAligned(ptr); }
+
+  AtomicPointer() : ptr_(nullptr), counter_(0) {}
+  ~AtomicPointer() { delete get(); }
+  inline T* swap(T* new_ptr) {
+    AcquireWriteLock();
+    T* old_ptr = get();
+    ptr_.store(new_ptr);
+    WaitForReadersToDrain();
+    ReleaseWriteLock();
+    return old_ptr;
+  }
+
+  inline void reset(T* new_ptr) { delete swap(new_ptr); }
+  inline T* get() { return ptr_.load(); }
+  inline Access<T> access_ptr() {
+    counter_.increment();
+    return Access<T>(ptr_.load(), &counter_);
+  }
+
+ private:
+  inline void AcquireWriteLock() {
+    write_mutex_.Acquire();
+    counter_.increment();
+  }
+  inline void WaitForReadersToDrain() {
+    int32_t expected_value = 1;
+    while (!counter_.compare_exchange_weak(&expected_value, 0)) {
+      SbThreadYield();
+      expected_value = 1;
+    }
+  }
+  inline void ReleaseWriteLock() { write_mutex_.Release(); }
+
+  starboard::Mutex write_mutex_;
+  starboard::atomic_int32_t counter_;
+  starboard::atomic_pointer<T*> ptr_;
+};
+}  // namespace detail
+}  // namespace nb
+
+#endif  // NB_CONCURRENT_PTR_H_
diff --git a/src/nb/concurrent_ptr_test.cc b/src/nb/concurrent_ptr_test.cc
new file mode 100644
index 0000000..ff0b0ba
--- /dev/null
+++ b/src/nb/concurrent_ptr_test.cc
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2014 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "nb/concurrent_ptr.h"
+
+#include "nb/simple_thread.h"
+#include "starboard/atomic.h"
+#include "starboard/common/semaphore.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Number of threads for the thread test.
+#define NUM_THREADS 64
+
+namespace nb {
+
+using atomic_int32 = starboard::atomic_int32_t;
+using atomic_int64 = starboard::atomic_int64_t;
+using Semaphore = starboard::Semaphore;
+
+struct CountLifetime {
+  explicit CountLifetime(atomic_int32* shared_int) {
+    shared_int_ = shared_int;
+    shared_int_->increment();
+  }
+
+  ~CountLifetime() { shared_int_->decrement(); }
+
+  atomic_int32* shared_int_;
+};
+
+TEST(ConcurrentPtr, nullptr) {
+  ConcurrentPtr<int> concurrent_ptr(nullptr);
+  ConcurrentPtr<int>::Access access_ptr =
+      concurrent_ptr.access_ptr(SbThreadGetId());
+  ASSERT_FALSE(access_ptr);
+  ASSERT_FALSE(access_ptr.valid());
+  ASSERT_EQ(access_ptr.get(), nullptr);
+  access_ptr.release();
+  concurrent_ptr.reset(nullptr);
+}
+
+TEST(ConcurrentPtr, UseSingleThreaded) {
+  int* int_ptr = new int(1234);
+  ConcurrentPtr<int> concurrent_ptr(int_ptr);
+  ConcurrentPtr<int>::Access access_ptr =
+      concurrent_ptr.access_ptr(SbThreadGetId());
+
+  ASSERT_TRUE(access_ptr);
+  ASSERT_TRUE(access_ptr.valid());
+  ASSERT_EQ(int_ptr, access_ptr.get());
+  ASSERT_EQ(int_ptr, &(*access_ptr));
+  access_ptr.release();
+  int* int_ptr2 = concurrent_ptr.release();
+  ASSERT_EQ(int_ptr, int_ptr2);
+  ASSERT_EQ(1234, *int_ptr);
+  delete int_ptr;
+}
+
+TEST(ConcurrentPtr, ResetDeltesInternalObject) {
+  atomic_int32 counter(0);
+
+  CountLifetime* ptr = new CountLifetime(&counter);
+  EXPECT_EQ(1, counter.load());
+
+  ConcurrentPtr<CountLifetime> concurrent_ptr(ptr);
+  concurrent_ptr.reset(nullptr);
+  EXPECT_EQ(0, counter.load());
+}
+
+TEST(ConcurrentPtr, UsePointerOperators) {
+  ConcurrentPtr<atomic_int32> concurrent_ptr(new atomic_int32());
+  ConcurrentPtr<atomic_int32>::Access access_ptr =
+      concurrent_ptr.access_ptr(SbThreadGetId());
+  ASSERT_TRUE(access_ptr.valid());
+  ASSERT_TRUE(access_ptr.get());
+
+  {
+    atomic_int32& int_ref = *access_ptr;
+    ASSERT_EQ(0, int_ref.load());
+  }
+
+  ASSERT_EQ(0, access_ptr->load());
+  access_ptr->store(2);
+  ASSERT_EQ(2, access_ptr->load());
+}
+
+class ConcurrentPtrThreadWorker : public SimpleThread {
+ public:
+  ConcurrentPtrThreadWorker(Semaphore* thread_seal,
+                            ConcurrentPtr<atomic_int32>* concurrent_ptr)
+      : SimpleThread("ConcurrentPtrThreadWorker"),
+        thread_seal_(thread_seal),
+        concurrent_ptr_(concurrent_ptr),
+        finished_(false) {
+    Start();
+  }
+
+  ConcurrentPtrThreadWorker(const ConcurrentPtrThreadWorker&) = delete;
+
+  ~ConcurrentPtrThreadWorker() {
+    finished_ = true;
+    Join();
+  }
+
+  virtual void Run() {
+    thread_seal_->Take();  // Pause until the main thread unblocks us.
+    int64_t yield_counter = 0;
+    while (!finished_) {
+      if (yield_counter++ % 512 == 0) {  // Be nice to other threads.
+        SbThreadYield();
+      }
+      ConcurrentPtr<atomic_int32>::Access access_ptr =
+          concurrent_ptr_->access_ptr(SbThreadGetId());
+      if (access_ptr) {
+        access_ptr->load();
+        access_ptr->store(SbThreadGetId());
+      }
+    }
+  }
+
+  virtual void Cancel() { finished_ = true; }
+
+ private:
+  Semaphore* thread_seal_;
+  ConcurrentPtr<atomic_int32>* concurrent_ptr_;
+  bool finished_;
+};
+
+// Tests the expectation that the ConcurrentPtr can have it's underlying
+// pointer repeatedly reset and that all the reading threads will be guaranteed
+// to either be able to lock the pointer for it's use or be receive nullptr.
+TEST(ConcurrentPtr, ThreadStressTest) {
+  Semaphore thread_seal;
+  ConcurrentPtr<atomic_int32> concurrent_ptr(new atomic_int32);
+
+  std::vector<ConcurrentPtrThreadWorker*> threads;
+  const int kThreads = NUM_THREADS;
+  for (int i = 0; i < kThreads; ++i) {
+    threads.push_back(
+        new ConcurrentPtrThreadWorker(&thread_seal, &concurrent_ptr));
+  }
+
+  // Launch threads.
+  for (int i = 0; i < kThreads; ++i) {
+    thread_seal.Put();
+  }
+
+  // Repeatedly reset the underlying pointer. If there is a race
+  // condition then the program will crash.
+  const SbTime start_time = SbTimeGetNow();
+  const SbTime end_time = start_time + (kSbTimeMillisecond * 100);
+  while (SbTimeGetNow() < end_time) {
+    concurrent_ptr.reset(nullptr);
+    SbThreadYield();
+    concurrent_ptr.reset(new atomic_int32);
+    concurrent_ptr.reset(new atomic_int32);
+    SbThreadYield();
+  }
+
+  for (auto it = threads.begin(); it != threads.end(); ++it) {
+    delete *it;
+  }
+  threads.clear();
+}
+
+}  // namespace nb.
diff --git a/src/nb/nb.gyp b/src/nb/nb.gyp
index 8523211..8c50a66 100644
--- a/src/nb/nb.gyp
+++ b/src/nb/nb.gyp
@@ -35,6 +35,7 @@
             'bidirectional_fit_reuse_allocator.h',
             'bidirectional_fit_reuse_allocator.cc',
             'concurrent_map.h',
+            'concurrent_ptr.h',
             'first_fit_reuse_allocator.h',
             'first_fit_reuse_allocator.cc',
             'fixed_no_free_allocator.cc',
@@ -95,6 +96,7 @@
             'atomic_test.cc',
             'bidirectional_fit_reuse_allocator_test.cc',
             'concurrent_map_test.cc',
+            'concurrent_ptr_test.cc',
             'first_fit_reuse_allocator_test.cc',
             'fixed_no_free_allocator_test.cc',
             'lexical_cast_test.cc',
diff --git a/src/nb/starboard_memory_allocator.h b/src/nb/starboard_memory_allocator.h
index 5f53112..62c59a3 100644
--- a/src/nb/starboard_memory_allocator.h
+++ b/src/nb/starboard_memory_allocator.h
@@ -38,7 +38,7 @@
                              std::size_t alignment) SB_OVERRIDE {
     return Allocate(*size, alignment);
   }
-  void Free(void* memory) SB_OVERRIDE { SbMemoryDeallocate(memory); }
+  void Free(void* memory) SB_OVERRIDE { SbMemoryDeallocateAligned(memory); }
   std::size_t GetCapacity() const SB_OVERRIDE {
     // Returns 0 here to avoid tracking the allocated memory.
     return 0;
diff --git a/src/net/base/mime_util_unittest.cc b/src/net/base/mime_util_unittest.cc
index c01b1d4..3a3b650 100644
--- a/src/net/base/mime_util_unittest.cc
+++ b/src/net/base/mime_util_unittest.cc
@@ -192,11 +192,7 @@
 TEST(MimeUtilTest, TestIsMimeType) {
   std::string nonAscii("application/nonutf8");
   EXPECT_TRUE(IsMimeType(nonAscii));
-#if defined(OS_WIN)
-  nonAscii.append(WideToUTF8(std::wstring(L"\u2603")));
-#else
-  nonAscii.append("\u2603");  // unicode snowman
-#endif
+  nonAscii.append(u8"\u2603");  // unicode snowman
   EXPECT_FALSE(IsMimeType(nonAscii));
 
   EXPECT_TRUE(IsMimeType("application/mime"));
diff --git a/src/net/cookies/cookie_monster_unittest.cc b/src/net/cookies/cookie_monster_unittest.cc
index 86cecff..38f7378 100644
--- a/src/net/cookies/cookie_monster_unittest.cc
+++ b/src/net/cookies/cookie_monster_unittest.cc
@@ -1725,11 +1725,11 @@
   // time and size of store to make sure we only get rid of cookies when
   // we really should.
   const struct TestCase {
-    int num_cookies;
-    int num_old_cookies;
-    int expected_initial_cookies;
+    size_t num_cookies;
+    size_t num_old_cookies;
+    size_t expected_initial_cookies;
     // Indexed by ExpiryAndKeyScheme
-    int expected_cookies_after_set;
+    size_t expected_cookies_after_set;
   } test_cases[] = {
     {
       // A whole lot of recent cookies; gc shouldn't happen.
@@ -1766,12 +1766,12 @@
             test_case->num_cookies, test_case->num_old_cookies,
             CookieMonster::kSafeFromGlobalPurgeDays * 2));
     EXPECT_EQ(test_case->expected_initial_cookies,
-              static_cast<int>(GetAllCookies(cm).size()))
+              GetAllCookies(cm).size())
         << "For test case " << ci;
     // Will trigger GC
     SetCookie(cm, GURL("http://newdomain.com"), "b=2");
     EXPECT_EQ(test_case->expected_cookies_after_set,
-              static_cast<int>((GetAllCookies(cm).size())))
+              (GetAllCookies(cm).size()))
         << "For test case " << ci;
   }
 }
diff --git a/src/sql/sql.gyp b/src/sql/sql.gyp
index ff30949..ef71147 100644
--- a/src/sql/sql.gyp
+++ b/src/sql/sql.gyp
@@ -30,11 +30,6 @@
         'transaction.h',
       ],
       'conditions': [
-        ['OS=="lb_shell"', {
-          'dependencies': [
-            '<(lbshell_root)/build/projects/posix_emulation.gyp:posix_emulation',
-            ],
-          }],
         ['OS=="starboard"', {
           'dependencies': [
             '<(DEPTH)/starboard/starboard.gyp:starboard',
diff --git a/src/starboard/CHANGELOG.md b/src/starboard/CHANGELOG.md
index 7ce54d9..acbe7b4 100644
--- a/src/starboard/CHANGELOG.md
+++ b/src/starboard/CHANGELOG.md
@@ -56,6 +56,9 @@
 signal that the application may soon be terminated due to low memory
 availability.
 
+### Interface change to SbPlayerWriteSample()
+`const` is added to `sample_buffers` and `sample_buffer_sizes` parameters.
+
 ## Version 5
 
 ### Add Speech Recognizer API
diff --git a/src/starboard/common/common.gyp b/src/starboard/common/common.gyp
index bfe17b0..bf285ef 100644
--- a/src/starboard/common/common.gyp
+++ b/src/starboard/common/common.gyp
@@ -43,6 +43,13 @@
         # building Starboard client code.
         'STARBOARD_IMPLEMENTATION',
       ],
+      'conditions': [
+        ['custom_media_session_client==0', {
+          'sources': [
+            '<(DEPTH)/starboard/shared/media_session/stub_playback_state.cc',
+           ],
+        }],
+      ]
     },
   ],
 }
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h
index 00dc565..d6007c9 100644
--- a/src/starboard/configuration.h
+++ b/src/starboard/configuration.h
@@ -76,6 +76,8 @@
   SB_RELEASE_CANDIDATE_API_VERSION
 #define SB_COLOR_KEYCODES_API_VERSION SB_RELEASE_CANDIDATE_API_VERSION
 #define SB_LOW_MEMORY_EVENT_API_VERSION SB_RELEASE_CANDIDATE_API_VERSION
+#define SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION \
+  SB_RELEASE_CANDIDATE_API_VERSION
 
 // --- Common Detected Features ----------------------------------------------
 
@@ -547,20 +549,6 @@
 #error "SB_MEDIA_GPU_BUFFER_BUDGET is deprecated."
 #endif  // defined(SB_MEDIA_GPU_BUFFER_BUDGET)
 
-#if COBALT_MEDIA_BUFFER_NON_VIDEO_BUDGET <= 0
-#error "cobalt_media_buffer_non_video_budget has to be greater than 0."
-#endif  // COBALT_MEDIA_BUFFER_NON_VIDEO_BUDGET < 0
-
-#if COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P <= 0
-#error "cobalt_media_buffer_video_budget_1080p has to be greater than 0."
-#endif  // COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P < 0
-
-#if COBALT_MEDIA_BUFFER_VIDEO_BUDGET_4K < COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P
-#error cobalt_media_buffer_video_budget_4k has to be greater than or equal to \
-           cobalt_media_buffer_video_budget_1080p.
-#endif  // COBALT_MEDIA_BUFFER_VIDEO_BUDGET_4K <
-        //     COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P
-
 #endif  // SB_API_VERSION >= 4
 
 #if SB_API_VERSION >= 5
diff --git a/src/starboard/linux/shared/gyp_configuration.gypi b/src/starboard/linux/shared/gyp_configuration.gypi
index 01ca539..9500981 100644
--- a/src/starboard/linux/shared/gyp_configuration.gypi
+++ b/src/starboard/linux/shared/gyp_configuration.gypi
@@ -35,7 +35,6 @@
       '-lavresample',
       '-lavutil',
       '-lpthread',
-      '-lpulse',
       '-lrt',
     ],
 
diff --git a/src/starboard/linux/x64x11/clang/3.3/atomic_public.h b/src/starboard/linux/x64x11/clang/3.3/atomic_public.h
deleted file mode 100644
index 2318bd7..0000000
--- a/src/starboard/linux/x64x11/clang/3.3/atomic_public.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef STARBOARD_LINUX_X64X11_CLANG_3_3_ATOMIC_PUBLIC_H_
-#define STARBOARD_LINUX_X64X11_CLANG_3_3_ATOMIC_PUBLIC_H_
-
-#include "starboard/linux/x64x11/atomic_public.h"
-
-#endif  // STARBOARD_LINUX_X64X11_CLANG_3_3_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/clang/3.3/compiler_flags.gypi b/src/starboard/linux/x64x11/clang/3.3/compiler_flags.gypi
deleted file mode 100644
index 22d5331..0000000
--- a/src/starboard/linux/x64x11/clang/3.3/compiler_flags.gypi
+++ /dev/null
@@ -1,162 +0,0 @@
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Platform specific compiler flags for Linux on Starboard. Included from
-# gyp_configuration.gypi.
-#
-{
-  'variables': {
-    'compiler_flags_host': [
-      '-O2',
-    ],
-    'linker_flags': [
-    ],
-    'compiler_flags_debug': [
-      '-frtti',
-      '-O0',
-    ],
-    'compiler_flags_devel': [
-      '-frtti',
-      '-O2',
-    ],
-    'compiler_flags_qa': [
-      '-fno-rtti',
-      '-O2',
-      '-gline-tables-only',
-    ],
-    'compiler_flags_gold': [
-      '-fno-rtti',
-      '-O2',
-      '-gline-tables-only',
-    ],
-    'conditions': [
-      ['clang==1', {
-        'common_clang_flags': [
-          '-Werror',
-          '-fcolor-diagnostics',
-          # Default visibility to hidden, to enable dead stripping.
-          '-fvisibility=hidden',
-          # protobuf uses hash_map.
-          '-Wno-deprecated',
-          '-fno-exceptions',
-          # Don't warn about the "struct foo f = {0};" initialization pattern.
-          '-Wno-missing-field-initializers',
-          '-fno-strict-aliasing',  # See http://crbug.com/32204
-          # Don't warn for invalid access to non-static data member of NULL object.
-          '-Wno-invalid-offsetof',
-          # Don't warn about any conversions.
-          '-Wno-conversion',
-          # Don't complain about unknown warning options
-          '-Wno-unknown-warning-option',
-          # Suppress: "warning: 'override' keyword is a C++11 extension"
-          '-Wno-c++11-extensions',
-          # Suppress "case value not in enumerated type"
-          '-Wno-switch',
-          # Suppress "'&&' within '||'"
-          '-Wno-logical-op-parentheses',
-          # Suppress "error: unused function"
-          '-Wno-unused-function',
-          # Suppress "comparison of unsigned enum expression < 0 is always false"
-          '-Wno-tautological-compare',
-          # Suppress "[type1] has C-linkage specified, but returns user-defined type [type2] which is incompatible with C"
-          '-Wno-return-type-c-linkage',
-          # Suppress "will never be executed"
-          '-Wno-unreachable-code',
-          # Suppress "++98 requires a copy constructor when binding a reference to a temporary"
-          '-Wno-bind-to-temporary-copy',
-          '-DHAS_LEAK_SANITIZER=0', # Clang 3.3 does not have Leak Sanitizer. This is
-                                    # is important because it's assumed in chromium
-                                    # that the two always are enabled together.
-          # Suppress "template argument uses unnamed type"
-          '-Wno-unnamed-type-template-args',
-        ],
-      }],
-      ['cobalt_fastbuild==0', {
-        'compiler_flags_debug': [
-          '-g',
-        ],
-        'compiler_flags_devel': [
-          '-g',
-        ],
-        'compiler_flags_qa': [
-          '-gline-tables-only',
-        ],
-        'compiler_flags_gold': [
-          '-gline-tables-only',
-        ],
-      }],
-    ],
-  },
-
-  'target_defaults': {
-    'cflags_c': [
-      # Limit to C99. This allows Linux to be a canary build for any
-      # C11 features that are not supported on some platforms' compilers.
-      '-std=c99',
-    ],
-    'cflags_cc': [
-      '-std=gnu++98',
-    ],
-    'target_conditions': [
-      ['sb_pedantic_warnings==1', {
-        'cflags': [
-          '-Wall',
-          '-Wextra',
-          '<@(common_clang_flags)',
-        ],
-      },{
-        'cflags': [
-          '<@(common_clang_flags)',
-          # 'this' pointer cannot be NULL...pointer may be assumed
-          # to always convert to true.
-          '-Wno-undefined-bool-conversion',
-          # Skia doesn't use overrides.
-          '-Wno-inconsistent-missing-override',
-          # Do not warn about unused function params.
-          '-Wno-unused-parameter',
-          # shifting a negative signed value is undefined
-          '-Wno-shift-negative-value',
-          # Width of bit-field exceeds width of its type- value will be truncated
-          '-Wno-bitfield-width',
-        ],
-      }],
-      ['use_asan==1', {
-        'cflags': [
-          '-fsanitize=address',
-          '-fno-omit-frame-pointer',
-        ],
-        'ldflags': [
-          '-fsanitize=address',
-          # Force linking of the helpers in sanitizer_options.cc
-          '-Wl,-u_sanitizer_options_link_helper',
-        ],
-        'defines': [
-          'ADDRESS_SANITIZER',
-        ],
-      }],
-      ['use_tsan==1', {
-        'cflags': [
-          '-fsanitize=thread',
-          '-fno-omit-frame-pointer',
-        ],
-        'ldflags': [
-          '-fsanitize=thread',
-        ],
-        'defines': [
-          'THREAD_SANITIZER',
-        ],
-      }],
-    ],
-  }, # end of target_defaults
-}
diff --git a/src/starboard/linux/x64x11/clang/3.3/configuration_public.h b/src/starboard/linux/x64x11/clang/3.3/configuration_public.h
deleted file mode 100644
index 1914518..0000000
--- a/src/starboard/linux/x64x11/clang/3.3/configuration_public.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef STARBOARD_LINUX_X64X11_CLANG_3_3_CONFIGURATION_PUBLIC_H_
-#define STARBOARD_LINUX_X64X11_CLANG_3_3_CONFIGURATION_PUBLIC_H_
-
-#include "starboard/linux/x64x11/configuration_public.h"
-
-// Indicates that there is no support for alignment at greater than 16 bytes for
-// items on the stack.
-#define SB_HAS_QUIRK_DOES_NOT_STACK_ALIGN_OVER_16_BYTES 1
-
-#endif  // STARBOARD_LINUX_X64X11_CLANG_3_3_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/clang/3.3/download_clang.sh b/src/starboard/linux/x64x11/clang/3.3/download_clang.sh
deleted file mode 100755
index f552ae8..0000000
--- a/src/starboard/linux/x64x11/clang/3.3/download_clang.sh
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This script downloads and compiles clang version 3.3.
-
-set -e
-
-toolchain_name="clang"
-version="3.3"
-toolchain_folder="x86_64-linux-gnu-${toolchain_name}-${version}"
-branch="release_33"
-
-binary_path="llvm/Release+Asserts/bin/clang++"
-build_duration="about 15 minutes"
-
-source ../../toolchain_paths.sh
-
-(
-  git clone --branch ${branch} http://llvm.org/git/llvm.git
-  cd llvm/tools/
-  git clone --branch ${branch} http://llvm.org/git/clang.git
-  cd ../projects/
-  git clone --branch ${branch} http://llvm.org/git/compiler-rt.git
-  cd ${toolchain_path}
-
-  cd llvm
-  # Specify a bootstrap compiler that is known to be available.
-  CC=clang-3.6 CXX=clang++-3.6 \
-  ./configure --enable-optimized --disable-doxygen --prefix=${PWD}/bin
-  make -j"$(nproc)"
-  cd ${toolchain_path}
-
-  ls -l ${toolchain_binary}
-  ${toolchain_binary} --version
-) >${logfile} 2>&1
diff --git a/src/starboard/linux/x64x11/clang/3.3/gyp_configuration.gypi b/src/starboard/linux/x64x11/clang/3.3/gyp_configuration.gypi
deleted file mode 100644
index 05d38d0..0000000
--- a/src/starboard/linux/x64x11/clang/3.3/gyp_configuration.gypi
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-{
-  'variables': {
-    # This should have a default value in cobalt/base.gypi. See the comment
-    # there for acceptable values for this variable.
-    'javascript_engine': 'mozjs',
-    'cobalt_enable_jit': 1,
-  },
-  'target_defaults': {
-    'default_configuration': 'linux-x64x11-clang-3-3_debug',
-    'configurations': {
-      'linux-x64x11-clang-3-3_debug': {
-        'inherit_from': ['debug_base'],
-      },
-      'linux-x64x11-clang-3-3_devel': {
-        'inherit_from': ['devel_base'],
-      },
-      'linux-x64x11-clang-3-3_qa': {
-        'inherit_from': ['qa_base'],
-      },
-      'linux-x64x11-clang-3-3_gold': {
-        'inherit_from': ['gold_base'],
-      },
-    }, # end of configurations
-  },
-
-  'includes': [
-    'compiler_flags.gypi',
-    '../gyp_configuration.gypi',
-  ],
-}
diff --git a/src/starboard/linux/x64x11/clang/3.3/gyp_configuration.py b/src/starboard/linux/x64x11/clang/3.3/gyp_configuration.py
deleted file mode 100644
index 7efd522..0000000
--- a/src/starboard/linux/x64x11/clang/3.3/gyp_configuration.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Starboard Linux X64 X11 Clang 3.6 platform configuration for gyp_cobalt."""
-
-import logging
-import os
-import subprocess
-import sys
-
-# Import the shared Linux platform configuration.
-sys.path.append(
-    os.path.realpath(
-        os.path.join(
-            os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
-            'shared')))
-# pylint: disable=import-self,g-import-not-at-top
-import gyp_configuration as shared_configuration
-import gyp_utils
-
-
-class PlatformConfig(shared_configuration.PlatformConfig):
-  """Starboard Linux platform configuration."""
-
-  def __init__(self, platform, asan_enabled_by_default=False):
-    super(PlatformConfig, self).__init__(
-        platform, asan_enabled_by_default, goma_supports_compiler=False)
-
-    script_path = os.path.dirname(os.path.realpath(__file__))
-    # Run the script that ensures clang 3.3 is installed.
-    subprocess.call(
-        os.path.join(script_path, 'download_clang.sh'), cwd=script_path)
-
-  def GetEnvironmentVariables(self):
-    env_variables = super(PlatformConfig, self).GetEnvironmentVariables()
-    toolchain_bin_dir = os.path.join(gyp_utils.GetToolchainsDir(),
-                                     'x86_64-linux-gnu-clang-3.3', 'llvm',
-                                     'Release+Asserts', 'bin')
-    env_variables.update({
-        'CC': os.path.join(toolchain_bin_dir, 'clang'),
-        'CXX': os.path.join(toolchain_bin_dir, 'clang++'),
-    })
-    return env_variables
-
-
-def CreatePlatformConfig():
-  try:
-    return PlatformConfig('linux-x64x11-clang-3-3')
-  except RuntimeError as e:
-    logging.critical(e)
-    return None
diff --git a/src/starboard/linux/x64x11/clang/3.3/starboard_platform.gyp b/src/starboard/linux/x64x11/clang/3.3/starboard_platform.gyp
deleted file mode 100644
index 71a6d38..0000000
--- a/src/starboard/linux/x64x11/clang/3.3/starboard_platform.gyp
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2016 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-{
-  'includes': [
-    '../starboard_platform.gyp',
-  ],
-}
diff --git a/src/starboard/linux/x64x11/clang/3.3/thread_types_public.h b/src/starboard/linux/x64x11/clang/3.3/thread_types_public.h
deleted file mode 100644
index d9310bd..0000000
--- a/src/starboard/linux/x64x11/clang/3.3/thread_types_public.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef STARBOARD_LINUX_X64X11_CLANG_3_3_THREAD_TYPES_PUBLIC_H_
-#define STARBOARD_LINUX_X64X11_CLANG_3_3_THREAD_TYPES_PUBLIC_H_
-
-#include "starboard/linux/x64x11/thread_types_public.h"
-
-#endif  // STARBOARD_LINUX_X64X11_CLANG_3_3_THREAD_TYPES_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/libraries.gypi b/src/starboard/linux/x64x11/libraries.gypi
index 60a0f7e..f2c94d0 100644
--- a/src/starboard/linux/x64x11/libraries.gypi
+++ b/src/starboard/linux/x64x11/libraries.gypi
@@ -19,7 +19,6 @@
       '-lGLESv2',
       '-lX11',
       '-lXcomposite',
-      '-lXext',
       '-lXrender',
     ],
   },
diff --git a/src/starboard/linux/x64x11/mse2016/atomic_public.h b/src/starboard/linux/x64x11/mse2016/atomic_public.h
deleted file mode 100644
index 889c4c2..0000000
--- a/src/starboard/linux/x64x11/mse2016/atomic_public.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "starboard/linux/x64x11/atomic_public.h"
diff --git a/src/starboard/linux/x64x11/mse2016/configuration_public.h b/src/starboard/linux/x64x11/mse2016/configuration_public.h
deleted file mode 100644
index 49d5f8a..0000000
--- a/src/starboard/linux/x64x11/mse2016/configuration_public.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// The Starboard configuration for Desktop X86 Linux. Other devices will have
-// specific Starboard implementations, even if they ultimately are running some
-// version of Linux.
-
-// Other source files should never include this header directly, but should
-// include the generic "starboard/configuration.h" instead.
-
-#ifndef STARBOARD_LINUX_X64X11_MSE2016_CONFIGURATION_PUBLIC_H_
-#define STARBOARD_LINUX_X64X11_MSE2016_CONFIGURATION_PUBLIC_H_
-
-// Include the Linux configuration that's common between all x64x11 Linuxes.
-#include "starboard/linux/x64x11/configuration_public.h"
-
-#endif  // STARBOARD_LINUX_X64X11_MSE2016_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/linux/x64x11/mse2016/gyp_configuration.gypi b/src/starboard/linux/x64x11/mse2016/gyp_configuration.gypi
deleted file mode 100644
index 75362de..0000000
--- a/src/starboard/linux/x64x11/mse2016/gyp_configuration.gypi
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2017 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-{
-  'variables': {
-    'cobalt_media_source_2016': 1,
-  },
-  'target_defaults': {
-    'default_configuration': 'linux-x64x11-mse2016_debug',
-    'configurations': {
-      'linux-x64x11-mse2016_debug': {
-        'inherit_from': ['debug_base'],
-      },
-      'linux-x64x11-mse2016_devel': {
-        'inherit_from': ['devel_base'],
-      },
-      'linux-x64x11-mse2016_qa': {
-        'inherit_from': ['qa_base'],
-      },
-      'linux-x64x11-mse2016_gold': {
-        'inherit_from': ['gold_base'],
-      },
-    }, # end of configurations
-  },
-
-  'includes': [
-    '../gyp_configuration.gypi',
-  ],
-}
diff --git a/src/starboard/linux/x64x11/mse2016/gyp_configuration.py b/src/starboard/linux/x64x11/mse2016/gyp_configuration.py
deleted file mode 100644
index ec9d0e5..0000000
--- a/src/starboard/linux/x64x11/mse2016/gyp_configuration.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2015 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Starboard Linux X64 X11 MSE2016 platform configuration for gyp_cobalt."""
-
-import logging
-import os
-import sys
-
-# Import the shared platform configuration.
-sys.path.append(os.path.realpath(os.path.join(
-    os.path.dirname(__file__), os.pardir, os.pardir, 'shared')))
-import gyp_configuration
-
-
-def CreatePlatformConfig():
-  try:
-    return gyp_configuration.PlatformConfig('linux-x64x11-mse2016')
-  except RuntimeError as e:
-    logging.critical(e)
-    return None
diff --git a/src/starboard/linux/x64x11/mse2016/starboard_platform.gyp b/src/starboard/linux/x64x11/mse2016/starboard_platform.gyp
deleted file mode 100644
index d64fb48..0000000
--- a/src/starboard/linux/x64x11/mse2016/starboard_platform.gyp
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2015 Google Inc. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-{
-  'includes': [
-    '../starboard_platform.gypi'
-  ],
-  'targets': [
-    {
-      'target_name': 'starboard_platform',
-      'type': 'static_library',
-      'sources': [
-        '<@(starboard_platform_sources)',
-      ],
-      'defines': [
-        # This must be defined when building Starboard, and must not when
-        # building Starboard client code.
-        'STARBOARD_IMPLEMENTATION',
-      ],
-      'dependencies': [
-        '<@(starboard_platform_dependencies)',
-      ],
-    },
-  ],
-}
diff --git a/src/starboard/linux/x64x11/mse2016/thread_types_public.h b/src/starboard/linux/x64x11/mse2016/thread_types_public.h
deleted file mode 100644
index 04d844d..0000000
--- a/src/starboard/linux/x64x11/mse2016/thread_types_public.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "starboard/linux/x64x11/thread_types_public.h"
diff --git a/src/starboard/player.h b/src/starboard/player.h
index a58b683..0226d8b 100644
--- a/src/starboard/player.h
+++ b/src/starboard/player.h
@@ -399,8 +399,13 @@
 SB_EXPORT void SbPlayerWriteSample(
     SbPlayer player,
     SbMediaType sample_type,
+#if SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
+    const void* const* sample_buffers,
+    const int* sample_buffer_sizes,
+#else   // SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
     const void** sample_buffers,
     int* sample_buffer_sizes,
+#endif  // SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
     int number_of_sample_buffers,
     SbMediaTime sample_pts,
     const SbMediaVideoSampleInfo* video_sample_info,
diff --git a/src/starboard/raspi/shared/application_dispmanx.h b/src/starboard/raspi/shared/application_dispmanx.h
index d08c406..a3469c2 100644
--- a/src/starboard/raspi/shared/application_dispmanx.h
+++ b/src/starboard/raspi/shared/application_dispmanx.h
@@ -61,6 +61,11 @@
   Event* WaitForSystemEventWithTimeout(SbTime duration) SB_OVERRIDE;
   void WakeSystemEventWait() SB_OVERRIDE;
 
+#if SB_API_VERSION >= SB_PRELOAD_API_VERSION
+  bool IsStartImmediate() SB_OVERRIDE { return !HasPreloadSwitch(); }
+  bool IsPreloadImmediate() SB_OVERRIDE { return HasPreloadSwitch(); }
+#endif  // SB_API_VERSION >= SB_PRELOAD_API_VERSION
+
  private:
   // Returns whether DISPMANX has been initialized.
   bool IsDispmanxInitialized() { return display_ != NULL; }
diff --git a/src/starboard/raspi/shared/gyp_configuration.gypi b/src/starboard/raspi/shared/gyp_configuration.gypi
index 1e1f4cf..5123449 100644
--- a/src/starboard/raspi/shared/gyp_configuration.gypi
+++ b/src/starboard/raspi/shared/gyp_configuration.gypi
@@ -122,7 +122,6 @@
       '-lEGL',
       '-lGLESv2',
       '-lpthread',
-      '-lpulse',
       '-lrt',
       '-lopenmaxil',
       '-lbcm_host',
diff --git a/src/starboard/raspi/shared/open_max/video_decoder.cc b/src/starboard/raspi/shared/open_max/video_decoder.cc
index f0e3909..7c96b7d 100644
--- a/src/starboard/raspi/shared/open_max/video_decoder.cc
+++ b/src/starboard/raspi/shared/open_max/video_decoder.cc
@@ -67,7 +67,9 @@
   SB_DCHECK(SbThreadIsValid(thread_));
 }
 
-void VideoDecoder::WriteInputBuffer(const InputBuffer& input_buffer) {
+void VideoDecoder::WriteInputBuffer(
+    const scoped_refptr<InputBuffer>& input_buffer) {
+  SB_DCHECK(input_buffer);
   SB_DCHECK(host_ != NULL);
 
   queue_.Put(new Event(input_buffer));
@@ -133,7 +135,7 @@
 
   component.Start();
 
-  InputBuffer current_buffer;
+  scoped_refptr<InputBuffer> current_buffer;
   int offset = 0;
 
   for (;;) {
@@ -158,13 +160,13 @@
       filled_buffers_.push(buffer);
     }
 
-    if (current_buffer.is_valid()) {
-      int size = static_cast<int>(current_buffer.size());
+    if (current_buffer) {
+      int size = static_cast<int>(current_buffer->size());
       while (offset < size) {
         int written = component.WriteData(
-            current_buffer.data() + offset, size - offset,
+            current_buffer->data() + offset, size - offset,
             OpenMaxComponent::kDataNonEOS,
-            current_buffer.pts() * kSbTimeSecond / kSbMediaTimeSecond);
+            current_buffer->pts() * kSbTimeSecond / kSbMediaTimeSecond);
         SB_DCHECK(written >= 0);
         offset += written;
         if (written == 0) {
@@ -172,7 +174,7 @@
         }
       }
       if (offset == size) {
-        current_buffer = InputBuffer();
+        current_buffer = NULL;
         offset = 0;
       } else {
         SbThreadSleep(kSbTimeMillisecond);
diff --git a/src/starboard/raspi/shared/open_max/video_decoder.h b/src/starboard/raspi/shared/open_max/video_decoder.h
index fa950fe..444d778 100644
--- a/src/starboard/raspi/shared/open_max/video_decoder.h
+++ b/src/starboard/raspi/shared/open_max/video_decoder.h
@@ -17,6 +17,7 @@
 
 #include <queue>
 
+#include "starboard/common/ref_counted.h"
 #include "starboard/log.h"
 #include "starboard/media.h"
 #include "starboard/mutex.h"
@@ -46,7 +47,8 @@
   ~VideoDecoder() SB_OVERRIDE;
 
   void SetHost(Host* host) SB_OVERRIDE;
-  void WriteInputBuffer(const InputBuffer& input_buffer) SB_OVERRIDE;
+  void WriteInputBuffer(const scoped_refptr<InputBuffer>& input_buffer)
+      SB_OVERRIDE;
   void WriteEndOfStream() SB_OVERRIDE;
   void Reset() SB_OVERRIDE;
 
@@ -56,11 +58,11 @@
     explicit Event(const Type type) : type(type) {
       SB_DCHECK(type != kWriteInputBuffer);
     }
-    explicit Event(const InputBuffer& input_buffer)
+    explicit Event(const scoped_refptr<InputBuffer>& input_buffer)
         : type(kWriteInputBuffer), input_buffer(input_buffer) {}
 
     Type type;
-    InputBuffer input_buffer;
+    scoped_refptr<InputBuffer> input_buffer;
   };
 
   bool TryToDeliverOneFrame();
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
index 16bc1c5..12531ab 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
@@ -70,9 +70,10 @@
   output_cb_ = output_cb;
 }
 
-void AudioDecoder::Decode(const InputBuffer& input_buffer,
+void AudioDecoder::Decode(const scoped_refptr<InputBuffer>& input_buffer,
                           const Closure& consumed_cb) {
   SB_DCHECK(BelongsToCurrentThread());
+  SB_DCHECK(input_buffer);
   SB_DCHECK(output_cb_.is_valid());
   SB_CHECK(codec_context_ != NULL);
 
@@ -85,17 +86,17 @@
 
   AVPacket packet;
   av_init_packet(&packet);
-  packet.data = const_cast<uint8_t*>(input_buffer.data());
-  packet.size = input_buffer.size();
+  packet.data = const_cast<uint8_t*>(input_buffer->data());
+  packet.size = input_buffer->size();
 
   avcodec_get_frame_defaults(av_frame_);
   int frame_decoded = 0;
   int result =
       avcodec_decode_audio4(codec_context_, av_frame_, &frame_decoded, &packet);
-  if (result != input_buffer.size() || frame_decoded != 1) {
+  if (result != input_buffer->size() || frame_decoded != 1) {
     // TODO: Consider fill it with silence.
     SB_DLOG(WARNING) << "avcodec_decode_audio4() failed with result: " << result
-                     << " with input buffer size: " << input_buffer.size()
+                     << " with input buffer size: " << input_buffer->size()
                      << " and frame decoded: " << frame_decoded;
     return;
   }
@@ -108,7 +109,7 @@
   if (decoded_audio_size > 0) {
     scoped_refptr<DecodedAudio> decoded_audio = new DecodedAudio(
         codec_context_->channels, GetSampleType(), GetStorageType(),
-        input_buffer.pts(),
+        input_buffer->pts(),
         codec_context_->channels * av_frame_->nb_samples *
             starboard::media::GetBytesPerSample(GetSampleType()));
     if (GetStorageType() == kSbMediaAudioFrameStorageTypeInterleaved) {
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h
index 40bd9c8..7cc62fd 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h
+++ b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h
@@ -17,6 +17,7 @@
 
 #include <queue>
 
+#include "starboard/common/ref_counted.h"
 #include "starboard/media.h"
 #include "starboard/shared/ffmpeg/ffmpeg_common.h"
 #include "starboard/shared/internal_only.h"
@@ -37,7 +38,7 @@
   ~AudioDecoder() SB_OVERRIDE;
 
   void Initialize(const Closure& output_cb) SB_OVERRIDE;
-  void Decode(const InputBuffer& input_buffer,
+  void Decode(const scoped_refptr<InputBuffer>& input_buffer,
               const Closure& consumed_cb) SB_OVERRIDE;
   void WriteEndOfStream() SB_OVERRIDE;
   scoped_refptr<DecodedAudio> Read() SB_OVERRIDE;
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
index 98a8680..5c08757 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
@@ -125,7 +125,9 @@
   host_ = host;
 }
 
-void VideoDecoder::WriteInputBuffer(const InputBuffer& input_buffer) {
+void VideoDecoder::WriteInputBuffer(
+    const scoped_refptr<InputBuffer>& input_buffer) {
+  SB_DCHECK(input_buffer);
   SB_DCHECK(queue_.Poll().type == kInvalid);
   SB_DCHECK(host_ != NULL);
 
@@ -194,9 +196,9 @@
       // Send |input_buffer| to ffmpeg and try to decode one frame.
       AVPacket packet;
       av_init_packet(&packet);
-      packet.data = const_cast<uint8_t*>(event.input_buffer.data());
-      packet.size = event.input_buffer.size();
-      packet.pts = event.input_buffer.pts();
+      packet.data = const_cast<uint8_t*>(event.input_buffer->data());
+      packet.size = event.input_buffer->size();
+      packet.pts = event.input_buffer->pts();
       codec_context_->reordered_opaque = packet.pts;
 
       DecodePacket(&packet);
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.h b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.h
index 3daf19e..a89e8f9 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.h
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.h
@@ -15,6 +15,7 @@
 #ifndef STARBOARD_SHARED_FFMPEG_FFMPEG_VIDEO_DECODER_H_
 #define STARBOARD_SHARED_FFMPEG_FFMPEG_VIDEO_DECODER_H_
 
+#include "starboard/common/ref_counted.h"
 #include "starboard/log.h"
 #include "starboard/media.h"
 #include "starboard/queue.h"
@@ -41,7 +42,8 @@
   ~VideoDecoder() SB_OVERRIDE;
 
   void SetHost(Host* host) SB_OVERRIDE;
-  void WriteInputBuffer(const InputBuffer& input_buffer) SB_OVERRIDE;
+  void WriteInputBuffer(const scoped_refptr<InputBuffer>& input_buffer)
+      SB_OVERRIDE;
   void WriteEndOfStream() SB_OVERRIDE;
   void Reset() SB_OVERRIDE;
 
@@ -58,13 +60,13 @@
   struct Event {
     EventType type;
     // |input_buffer| is only used when |type| is kWriteInputBuffer.
-    InputBuffer input_buffer;
+    scoped_refptr<InputBuffer> input_buffer;
 
     explicit Event(EventType type = kInvalid) : type(type) {
       SB_DCHECK(type != kWriteInputBuffer);
     }
 
-    explicit Event(InputBuffer input_buffer)
+    explicit Event(const scoped_refptr<InputBuffer>& input_buffer)
         : type(kWriteInputBuffer), input_buffer(input_buffer) {}
   };
 
diff --git a/src/starboard/shared/libvpx/vpx_video_decoder.cc b/src/starboard/shared/libvpx/vpx_video_decoder.cc
index 14727f9..d6dbf97 100644
--- a/src/starboard/shared/libvpx/vpx_video_decoder.cc
+++ b/src/starboard/shared/libvpx/vpx_video_decoder.cc
@@ -49,7 +49,9 @@
   host_ = host;
 }
 
-void VideoDecoder::WriteInputBuffer(const InputBuffer& input_buffer) {
+void VideoDecoder::WriteInputBuffer(
+    const scoped_refptr<InputBuffer>& input_buffer) {
+  SB_DCHECK(input_buffer);
   SB_DCHECK(queue_.Poll().type == kInvalid);
   SB_DCHECK(host_ != NULL);
 
@@ -171,8 +173,10 @@
   }
 }
 
-void VideoDecoder::DecodeOneBuffer(const InputBuffer& input_buffer) {
-  const SbMediaVideoSampleInfo* sample_info = input_buffer.video_sample_info();
+void VideoDecoder::DecodeOneBuffer(
+    const scoped_refptr<InputBuffer>& input_buffer) {
+  SB_DCHECK(input_buffer);
+  const SbMediaVideoSampleInfo* sample_info = input_buffer->video_sample_info();
   SB_DCHECK(sample_info);
   if (!context_ || sample_info->frame_width != current_frame_width_ ||
       sample_info->frame_height != current_frame_height_) {
@@ -184,9 +188,9 @@
 
   SB_DCHECK(context_);
 
-  SbMediaTime pts = input_buffer.pts();
-  vpx_codec_err_t status = vpx_codec_decode(context_.get(), input_buffer.data(),
-                                            input_buffer.size(), &pts, 0);
+  SbMediaTime pts = input_buffer->pts();
+  vpx_codec_err_t status = vpx_codec_decode(
+      context_.get(), input_buffer->data(), input_buffer->size(), &pts, 0);
   if (status != VPX_CODEC_OK) {
     SB_DLOG(ERROR) << "vpx_codec_decode() failed, status=" << status;
     ReportError();
diff --git a/src/starboard/shared/libvpx/vpx_video_decoder.h b/src/starboard/shared/libvpx/vpx_video_decoder.h
index 50b39ce..9eb2f5a 100644
--- a/src/starboard/shared/libvpx/vpx_video_decoder.h
+++ b/src/starboard/shared/libvpx/vpx_video_decoder.h
@@ -15,6 +15,7 @@
 #ifndef STARBOARD_SHARED_LIBVPX_VPX_VIDEO_DECODER_H_
 #define STARBOARD_SHARED_LIBVPX_VPX_VIDEO_DECODER_H_
 
+#include "starboard/common/ref_counted.h"
 #include "starboard/log.h"
 #include "starboard/media.h"
 #include "starboard/queue.h"
@@ -44,7 +45,8 @@
   ~VideoDecoder() SB_OVERRIDE;
 
   void SetHost(Host* host) SB_OVERRIDE;
-  void WriteInputBuffer(const InputBuffer& input_buffer) SB_OVERRIDE;
+  void WriteInputBuffer(const scoped_refptr<InputBuffer>& input_buffer)
+      SB_OVERRIDE;
   void WriteEndOfStream() SB_OVERRIDE;
   void Reset() SB_OVERRIDE;
 
@@ -59,13 +61,13 @@
   struct Event {
     EventType type;
     // |input_buffer| is only used when |type| is kWriteInputBuffer.
-    InputBuffer input_buffer;
+    scoped_refptr<InputBuffer> input_buffer;
 
     explicit Event(EventType type = kInvalid) : type(type) {
       SB_DCHECK(type != kWriteInputBuffer);
     }
 
-    explicit Event(InputBuffer input_buffer)
+    explicit Event(const scoped_refptr<InputBuffer>& input_buffer)
         : type(kWriteInputBuffer), input_buffer(input_buffer) {}
   };
 
@@ -79,7 +81,7 @@
   // thread is not running.
   void InitializeCodec();
   void TeardownCodec();
-  void DecodeOneBuffer(const InputBuffer& input_buffer);
+  void DecodeOneBuffer(const scoped_refptr<InputBuffer>& input_buffer);
 
   SbDecodeTarget GetCurrentDecodeTarget() SB_OVERRIDE;
 
diff --git a/src/starboard/shared/media_session/playback_state.h b/src/starboard/shared/media_session/playback_state.h
new file mode 100644
index 0000000..feeed87
--- /dev/null
+++ b/src/starboard/shared/media_session/playback_state.h
@@ -0,0 +1,30 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_SHARED_MEDIA_SESSION_PLAYBACK_STATE_H_
+#define STARBOARD_SHARED_MEDIA_SESSION_PLAYBACK_STATE_H_
+
+namespace starboard {
+namespace shared {
+namespace media_session {
+
+enum PlaybackState { kPlaying = 0, kPaused = 1, kNone = 2 };
+
+void UpdateActiveSessionPlatformPlaybackState(PlaybackState state);
+
+}  // namespace media_session
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_MEDIA_SESSION_PLAYBACK_STATE_H_
diff --git a/src/starboard/shared/media_session/stub_playback_state.cc b/src/starboard/shared/media_session/stub_playback_state.cc
new file mode 100644
index 0000000..e4ae5bf
--- /dev/null
+++ b/src/starboard/shared/media_session/stub_playback_state.cc
@@ -0,0 +1,30 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/log.h"
+
+#include "starboard/shared/media_session/playback_state.h"
+
+namespace starboard {
+namespace shared {
+namespace media_session {
+
+void UpdateActiveSessionPlatformPlaybackState(PlaybackState state) {
+  SB_UNREFERENCED_PARAMETER(state);
+  SB_NOTIMPLEMENTED();
+}
+
+}  // namespace media_session
+}  // namespace shared
+}  // namespace starboard
diff --git a/src/starboard/shared/starboard/application.cc b/src/starboard/shared/starboard/application.cc
index 1a4bf89..194adc1 100644
--- a/src/starboard/shared/starboard/application.cc
+++ b/src/starboard/shared/starboard/application.cc
@@ -14,6 +14,8 @@
 
 #include "starboard/shared/starboard/application.h"
 
+#include <string>
+
 #include "starboard/atomic.h"
 #include "starboard/common/scoped_ptr.h"
 #include "starboard/condition_variable.h"
@@ -31,6 +33,7 @@
 namespace {
 
 const char kPreloadSwitch[] = "preload";
+const char kLinkSwitch[] = "link";
 
 // Dispatches an event of |type| with |data| to the system event handler,
 // calling |destructor| on |data| when finished dispatching. Does all
@@ -63,6 +66,7 @@
           reinterpret_cast<SbAtomicPtr>(reinterpret_cast<void*>(NULL)),
           reinterpret_cast<SbAtomicPtr>(this)));
   SB_DCHECK(!old_instance);
+  SB_UNREFERENCED_PARAMETER(old_instance);
 }
 
 Application::~Application() {
@@ -76,24 +80,27 @@
   SbMemoryDeallocate(start_link_);
 }
 
+int Application::Run(int argc, char** argv, const char* link_data) {
+  Initialize();
+  command_line_.reset(new CommandLine(argc, argv));
+  if (link_data) {
+    SetStartLink(link_data);
+  }
+
+  return RunLoop();
+}
+
 int Application::Run(int argc, char** argv) {
   Initialize();
   command_line_.reset(new CommandLine(argc, argv));
-  if (IsPreloadImmediate()) {
-    DispatchPreload();
-  } else if (IsStartImmediate()) {
-    DispatchStart();
-  }
-
-  for (;;) {
-    if (!DispatchNextEvent()) {
-      break;
+  if (command_line_->HasSwitch(kLinkSwitch)) {
+    std::string value = command_line_->GetSwitchValue(kLinkSwitch);
+    if (!value.empty()) {
+      SetStartLink(value.c_str());
     }
   }
 
-  CallTeardownCallbacks();
-  Teardown();
-  return error_level_;
+  return RunLoop();
 }
 
 CommandLine* Application::GetCommandLine() {
@@ -122,6 +129,12 @@
   Inject(event);
 }
 
+void Application::Link(const char *link_data) {
+  SB_DCHECK(link_data) << "You must call Link with link_data.";
+  Inject(new Event(kSbEventTypeLink, SbStringDuplicate(link_data),
+                   SbMemoryDeallocate));
+}
+
 SbEventId Application::Schedule(SbEventCallback callback,
                                 void* context,
                                 SbTimeMonotonic delay) {
@@ -336,6 +349,25 @@
   return new Event(type, start_data, &DeleteDestructor<SbEventStartData>);
 }
 
+int Application::RunLoop() {
+  SB_DCHECK(command_line_);
+  if (IsPreloadImmediate()) {
+    DispatchPreload();
+  } else if (IsStartImmediate()) {
+    DispatchStart();
+  }
+
+  for (;;) {
+    if (!DispatchNextEvent()) {
+      break;
+    }
+  }
+
+  CallTeardownCallbacks();
+  Teardown();
+  return error_level_;
+}
+
 }  // namespace starboard
 }  // namespace shared
 }  // namespace starboard
diff --git a/src/starboard/shared/starboard/application.h b/src/starboard/shared/starboard/application.h
index c70bcfb..2d1569d 100644
--- a/src/starboard/shared/starboard/application.h
+++ b/src/starboard/shared/starboard/application.h
@@ -155,6 +155,7 @@
   // Runs the application with the current thread as the Main Starboard Thread,
   // blocking until application exit. This method will dispatch all appropriate
   // initialization and teardown events. Returns the resulting error level.
+  int Run(int argc, char** argv, const char* link_data);
   int Run(int argc, char** argv);
 
   // Retrieves the CommandLine for the application.
@@ -202,6 +203,12 @@
   // appropriate for the current state. May be called from an external thread.
   void Stop(int error_level);
 
+  // Injects a link event to the application with the given |link_data|, which
+  // must be a null-terminated string. Makes a copy of |link_data|, so it only
+  // has to live over the lifetime of the call to Link. May be called from an
+  // external thread.
+  void Link(const char* link_data);
+
   // Schedules an event into the event queue.  May be called from an external
   // thread.
   SbEventId Schedule(SbEventCallback callback,
@@ -357,6 +364,9 @@
   // command line and deep link.
   Event* CreateInitialEvent(SbEventType type);
 
+  // Internal workhorse of the main run loop.
+  int RunLoop();
+
   // The single application instance.
   static Application* g_instance;
 
diff --git a/src/starboard/shared/starboard/localized_strings.cc b/src/starboard/shared/starboard/localized_strings.cc
index e25e5af..ec68964 100644
--- a/src/starboard/shared/starboard/localized_strings.cc
+++ b/src/starboard/shared/starboard/localized_strings.cc
@@ -71,7 +71,7 @@
   char* buffer_pos = buffer;
   while (bytes_to_read > 0) {
     int max_bytes_to_read = static_cast<int>(
-        std::min(static_cast<int64_t>(kSbInt32Min), bytes_to_read));
+        std::min(static_cast<int64_t>(kSbInt32Max), bytes_to_read));
     int bytes_read = file.Read(buffer_pos, max_bytes_to_read);
     if (bytes_read < 0) {
       SB_DLOG(ERROR) << "Read from i18n file failed.";
diff --git a/src/starboard/shared/starboard/media/mime_type_test.cc b/src/starboard/shared/starboard/media/mime_type_test.cc
index e8847d7..6a9fe7a 100644
--- a/src/starboard/shared/starboard/media/mime_type_test.cc
+++ b/src/starboard/shared/starboard/media/mime_type_test.cc
@@ -198,8 +198,8 @@
 
 TEST(MimeTypeTest, GetParamFloatValueWithIndex) {
   MimeType mime_type("video/mp4; name0=123; name1=123.4");
-  EXPECT_FLOAT_EQ(123., mime_type.GetParamFloatValue(0));
-  EXPECT_FLOAT_EQ(123.4, mime_type.GetParamFloatValue(1));
+  EXPECT_FLOAT_EQ(123.f, mime_type.GetParamFloatValue(0));
+  EXPECT_FLOAT_EQ(123.4f, mime_type.GetParamFloatValue(1));
 }
 
 TEST(MimeTypeTest, GetParamStringValueWithIndex) {
diff --git a/src/starboard/shared/starboard/player/closure.h b/src/starboard/shared/starboard/player/closure.h
index 96e2b4e..3ae7bae 100644
--- a/src/starboard/shared/starboard/player/closure.h
+++ b/src/starboard/shared/starboard/player/closure.h
@@ -117,6 +117,23 @@
   return Closure(new FunctorImpl(func, obj, param));
 }
 
+template <typename C, typename Param>
+inline Closure Bind(void (C::*func)(const Param&), C* obj, const Param& param) {
+  class FunctorImpl : public Closure::Functor {
+   public:
+    FunctorImpl(void (C::*func)(const Param&), C* obj, const Param& param)
+        : func_(func), obj_(obj), param_(param) {}
+
+    void Run() SB_OVERRIDE { ((*obj_).*func_)(param_); }
+
+   private:
+    void (C::*func_)(const Param&);
+    C* obj_;
+    Param param_;
+  };
+  return Closure(new FunctorImpl(func, obj, param));
+}
+
 template <typename C, typename Param1, typename Param2>
 inline Closure Bind(void (C::*func)(Param1, Param2),
                     C* obj,
diff --git a/src/starboard/shared/starboard/player/filter/audio_decoder_internal.h b/src/starboard/shared/starboard/player/filter/audio_decoder_internal.h
index dadbe57..f3159e6 100644
--- a/src/starboard/shared/starboard/player/filter/audio_decoder_internal.h
+++ b/src/starboard/shared/starboard/player/filter/audio_decoder_internal.h
@@ -15,8 +15,7 @@
 #ifndef STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_AUDIO_DECODER_INTERNAL_H_
 #define STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_AUDIO_DECODER_INTERNAL_H_
 
-#include <vector>
-
+#include "starboard/common/ref_counted.h"
 #include "starboard/media.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/player/closure.h"
@@ -52,7 +51,7 @@
   // |consumed_cb|.
   // Note that |consumed_cb| is always called asynchronously on the calling job
   // queue.
-  virtual void Decode(const InputBuffer& input_buffer,
+  virtual void Decode(const scoped_refptr<InputBuffer>& input_buffer,
                       const Closure& consumed_cb) = 0;
 
   // Notice the object that there is no more input data unless Reset() is
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
index 29fc319..598f725 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
@@ -115,12 +115,14 @@
   }
 }
 
-void AudioRendererImpl::WriteSample(const InputBuffer& input_buffer) {
+void AudioRendererImpl::WriteSample(
+    const scoped_refptr<InputBuffer>& input_buffer) {
   SB_DCHECK(BelongsToCurrentThread());
+  SB_DCHECK(input_buffer);
   SB_DCHECK(can_accept_more_data_);
 
   if (eos_state_.load() >= kEOSWrittenToDecoder) {
-    SB_LOG(ERROR) << "Appending audio sample at " << input_buffer.pts()
+    SB_LOG(ERROR) << "Appending audio sample at " << input_buffer->pts()
                   << " after EOS reached.";
     return;
   }
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
index f908fd8..d9278da 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
@@ -52,7 +52,7 @@
                     const SbMediaAudioHeader& audio_header);
   ~AudioRendererImpl() SB_OVERRIDE;
 
-  void WriteSample(const InputBuffer& input_buffer) SB_OVERRIDE;
+  void WriteSample(const scoped_refptr<InputBuffer>& input_buffer) SB_OVERRIDE;
   void WriteEndOfStream() SB_OVERRIDE;
 
   void Play() SB_OVERRIDE;
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal_test.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal_test.cc
index 5737d57..517c3ef 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal_test.cc
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal_test.cc
@@ -71,11 +71,11 @@
                               GetDefaultAudioHeader()));
   }
 
-  void WriteSample(InputBuffer input_buffer) {
-    ASSERT_TRUE(input_buffer.is_valid());
+  void WriteSample(const scoped_refptr<InputBuffer>& input_buffer) {
+    ASSERT_TRUE(input_buffer != NULL);
     ASSERT_FALSE(consumed_cb_.is_valid());
 
-    buffers_in_decoder_.insert(input_buffer.data());
+    buffers_in_decoder_.insert(input_buffer->data());
     EXPECT_CALL(*audio_decoder_, Decode(input_buffer, _))
         .WillOnce(SaveArg<1>(&consumed_cb_));
     audio_renderer_->WriteSample(input_buffer);
@@ -111,11 +111,11 @@
     job_queue_.RunUntilIdle();
   }
 
-  InputBuffer CreateInputBuffer(SbMediaTime pts) {
+  scoped_refptr<InputBuffer> CreateInputBuffer(SbMediaTime pts) {
     const int kInputBufferSize = 4;
-    return InputBuffer(kSbMediaTypeAudio, DeallocateSampleCB, NULL, this,
-                       SbMemoryAllocate(kInputBufferSize), kInputBufferSize,
-                       pts, NULL, NULL);
+    return new InputBuffer(kSbMediaTypeAudio, DeallocateSampleCB, NULL, this,
+                           SbMemoryAllocate(kInputBufferSize), kInputBufferSize,
+                           pts, NULL, NULL);
   }
 
   scoped_refptr<DecodedAudio> CreateDecodedAudio(SbMediaTime pts, int frames) {
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h
index ccb12a7..1c192c1 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h
@@ -15,8 +15,7 @@
 #ifndef STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_AUDIO_RENDERER_INTERNAL_H_
 #define STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_AUDIO_RENDERER_INTERNAL_H_
 
-#include <vector>
-
+#include "starboard/common/ref_counted.h"
 #include "starboard/media.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
@@ -32,7 +31,7 @@
  public:
   virtual ~AudioRenderer() {}
 
-  virtual void WriteSample(const InputBuffer& input_buffer) = 0;
+  virtual void WriteSample(const scoped_refptr<InputBuffer>& input_buffer) = 0;
   virtual void WriteEndOfStream() = 0;
   virtual void Play() = 0;
   virtual void Pause() = 0;
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
index 556c96c..a57c6ac 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
@@ -160,8 +160,10 @@
   return true;
 }
 
-bool FilterBasedPlayerWorkerHandler::WriteSample(InputBuffer input_buffer,
-                                                 bool* written) {
+bool FilterBasedPlayerWorkerHandler::WriteSample(
+    const scoped_refptr<InputBuffer>& input_buffer,
+    bool* written) {
+  SB_DCHECK(input_buffer);
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
   SB_DCHECK(written != NULL);
 
@@ -171,7 +173,7 @@
 
   *written = true;
 
-  if (input_buffer.sample_type() == kSbMediaTypeAudio) {
+  if (input_buffer->sample_type() == kSbMediaTypeAudio) {
     if (audio_renderer_->IsEndOfStreamWritten()) {
       SB_LOG(WARNING) << "Try to write audio sample after EOS is reached";
     } else {
@@ -180,11 +182,11 @@
         return true;
       }
 
-      if (input_buffer.drm_info()) {
+      if (input_buffer->drm_info()) {
         if (!SbDrmSystemIsValid(drm_system_)) {
           return false;
         }
-        if (drm_system_->Decrypt(&input_buffer) == SbDrmSystemPrivate::kRetry) {
+        if (drm_system_->Decrypt(input_buffer) == SbDrmSystemPrivate::kRetry) {
           *written = false;
           return true;
         }
@@ -192,7 +194,7 @@
       audio_renderer_->WriteSample(input_buffer);
     }
   } else {
-    SB_DCHECK(input_buffer.sample_type() == kSbMediaTypeVideo);
+    SB_DCHECK(input_buffer->sample_type() == kSbMediaTypeVideo);
     if (video_renderer_->IsEndOfStreamWritten()) {
       SB_LOG(WARNING) << "Try to write video sample after EOS is reached";
     } else {
@@ -200,11 +202,11 @@
         *written = false;
         return true;
       }
-      if (input_buffer.drm_info()) {
+      if (input_buffer->drm_info()) {
         if (!SbDrmSystemIsValid(drm_system_)) {
           return false;
         }
-        if (drm_system_->Decrypt(&input_buffer) == SbDrmSystemPrivate::kRetry) {
+        if (drm_system_->Decrypt(input_buffer) == SbDrmSystemPrivate::kRetry) {
           *written = false;
           return true;
         }
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
index 610c4e1..0ec1a3d 100644
--- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
+++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
@@ -60,7 +60,8 @@
             GetPlayerStateCB get_player_state_cb,
             UpdatePlayerStateCB update_player_state_cb) SB_OVERRIDE;
   bool Seek(SbMediaTime seek_to_pts, int ticket) SB_OVERRIDE;
-  bool WriteSample(InputBuffer input_buffer, bool* written) SB_OVERRIDE;
+  bool WriteSample(const scoped_refptr<InputBuffer>& input_buffer,
+                   bool* written) SB_OVERRIDE;
   bool WriteEndOfStream(SbMediaType sample_type) SB_OVERRIDE;
   bool SetPause(bool pause) SB_OVERRIDE;
 #if SB_API_VERSION >= 4
diff --git a/src/starboard/shared/starboard/player/filter/mock_audio_decoder.h b/src/starboard/shared/starboard/player/filter/mock_audio_decoder.h
index d1726c2..4558d8e 100644
--- a/src/starboard/shared/starboard/player/filter/mock_audio_decoder.h
+++ b/src/starboard/shared/starboard/player/filter/mock_audio_decoder.h
@@ -19,6 +19,7 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 
+#include "starboard/common/ref_counted.h"
 #include "starboard/media.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/player/closure.h"
@@ -43,7 +44,7 @@
         samples_per_second_(sample_per_second) {}
 
   MOCK_METHOD1(Initialize, void(const Closure&));
-  MOCK_METHOD2(Decode, void(const InputBuffer&, const Closure&));
+  MOCK_METHOD2(Decode, void(const scoped_refptr<InputBuffer>&, const Closure&));
   MOCK_METHOD0(WriteEndOfStream, void());
   MOCK_METHOD0(Read, scoped_refptr<DecodedAudio>());
   MOCK_METHOD0(Reset, void());
diff --git a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
index 0d3728d..f4bc6f6 100644
--- a/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
+++ b/src/starboard/shared/starboard/player/filter/stub_player_components_impl.cc
@@ -12,12 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "starboard/shared/starboard/player/filter/player_components.h"
-
 #include <queue>
 
+#include "starboard/common/ref_counted.h"
+#include "starboard/log.h"
 #include "starboard/shared/starboard/player/closure.h"
 #include "starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h"
+#include "starboard/shared/starboard/player/filter/player_components.h"
 #include "starboard/shared/starboard/player/filter/video_renderer_impl_internal.h"
 #include "starboard/shared/starboard/player/job_queue.h"
 
@@ -40,17 +41,21 @@
 
 }  // namespace
 
-class StubAudioDecoder : public AudioDecoder, JobQueue::JobOwner {
+class StubAudioDecoder : public AudioDecoder, private JobQueue::JobOwner {
  public:
   explicit StubAudioDecoder(const SbMediaAudioHeader& audio_header)
       : sample_type_(GetSupportedSampleType()),
         audio_header_(audio_header),
         stream_ended_(false) {}
+
   void Initialize(const Closure& output_cb) SB_OVERRIDE {
     output_cb_ = output_cb;
   }
-  void Decode(const InputBuffer& input_buffer,
+
+  void Decode(const scoped_refptr<InputBuffer>& input_buffer,
               const Closure& consumed_cb) SB_OVERRIDE {
+    SB_DCHECK(input_buffer);
+
     // Values to represent what kind of dummy audio to fill the decoded audio
     // we produce with.
     enum FillType {
@@ -60,13 +65,18 @@
     // Can be set locally to fill with different types.
     const FillType fill_type = kSilence;
 
-    if (last_input_buffer_.is_valid()) {
-      SbMediaTime diff = input_buffer.pts() - last_input_buffer_.pts();
+    if (last_input_buffer_) {
+      SbMediaTime diff = input_buffer->pts() - last_input_buffer_->pts();
+      SB_DCHECK(diff >= 0);
       size_t sample_size =
           GetSampleType() == kSbMediaAudioSampleTypeInt16 ? 2 : 4;
       size_t size = diff * GetSamplesPerSecond() * sample_size *
                     audio_header_.number_of_channels / kSbMediaTimeSecond;
-      decoded_audios_.push(new DecodedAudio(input_buffer.pts(), size));
+      size += size % (sample_size * audio_header_.number_of_channels);
+
+      decoded_audios_.push(new DecodedAudio(audio_header_.number_of_channels,
+                                            GetSampleType(), GetStorageType(),
+                                            input_buffer->pts(), size));
 
       if (fill_type == kSilence) {
         SbMemorySet(decoded_audios_.back()->buffer(), 0, size);
@@ -83,22 +93,31 @@
           }
         }
       }
+      Schedule(output_cb_);
     }
-    last_input_buffer_ = input_buffer;
     Schedule(consumed_cb);
-    Schedule(output_cb_);
+    last_input_buffer_ = input_buffer;
   }
+
   void WriteEndOfStream() SB_OVERRIDE {
-    if (last_input_buffer_.is_valid()) {
+    if (last_input_buffer_) {
       // There won't be a next pts, so just guess that the decoded size is
       // 4 times the encoded size.
-      decoded_audios_.push(new DecodedAudio(last_input_buffer_.pts(),
-                                            4 * last_input_buffer_.size()));
+      size_t fake_size = 4 * last_input_buffer_->size();
+      size_t sample_size =
+          GetSampleType() == kSbMediaAudioSampleTypeInt16 ? 2 : 4;
+      fake_size += fake_size % (sample_size * audio_header_.number_of_channels);
+
+      decoded_audios_.push(new DecodedAudio(
+          audio_header_.number_of_channels, GetSampleType(), GetStorageType(),
+          last_input_buffer_->pts(), fake_size));
+      Schedule(output_cb_);
     }
     decoded_audios_.push(new DecodedAudio());
     stream_ended_ = true;
     Schedule(output_cb_);
   }
+
   scoped_refptr<DecodedAudio> Read() SB_OVERRIDE {
     scoped_refptr<DecodedAudio> result;
     if (!decoded_audios_.empty()) {
@@ -107,43 +126,44 @@
     }
     return result;
   }
+
   void Reset() SB_OVERRIDE {
     while (!decoded_audios_.empty()) {
       decoded_audios_.pop();
     }
     stream_ended_ = false;
-    last_input_buffer_ = InputBuffer();
+    last_input_buffer_ = NULL;
 
     CancelPendingJobs();
   }
   SbMediaAudioSampleType GetSampleType() const SB_OVERRIDE {
     return sample_type_;
   }
+  SbMediaAudioFrameStorageType GetStorageType() const SB_OVERRIDE {
+    return kSbMediaAudioFrameStorageTypeInterleaved;
+  }
   int GetSamplesPerSecond() const SB_OVERRIDE {
     return audio_header_.samples_per_second;
   }
-  bool CanAcceptMoreData() const SB_OVERRIDE {
-    return !stream_ended_ && decoded_audios_.size() <= kMaxDecodedAudiosSize;
-  }
 
  private:
-  static const kMaxDecodedAudiosSize = 64;
-
   Closure output_cb_;
   SbMediaAudioSampleType sample_type_;
   SbMediaAudioHeader audio_header_;
   bool stream_ended_;
   std::queue<scoped_refptr<DecodedAudio> > decoded_audios_;
-  InputBuffer last_input_buffer_;
+  scoped_refptr<InputBuffer> last_input_buffer_;
 };
 
 class StubVideoDecoder : public HostedVideoDecoder {
  public:
   StubVideoDecoder() : host_(NULL) {}
-  void WriteInputBuffer(const InputBuffer& input_buffer) SB_OVERRIDE {
+  void WriteInputBuffer(const scoped_refptr<InputBuffer>& input_buffer)
+      SB_OVERRIDE {
+    SB_DCHECK(input_buffer);
     SB_DCHECK(host_ != NULL);
     host_->OnDecoderStatusUpdate(
-        kNeedMoreInput, VideoFrame::CreateEmptyFrame(input_buffer.pts()));
+        kNeedMoreInput, VideoFrame::CreateEmptyFrame(input_buffer->pts()));
   }
   void WriteEndOfStream() SB_OVERRIDE {
     SB_DCHECK(host_ != NULL);
@@ -177,8 +197,7 @@
       new StubAudioDecoder(audio_parameters.audio_header);
   StubVideoDecoder* video_decoder = new StubVideoDecoder();
   AudioRendererImpl* audio_renderer =
-      new AudioRendererImpl(audio_parameters.job_queue,
-                            scoped_ptr<AudioDecoder>(audio_decoder).Pass(),
+      new AudioRendererImpl(scoped_ptr<AudioDecoder>(audio_decoder).Pass(),
                             audio_parameters.audio_header);
   VideoRendererImpl* video_renderer = new VideoRendererImpl(
       scoped_ptr<HostedVideoDecoder>(video_decoder).Pass());
diff --git a/src/starboard/shared/starboard/player/filter/video_decoder_internal.h b/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
index 6dcce32..a8c8952 100644
--- a/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_decoder_internal.h
@@ -15,6 +15,7 @@
 #ifndef STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_VIDEO_DECODER_INTERNAL_H_
 #define STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_VIDEO_DECODER_INTERNAL_H_
 
+#include "starboard/common/ref_counted.h"
 #include "starboard/player.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/player/input_buffer_internal.h"
@@ -35,7 +36,8 @@
   virtual ~VideoDecoder() {}
 
   // Send encoded video frame stored in |input_buffer| to decode.
-  virtual void WriteInputBuffer(const InputBuffer& input_buffer) = 0;
+  virtual void WriteInputBuffer(
+      const scoped_refptr<InputBuffer>& input_buffer) = 0;
   // Note that there won't be more input data unless Reset() is called.
   // OnDecoderStatusUpdate will still be called on Host during flushing until
   // the |frame| is an EOS frame.
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc
index fb8e940..ffd6aca 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc
@@ -34,11 +34,13 @@
   decoder_->SetHost(this);
 }
 
-void VideoRendererImpl::WriteSample(const InputBuffer& input_buffer) {
+void VideoRendererImpl::WriteSample(
+    const scoped_refptr<InputBuffer>& input_buffer) {
   SB_DCHECK(thread_checker_.CalledOnValidThread());
+  SB_DCHECK(input_buffer);
 
   if (end_of_stream_written_) {
-    SB_LOG(ERROR) << "Appending video sample at " << input_buffer.pts()
+    SB_LOG(ERROR) << "Appending video sample at " << input_buffer->pts()
                   << " after EOS reached.";
     return;
   }
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h
index e0ca1a2..b40365e 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h
@@ -17,7 +17,7 @@
 
 #include <list>
 
-#include "starboard/common/scoped_ptr.h"
+#include "starboard/common/ref_counted.h"
 #include "starboard/log.h"
 #include "starboard/media.h"
 #include "starboard/mutex.h"
@@ -44,7 +44,7 @@
 
   int GetDroppedFrames() const SB_OVERRIDE { return dropped_frames_; }
 
-  void WriteSample(const InputBuffer& input_buffer) SB_OVERRIDE;
+  void WriteSample(const scoped_refptr<InputBuffer>& input_buffer) SB_OVERRIDE;
   void WriteEndOfStream() SB_OVERRIDE;
 
   void Seek(SbMediaTime seek_to_pts) SB_OVERRIDE;
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_internal.h b/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
index df3beef..cffa6de 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_internal.h
@@ -15,7 +15,7 @@
 #ifndef STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_VIDEO_RENDERER_INTERNAL_H_
 #define STARBOARD_SHARED_STARBOARD_PLAYER_FILTER_VIDEO_RENDERER_INTERNAL_H_
 
-#include "starboard/common/scoped_ptr.h"
+#include "starboard/common/ref_counted.h"
 #include "starboard/log.h"
 #include "starboard/media.h"
 #include "starboard/mutex.h"
@@ -36,7 +36,7 @@
   virtual ~VideoRenderer() {}
 
   virtual int GetDroppedFrames() const = 0;
-  virtual void WriteSample(const InputBuffer& input_buffer) = 0;
+  virtual void WriteSample(const scoped_refptr<InputBuffer>& input_buffer) = 0;
   virtual void WriteEndOfStream() = 0;
   virtual void Seek(SbMediaTime seek_to_pts) = 0;
   virtual scoped_refptr<VideoFrame> GetCurrentFrame(SbMediaTime media_time) = 0;
diff --git a/src/starboard/shared/starboard/player/input_buffer_internal.cc b/src/starboard/shared/starboard/player/input_buffer_internal.cc
index 9c44224..968f002 100644
--- a/src/starboard/shared/starboard/player/input_buffer_internal.cc
+++ b/src/starboard/shared/starboard/player/input_buffer_internal.cc
@@ -15,9 +15,7 @@
 #include "starboard/shared/starboard/player/input_buffer_internal.h"
 
 #include <numeric>
-#include <vector>
 
-#include "starboard/atomic.h"
 #include "starboard/log.h"
 #include "starboard/memory.h"
 
@@ -26,171 +24,6 @@
 namespace starboard {
 namespace player {
 
-class InputBuffer::ReferenceCountedBuffer {
- public:
-  ReferenceCountedBuffer(SbMediaType sample_type,
-                         SbPlayerDeallocateSampleFunc deallocate_sample_func,
-                         SbPlayer player,
-                         void* context,
-                         const void* sample_buffer,
-                         int sample_buffer_size,
-                         SbMediaTime sample_pts,
-                         const SbMediaVideoSampleInfo* video_sample_info,
-                         const SbDrmSampleInfo* sample_drm_info)
-      : ref_count_(0),
-        sample_type_(sample_type),
-        deallocate_sample_func_(deallocate_sample_func),
-        player_(player),
-        context_(context),
-        data_(static_cast<const uint8_t*>(sample_buffer)),
-        size_(sample_buffer_size),
-        pts_(sample_pts) {
-    SB_DCHECK(deallocate_sample_func);
-    TryToAssignVideoSampleInfo(video_sample_info);
-    TryToAssignDrmSampleInfo(sample_drm_info);
-  }
-
-  ReferenceCountedBuffer(SbMediaType sample_type,
-                         SbPlayerDeallocateSampleFunc deallocate_sample_func,
-                         SbPlayer player,
-                         void* context,
-                         const void** sample_buffers,
-                         int* sample_buffer_sizes,
-                         int number_of_sample_buffers,
-                         SbMediaTime sample_pts,
-                         const SbMediaVideoSampleInfo* video_sample_info,
-                         const SbDrmSampleInfo* sample_drm_info)
-      : ref_count_(0),
-        sample_type_(sample_type),
-        deallocate_sample_func_(deallocate_sample_func),
-        player_(player),
-        context_(context),
-        pts_(sample_pts) {
-    SB_DCHECK(deallocate_sample_func);
-    SB_DCHECK(number_of_sample_buffers > 0);
-
-    TryToAssignVideoSampleInfo(video_sample_info);
-    TryToAssignDrmSampleInfo(sample_drm_info);
-
-    if (number_of_sample_buffers == 1) {
-      data_ = static_cast<const uint8_t*>(sample_buffers[0]);
-      size_ = sample_buffer_sizes[0];
-    } else if (number_of_sample_buffers > 1) {
-      // TODO: This simply concatenating multi-part buffers into one large
-      // buffer.  It serves the purpose to test the Cobalt media code work with
-      // multi-part sample buffer but we should proper implement InputBuffer to
-      // ensure that the concatenating of multi-part buffers is handled inside
-      // the renderers or the decoders so the SbPlayer implementation won't use
-      // too much memory.
-      size_ =
-          std::accumulate(sample_buffer_sizes,
-                          sample_buffer_sizes + number_of_sample_buffers, 0);
-      flattened_data_.reserve(size_);
-      for (int i = 0; i < number_of_sample_buffers; ++i) {
-        const uint8_t* data = static_cast<const uint8_t*>(sample_buffers[i]);
-        flattened_data_.insert(flattened_data_.end(), data,
-                               data + sample_buffer_sizes[i]);
-      }
-      DeallocateSampleBuffer(sample_buffers[0]);
-      data_ = flattened_data_.data();
-    }
-  }
-
-  void AddRef() const { SbAtomicBarrier_Increment(&ref_count_, 1); }
-  void Release() const {
-    if (SbAtomicBarrier_Increment(&ref_count_, -1) == 0) {
-      delete this;
-    }
-  }
-
-  SbMediaType sample_type() const { return sample_type_; }
-  const uint8_t* data() const { return data_; }
-  int size() const { return size_; }
-  SbMediaTime pts() const { return pts_; }
-  const SbMediaVideoSampleInfo* video_sample_info() const {
-    return has_video_sample_info_ ? &video_sample_info_ : NULL;
-  }
-  const SbDrmSampleInfo* drm_info() const {
-    return has_drm_info_ ? &drm_info_ : NULL;
-  }
-  void SetDecryptedContent(const void* buffer, int size) {
-    SB_DCHECK(size == size_);
-    DeallocateSampleBuffer(data_);
-
-    if (size > 0) {
-      flattened_data_.resize(size);
-      SbMemoryCopy(flattened_data_.data(), buffer, size);
-      data_ = flattened_data_.data();
-    } else {
-      data_ = NULL;
-    }
-    size_ = size;
-    has_drm_info_ = false;
-  }
-
- private:
-  ~ReferenceCountedBuffer() { DeallocateSampleBuffer(data_); }
-
-  void TryToAssignVideoSampleInfo(
-      const SbMediaVideoSampleInfo* video_sample_info) {
-    has_video_sample_info_ = video_sample_info != NULL;
-
-    if (!has_video_sample_info_) {
-      return;
-    }
-
-    video_sample_info_ = *video_sample_info;
-    if (video_sample_info_.color_metadata) {
-      color_metadata_ = *video_sample_info_.color_metadata;
-      video_sample_info_.color_metadata = &color_metadata_;
-    } else {
-      video_sample_info_.color_metadata = NULL;
-    }
-  }
-  void TryToAssignDrmSampleInfo(const SbDrmSampleInfo* sample_drm_info) {
-    has_drm_info_ = sample_drm_info != NULL;
-
-    if (!has_drm_info_) {
-      return;
-    }
-
-    SB_DCHECK(sample_drm_info->subsample_count > 0);
-
-    subsamples_.assign(
-        sample_drm_info->subsample_mapping,
-        sample_drm_info->subsample_mapping + sample_drm_info->subsample_count);
-    drm_info_ = *sample_drm_info;
-    drm_info_.subsample_mapping = subsamples_.empty() ? NULL : &subsamples_[0];
-  }
-
-  void DeallocateSampleBuffer(const void* buffer) {
-    if (deallocate_sample_func_) {
-      deallocate_sample_func_(player_, context_, buffer);
-      deallocate_sample_func_ = NULL;
-    }
-  }
-
-  mutable SbAtomic32 ref_count_;
-  SbMediaType sample_type_;
-  SbPlayerDeallocateSampleFunc deallocate_sample_func_;
-  SbPlayer player_;
-  void* context_;
-  const uint8_t* data_;
-  int size_;
-  SbMediaTime pts_;
-  bool has_video_sample_info_;
-  SbMediaColorMetadata color_metadata_;
-  SbMediaVideoSampleInfo video_sample_info_;
-  bool has_drm_info_;
-  SbDrmSampleInfo drm_info_;
-  std::vector<uint8_t> flattened_data_;
-  std::vector<SbDrmSubSampleMapping> subsamples_;
-
-  SB_DISALLOW_COPY_AND_ASSIGN(ReferenceCountedBuffer);
-};
-
-InputBuffer::InputBuffer() : buffer_(NULL) {}
-
 InputBuffer::InputBuffer(SbMediaType sample_type,
                          SbPlayerDeallocateSampleFunc deallocate_sample_func,
                          SbPlayer player,
@@ -199,107 +32,121 @@
                          int sample_buffer_size,
                          SbMediaTime sample_pts,
                          const SbMediaVideoSampleInfo* video_sample_info,
-                         const SbDrmSampleInfo* sample_drm_info) {
-  buffer_ = new ReferenceCountedBuffer(
-      sample_type, deallocate_sample_func, player, context, sample_buffer,
-      sample_buffer_size, sample_pts, video_sample_info, sample_drm_info);
-  buffer_->AddRef();
+                         const SbDrmSampleInfo* sample_drm_info)
+    : sample_type_(sample_type),
+      deallocate_sample_func_(deallocate_sample_func),
+      player_(player),
+      context_(context),
+      data_(static_cast<const uint8_t*>(sample_buffer)),
+      size_(sample_buffer_size),
+      pts_(sample_pts) {
+  SB_DCHECK(deallocate_sample_func);
+  TryToAssignVideoSampleInfo(video_sample_info);
+  TryToAssignDrmSampleInfo(sample_drm_info);
 }
 
 InputBuffer::InputBuffer(SbMediaType sample_type,
                          SbPlayerDeallocateSampleFunc deallocate_sample_func,
                          SbPlayer player,
                          void* context,
-                         const void** sample_buffers,
-                         int* sample_buffer_sizes,
+                         const void* const* sample_buffers,
+                         const int* sample_buffer_sizes,
                          int number_of_sample_buffers,
                          SbMediaTime sample_pts,
                          const SbMediaVideoSampleInfo* video_sample_info,
-                         const SbDrmSampleInfo* sample_drm_info) {
-  buffer_ = new ReferenceCountedBuffer(
-      sample_type, deallocate_sample_func, player, context, sample_buffers,
-      sample_buffer_sizes, number_of_sample_buffers, sample_pts,
-      video_sample_info, sample_drm_info);
-  buffer_->AddRef();
-}
+                         const SbDrmSampleInfo* sample_drm_info)
+    : sample_type_(sample_type),
+      deallocate_sample_func_(deallocate_sample_func),
+      player_(player),
+      context_(context),
+      pts_(sample_pts) {
+  SB_DCHECK(deallocate_sample_func);
+  SB_DCHECK(number_of_sample_buffers > 0);
 
-InputBuffer::InputBuffer(const InputBuffer& that) {
-  buffer_ = that.buffer_;
-  if (buffer_) {
-    buffer_->AddRef();
+  TryToAssignVideoSampleInfo(video_sample_info);
+  TryToAssignDrmSampleInfo(sample_drm_info);
+
+  if (number_of_sample_buffers == 1) {
+    data_ = static_cast<const uint8_t*>(sample_buffers[0]);
+    size_ = sample_buffer_sizes[0];
+  } else if (number_of_sample_buffers > 1) {
+    // TODO: This simply concatenating multi-part buffers into one large
+    // buffer.  It serves the purpose to test the Cobalt media code work with
+    // multi-part sample buffer but we should proper implement InputBuffer to
+    // ensure that the concatenating of multi-part buffers is handled inside
+    // the renderers or the decoders so the SbPlayer implementation won't use
+    // too much memory.
+    size_ = std::accumulate(sample_buffer_sizes,
+                            sample_buffer_sizes + number_of_sample_buffers, 0);
+    flattened_data_.reserve(size_);
+    for (int i = 0; i < number_of_sample_buffers; ++i) {
+      const uint8_t* data = static_cast<const uint8_t*>(sample_buffers[i]);
+      flattened_data_.insert(flattened_data_.end(), data,
+                             data + sample_buffer_sizes[i]);
+    }
+    DeallocateSampleBuffer(sample_buffers[0]);
+    data_ = flattened_data_.data();
   }
 }
 
 InputBuffer::~InputBuffer() {
-  reset();
-}
-
-InputBuffer& InputBuffer::operator=(const InputBuffer& that) {
-  if (that.buffer_) {
-    that.buffer_->AddRef();
-  }
-  if (buffer_) {
-    buffer_->Release();
-  }
-  buffer_ = that.buffer_;
-
-  return *this;
-}
-
-void InputBuffer::reset() {
-  if (buffer_) {
-    buffer_->Release();
-    buffer_ = NULL;
-  }
-}
-
-SbMediaType InputBuffer::sample_type() const {
-  SB_DCHECK(buffer_);
-  return buffer_->sample_type();
-}
-
-const uint8_t* InputBuffer::data() const {
-  SB_DCHECK(buffer_);
-  return buffer_->data();
-}
-
-int InputBuffer::size() const {
-  SB_DCHECK(buffer_);
-  return buffer_->size();
-}
-
-SbMediaTime InputBuffer::pts() const {
-  SB_DCHECK(buffer_);
-  return buffer_->pts();
-}
-
-const SbMediaVideoSampleInfo* InputBuffer::video_sample_info() const {
-  SB_DCHECK(buffer_);
-  return buffer_->video_sample_info();
-}
-
-const SbDrmSampleInfo* InputBuffer::drm_info() const {
-  SB_DCHECK(buffer_);
-  return buffer_->drm_info();
+  DeallocateSampleBuffer(data_);
 }
 
 void InputBuffer::SetDecryptedContent(const void* buffer, int size) {
-  SB_DCHECK(buffer_);
-  buffer_->SetDecryptedContent(buffer, size);
+  SB_DCHECK(size == size_);
+  DeallocateSampleBuffer(data_);
+
+  if (size > 0) {
+    flattened_data_.resize(size);
+    SbMemoryCopy(flattened_data_.data(), buffer, size);
+    data_ = flattened_data_.data();
+  } else {
+    data_ = NULL;
+  }
+  size_ = size;
+  has_drm_info_ = false;
 }
 
-bool operator==(const InputBuffer& lhs, const InputBuffer& rhs) {
-  if (!lhs.is_valid() && !rhs.is_valid()) {
-    return true;
-  }
-  if (lhs.is_valid() && rhs.is_valid()) {
-    return lhs.sample_type() == rhs.sample_type() && lhs.data() == rhs.data() &&
-           lhs.size() == rhs.size() && lhs.pts() == rhs.pts() &&
-           lhs.video_sample_info() == rhs.video_sample_info() &&
-           lhs.drm_info() == rhs.drm_info();
+void InputBuffer::TryToAssignVideoSampleInfo(
+    const SbMediaVideoSampleInfo* video_sample_info) {
+  has_video_sample_info_ = video_sample_info != NULL;
+
+  if (!has_video_sample_info_) {
+    return;
   }
 
-  return false;
+  video_sample_info_ = *video_sample_info;
+  if (video_sample_info_.color_metadata) {
+    color_metadata_ = *video_sample_info_.color_metadata;
+    video_sample_info_.color_metadata = &color_metadata_;
+  } else {
+    video_sample_info_.color_metadata = NULL;
+  }
+}
+
+void InputBuffer::TryToAssignDrmSampleInfo(
+    const SbDrmSampleInfo* sample_drm_info) {
+  has_drm_info_ = sample_drm_info != NULL;
+
+  if (!has_drm_info_) {
+    return;
+  }
+
+  SB_DCHECK(sample_drm_info->subsample_count > 0);
+
+  subsamples_.assign(
+      sample_drm_info->subsample_mapping,
+      sample_drm_info->subsample_mapping + sample_drm_info->subsample_count);
+  drm_info_ = *sample_drm_info;
+  drm_info_.subsample_mapping = subsamples_.empty() ? NULL : &subsamples_[0];
+}
+
+void InputBuffer::DeallocateSampleBuffer(const void* buffer) {
+  if (deallocate_sample_func_) {
+    deallocate_sample_func_(player_, context_, buffer);
+    deallocate_sample_func_ = NULL;
+  }
 }
 
 }  // namespace player
diff --git a/src/starboard/shared/starboard/player/input_buffer_internal.h b/src/starboard/shared/starboard/player/input_buffer_internal.h
index 5c45e78..05ca16a 100644
--- a/src/starboard/shared/starboard/player/input_buffer_internal.h
+++ b/src/starboard/shared/starboard/player/input_buffer_internal.h
@@ -15,6 +15,9 @@
 #ifndef STARBOARD_SHARED_STARBOARD_PLAYER_INPUT_BUFFER_INTERNAL_H_
 #define STARBOARD_SHARED_STARBOARD_PLAYER_INPUT_BUFFER_INTERNAL_H_
 
+#include <vector>
+
+#include "starboard/common/ref_counted.h"
 #include "starboard/drm.h"
 #include "starboard/media.h"
 #include "starboard/player.h"
@@ -25,14 +28,9 @@
 namespace starboard {
 namespace player {
 
-// This class encapsulate a media buffer.  It holds a reference-counted object
-// internally to ensure that the object of this class can be copied while the
-// underlying resources allocated is properly managed.
-// Note that pass this class as const reference doesn't guarantee that the
-// content of the internal buffer won't be changed.
-class InputBuffer {
+// This class encapsulate a media buffer.
+class InputBuffer : public RefCountedThreadSafe<InputBuffer> {
  public:
-  InputBuffer();
   InputBuffer(SbMediaType sample_type,
               SbPlayerDeallocateSampleFunc deallocate_sample_func,
               SbPlayer player,
@@ -46,36 +44,50 @@
               SbPlayerDeallocateSampleFunc deallocate_sample_func,
               SbPlayer player,
               void* context,
-              const void** sample_buffers,
-              int* sample_buffer_sizes,
+              const void* const* sample_buffers,
+              const int* sample_buffer_sizes,
               int number_of_sample_buffers,
               SbMediaTime sample_pts,
               const SbMediaVideoSampleInfo* video_sample_info,
               const SbDrmSampleInfo* sample_drm_info);
-  InputBuffer(const InputBuffer& that);
   ~InputBuffer();
 
-  InputBuffer& operator=(const InputBuffer& that);
-
-  bool is_valid() const { return buffer_ != NULL; }
-  void reset();
-
-  SbMediaType sample_type() const;
-  const uint8_t* data() const;
-  int size() const;
-  SbMediaTime pts() const;
-  const SbMediaVideoSampleInfo* video_sample_info() const;
-  const SbDrmSampleInfo* drm_info() const;
+  SbMediaType sample_type() const { return sample_type_; }
+  const uint8_t* data() const { return data_; }
+  int size() const { return size_; }
+  SbMediaTime pts() const { return pts_; }
+  const SbMediaVideoSampleInfo* video_sample_info() const {
+    return has_video_sample_info_ ? &video_sample_info_ : NULL;
+  }
+  const SbDrmSampleInfo* drm_info() const {
+    return has_drm_info_ ? &drm_info_ : NULL;
+  }
   void SetDecryptedContent(const void* buffer, int size);
 
  private:
-  class ReferenceCountedBuffer;
+  void TryToAssignVideoSampleInfo(
+      const SbMediaVideoSampleInfo* video_sample_info);
+  void TryToAssignDrmSampleInfo(const SbDrmSampleInfo* sample_drm_info);
+  void DeallocateSampleBuffer(const void* buffer);
 
-  ReferenceCountedBuffer* buffer_;
+  SbMediaType sample_type_;
+  SbPlayerDeallocateSampleFunc deallocate_sample_func_;
+  SbPlayer player_;
+  void* context_;
+  const uint8_t* data_;
+  int size_;
+  SbMediaTime pts_;
+  bool has_video_sample_info_;
+  SbMediaColorMetadata color_metadata_;
+  SbMediaVideoSampleInfo video_sample_info_;
+  bool has_drm_info_;
+  SbDrmSampleInfo drm_info_;
+  std::vector<uint8_t> flattened_data_;
+  std::vector<SbDrmSubSampleMapping> subsamples_;
+
+  SB_DISALLOW_COPY_AND_ASSIGN(InputBuffer);
 };
 
-bool operator==(const InputBuffer& lhs, const InputBuffer& rhs);
-
 }  // namespace player
 }  // namespace starboard
 }  // namespace shared
diff --git a/src/starboard/shared/starboard/player/player_create.cc b/src/starboard/shared/starboard/player/player_create.cc
index 5c83020..25dfe9b 100644
--- a/src/starboard/shared/starboard/player/player_create.cc
+++ b/src/starboard/shared/starboard/player/player_create.cc
@@ -17,6 +17,7 @@
 #include "starboard/configuration.h"
 #include "starboard/decode_target.h"
 #include "starboard/log.h"
+#include "starboard/shared/media_session/playback_state.h"
 #if SB_API_VERSION >= 4
 #include "starboard/shared/starboard/media/media_support_internal.h"
 #endif  // SB_API_VERSION >= 4
@@ -24,6 +25,9 @@
 #include "starboard/shared/starboard/player/player_internal.h"
 #include "starboard/shared/starboard/player/player_worker.h"
 
+using starboard::shared::media_session::
+    UpdateActiveSessionPlatformPlaybackState;
+using starboard::shared::media_session::kPlaying;
 using starboard::shared::starboard::player::filter::
     FilterBasedPlayerWorkerHandler;
 using starboard::shared::starboard::player::PlayerWorker;
@@ -89,6 +93,8 @@
   }
 #endif  // SB_API_VERSION >= 4
 
+  UpdateActiveSessionPlatformPlaybackState(kPlaying);
+
 #if SB_API_VERSION >= 4
   starboard::scoped_ptr<PlayerWorker::Handler> handler(
       new FilterBasedPlayerWorkerHandler(video_codec, audio_codec, drm_system,
diff --git a/src/starboard/shared/starboard/player/player_destroy.cc b/src/starboard/shared/starboard/player/player_destroy.cc
index a0f9947..e1ed31a 100644
--- a/src/starboard/shared/starboard/player/player_destroy.cc
+++ b/src/starboard/shared/starboard/player/player_destroy.cc
@@ -14,11 +14,17 @@
 
 #include "starboard/player.h"
 
+#include "starboard/shared/media_session/playback_state.h"
 #include "starboard/shared/starboard/player/player_internal.h"
 
+using starboard::shared::media_session::kNone;
+using starboard::shared::media_session::
+    UpdateActiveSessionPlatformPlaybackState;
+
 void SbPlayerDestroy(SbPlayer player) {
   if (!SbPlayerIsValid(player)) {
     return;
   }
+  UpdateActiveSessionPlatformPlaybackState(kNone);
   delete player;
 }
diff --git a/src/starboard/shared/starboard/player/player_internal.cc b/src/starboard/shared/starboard/player/player_internal.cc
index 5fe32f8..20268ea 100644
--- a/src/starboard/shared/starboard/player/player_internal.cc
+++ b/src/starboard/shared/starboard/player/player_internal.cc
@@ -72,8 +72,8 @@
 
 void SbPlayerPrivate::WriteSample(
     SbMediaType sample_type,
-    const void** sample_buffers,
-    int* sample_buffer_sizes,
+    const void* const* sample_buffers,
+    const int* sample_buffer_sizes,
     int number_of_sample_buffers,
     SbMediaTime sample_pts,
     const SbMediaVideoSampleInfo* video_sample_info,
@@ -81,10 +81,10 @@
   if (sample_type == kSbMediaTypeVideo) {
     ++total_video_frames_;
   }
-  InputBuffer input_buffer(sample_type, sample_deallocate_func_, this, context_,
-                           sample_buffers, sample_buffer_sizes,
-                           number_of_sample_buffers, sample_pts,
-                           video_sample_info, sample_drm_info);
+  starboard::scoped_refptr<InputBuffer> input_buffer = new InputBuffer(
+      sample_type, sample_deallocate_func_, this, context_, sample_buffers,
+      sample_buffer_sizes, number_of_sample_buffers, sample_pts,
+      video_sample_info, sample_drm_info);
   worker_->WriteSample(input_buffer);
 }
 
diff --git a/src/starboard/shared/starboard/player/player_internal.h b/src/starboard/shared/starboard/player/player_internal.h
index 6eb3d4b..fdb3d09 100644
--- a/src/starboard/shared/starboard/player/player_internal.h
+++ b/src/starboard/shared/starboard/player/player_internal.h
@@ -39,8 +39,8 @@
 
   void Seek(SbMediaTime seek_to_pts, int ticket);
   void WriteSample(SbMediaType sample_type,
-                   const void** sample_buffers,
-                   int* sample_buffer_sizes,
+                   const void* const* sample_buffers,
+                   const int* sample_buffer_sizes,
                    int number_of_sample_buffers,
                    SbMediaTime sample_pts,
                    const SbMediaVideoSampleInfo* video_sample_info,
diff --git a/src/starboard/shared/starboard/player/player_set_playback_rate.cc b/src/starboard/shared/starboard/player/player_set_playback_rate.cc
index 7928293..aaf96d1 100644
--- a/src/starboard/shared/starboard/player/player_set_playback_rate.cc
+++ b/src/starboard/shared/starboard/player/player_set_playback_rate.cc
@@ -15,8 +15,14 @@
 #include "starboard/player.h"
 
 #include "starboard/log.h"
+#include "starboard/shared/media_session/playback_state.h"
 #include "starboard/shared/starboard/player/player_internal.h"
 
+using starboard::shared::media_session::kPaused;
+using starboard::shared::media_session::kPlaying;
+using starboard::shared::media_session::
+    UpdateActiveSessionPlatformPlaybackState;
+
 #if SB_API_VERSION >= 4
 
 bool SbPlayerSetPlaybackRate(SbPlayer player, double playback_rate) {
@@ -30,6 +36,8 @@
     return false;
   }
   player->SetPlaybackRate(playback_rate);
+  bool paused = (playback_rate == 0.0);
+  UpdateActiveSessionPlatformPlaybackState(paused ? kPaused : kPlaying);
   return true;
 }
 
diff --git a/src/starboard/shared/starboard/player/player_worker.cc b/src/starboard/shared/starboard/player/player_worker.cc
index b9ba48a..38a0a25 100644
--- a/src/starboard/shared/starboard/player/player_worker.cc
+++ b/src/starboard/shared/starboard/player/player_worker.cc
@@ -26,6 +26,13 @@
 
 namespace {
 
+// 8 ms is enough to ensure that DoWritePendingSamples() is called twice for
+// every frame in HFR.
+// TODO: Reduce this as there should be enough frames caches in the renderers.
+//       Also this should be configurable for platforms with very limited video
+//       backlogs.
+const SbTimeMonotonic kWritePendingSampleDelay = 8 * kSbTimeMillisecond;
+
 struct ThreadParam {
   explicit ThreadParam(PlayerWorker* player_worker)
       : condition_variable(mutex), player_worker(player_worker) {}
@@ -140,8 +147,8 @@
     job_queue_->Remove(write_pending_sample_closure_);
     write_pending_sample_closure_.reset();
   }
-  pending_audio_buffer_.reset();
-  pending_video_buffer_.reset();
+  pending_audio_buffer_ = NULL;
+  pending_video_buffer_ = NULL;
 
   if (!handler_->Seek(seek_to_pts, ticket)) {
     UpdatePlayerState(kSbPlayerStateError);
@@ -155,8 +162,10 @@
   UpdateDecoderState(kSbMediaTypeVideo, kSbPlayerDecoderStateNeedsData);
 }
 
-void PlayerWorker::DoWriteSample(InputBuffer input_buffer) {
+void PlayerWorker::DoWriteSample(
+    const scoped_refptr<InputBuffer>& input_buffer) {
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
+  SB_DCHECK(input_buffer);
 
   if (player_state_ == kSbPlayerStateInitialized ||
       player_state_ == kSbPlayerStateEndOfStream ||
@@ -167,10 +176,10 @@
     return;
   }
 
-  if (input_buffer.sample_type() == kSbMediaTypeAudio) {
-    SB_DCHECK(!pending_audio_buffer_.is_valid());
+  if (input_buffer->sample_type() == kSbMediaTypeAudio) {
+    SB_DCHECK(!pending_audio_buffer_);
   } else {
-    SB_DCHECK(!pending_video_buffer_.is_valid());
+    SB_DCHECK(!pending_video_buffer_);
   }
   bool written;
   bool result = handler_->WriteSample(input_buffer, &written);
@@ -179,10 +188,10 @@
     return;
   }
   if (written) {
-    UpdateDecoderState(input_buffer.sample_type(),
+    UpdateDecoderState(input_buffer->sample_type(),
                        kSbPlayerDecoderStateNeedsData);
   } else {
-    if (input_buffer.sample_type() == kSbMediaTypeAudio) {
+    if (input_buffer->sample_type() == kSbMediaTypeAudio) {
       pending_audio_buffer_ = input_buffer;
     } else {
       pending_video_buffer_ = input_buffer;
@@ -190,7 +199,8 @@
     if (!write_pending_sample_closure_.is_valid()) {
       write_pending_sample_closure_ =
           Bind(&PlayerWorker::DoWritePendingSamples, this);
-      job_queue_->Schedule(write_pending_sample_closure_);
+      job_queue_->Schedule(write_pending_sample_closure_,
+                           kWritePendingSampleDelay);
     }
   }
 }
@@ -200,10 +210,10 @@
   SB_DCHECK(write_pending_sample_closure_.is_valid());
   write_pending_sample_closure_.reset();
 
-  if (pending_audio_buffer_.is_valid()) {
+  if (pending_audio_buffer_) {
     DoWriteSample(common::ResetAndReturn(&pending_audio_buffer_));
   }
-  if (pending_video_buffer_.is_valid()) {
+  if (pending_video_buffer_) {
     DoWriteSample(common::ResetAndReturn(&pending_video_buffer_));
   }
 }
@@ -223,9 +233,9 @@
   }
 
   if (sample_type == kSbMediaTypeAudio) {
-    SB_DCHECK(!pending_audio_buffer_.is_valid());
+    SB_DCHECK(!pending_audio_buffer_);
   } else {
-    SB_DCHECK(!pending_video_buffer_.is_valid());
+    SB_DCHECK(!pending_video_buffer_);
   }
 
   if (!handler_->WriteEndOfStream(sample_type)) {
diff --git a/src/starboard/shared/starboard/player/player_worker.h b/src/starboard/shared/starboard/player/player_worker.h
index eeade17..a1d9333 100644
--- a/src/starboard/shared/starboard/player/player_worker.h
+++ b/src/starboard/shared/starboard/player/player_worker.h
@@ -15,6 +15,7 @@
 #ifndef STARBOARD_SHARED_STARBOARD_PLAYER_PLAYER_WORKER_H_
 #define STARBOARD_SHARED_STARBOARD_PLAYER_PLAYER_WORKER_H_
 
+#include "starboard/common/ref_counted.h"
 #include "starboard/common/scoped_ptr.h"
 #include "starboard/log.h"
 #include "starboard/media.h"
@@ -75,7 +76,8 @@
                       GetPlayerStateCB get_player_state_cb,
                       UpdatePlayerStateCB update_player_state_cb) = 0;
     virtual bool Seek(SbMediaTime seek_to_pts, int ticket) = 0;
-    virtual bool WriteSample(InputBuffer input_buffer, bool* written) = 0;
+    virtual bool WriteSample(const scoped_refptr<InputBuffer>& input_buffer,
+                             bool* written) = 0;
     virtual bool WriteEndOfStream(SbMediaType sample_type) = 0;
     virtual bool SetPause(bool pause) = 0;
 #if SB_API_VERSION >= 4
@@ -106,7 +108,7 @@
         Bind(&PlayerWorker::DoSeek, this, seek_to_pts, ticket));
   }
 
-  void WriteSample(InputBuffer input_buffer) {
+  void WriteSample(const scoped_refptr<InputBuffer>& input_buffer) {
     job_queue_->Schedule(
         Bind(&PlayerWorker::DoWriteSample, this, input_buffer));
   }
@@ -165,7 +167,7 @@
   void RunLoop();
   void DoInit();
   void DoSeek(SbMediaTime seek_to_pts, int ticket);
-  void DoWriteSample(InputBuffer input_buffer);
+  void DoWriteSample(const scoped_refptr<InputBuffer>& input_buffer);
   void DoWritePendingSamples();
   void DoWriteEndOfStream(SbMediaType sample_type);
 #if SB_API_VERSION >= 4 || SB_IS(PLAYER_PUNCHED_OUT)
@@ -192,8 +194,8 @@
   int ticket_;
 
   SbPlayerState player_state_;
-  InputBuffer pending_audio_buffer_;
-  InputBuffer pending_video_buffer_;
+  scoped_refptr<InputBuffer> pending_audio_buffer_;
+  scoped_refptr<InputBuffer> pending_video_buffer_;
   Closure write_pending_sample_closure_;
 };
 
diff --git a/src/starboard/shared/starboard/player/player_write_sample.cc b/src/starboard/shared/starboard/player/player_write_sample.cc
index a92797b..5fd3ca5 100644
--- a/src/starboard/shared/starboard/player/player_write_sample.cc
+++ b/src/starboard/shared/starboard/player/player_write_sample.cc
@@ -21,8 +21,13 @@
 
 void SbPlayerWriteSample(SbPlayer player,
                          SbMediaType sample_type,
+#if SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
+                         const void* const* sample_buffers,
+                         const int* sample_buffer_sizes,
+#else   // SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
                          const void** sample_buffers,
                          int* sample_buffer_sizes,
+#endif  // SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
                          int number_of_sample_buffers,
                          SbMediaTime sample_pts,
                          const SbMediaVideoSampleInfo* video_sample_info,
diff --git a/src/starboard/shared/stub/media_can_play_mime_and_key_system.cc b/src/starboard/shared/stub/media_can_play_mime_and_key_system.cc
index 34a9b16..f84e3dc 100644
--- a/src/starboard/shared/stub/media_can_play_mime_and_key_system.cc
+++ b/src/starboard/shared/stub/media_can_play_mime_and_key_system.cc
@@ -16,5 +16,7 @@
 
 SbMediaSupportType SbMediaCanPlayMimeAndKeySystem(const char* mime,
                                                   const char* key_system) {
+  SB_UNREFERENCED_PARAMETER(mime);
+  SB_UNREFERENCED_PARAMETER(key_system);
   return kSbMediaSupportTypeNotSupported;
 }
diff --git a/src/starboard/shared/stub/media_get_audio_configuration.cc b/src/starboard/shared/stub/media_get_audio_configuration.cc
index c2e9d8a..b28c9d1 100644
--- a/src/starboard/shared/stub/media_get_audio_configuration.cc
+++ b/src/starboard/shared/stub/media_get_audio_configuration.cc
@@ -17,5 +17,7 @@
 bool SbMediaGetAudioConfiguration(
     int output_index,
     SbMediaAudioConfiguration* out_configuration) {
+  SB_UNREFERENCED_PARAMETER(output_index);
+  SB_UNREFERENCED_PARAMETER(out_configuration);
   return false;
 }
diff --git a/src/starboard/shared/stub/player_create.cc b/src/starboard/shared/stub/player_create.cc
index 0a0bf62..a91e304 100644
--- a/src/starboard/shared/stub/player_create.cc
+++ b/src/starboard/shared/stub/player_create.cc
@@ -30,7 +30,7 @@
                         void* /*context*/
 #if SB_API_VERSION >= 4
                         ,
-                        SbPlayerOutputMode output_mode,
+                        SbPlayerOutputMode /*output_mode*/,
                         SbDecodeTargetGraphicsContextProvider* /*provider*/
 #elif SB_API_VERSION >= 3
                         ,
diff --git a/src/starboard/shared/stub/player_write_sample.cc b/src/starboard/shared/stub/player_write_sample.cc
index 1fd2d52..0450efd 100644
--- a/src/starboard/shared/stub/player_write_sample.cc
+++ b/src/starboard/shared/stub/player_write_sample.cc
@@ -18,12 +18,18 @@
 
 void SbPlayerWriteSample(SbPlayer /*player*/,
                          SbMediaType /*sample_type*/,
+#if SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
+                         const void* const* /*sample_buffers*/,
+                         const int* /*sample_buffer_sizes*/,
+#else   // SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
                          const void** /*sample_buffers*/,
                          int* /*sample_buffer_sizes*/,
+#endif  // SB_API_VERSION >= SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION
                          int /*number_of_sample_buffers*/,
                          SbMediaTime /*sample_pts*/,
                          const SbMediaVideoSampleInfo* /*video_sample_info*/,
-                         const SbDrmSampleInfo* /*sample_drm_info*/) {}
+                         const SbDrmSampleInfo* /*sample_drm_info*/) {
+}
 
 #else  // SB_API_VERSION >= 4
 
diff --git a/src/starboard/shared/uwp/application_uwp.cc b/src/starboard/shared/uwp/application_uwp.cc
index f7c44e1..6aa337e 100644
--- a/src/starboard/shared/uwp/application_uwp.cc
+++ b/src/starboard/shared/uwp/application_uwp.cc
@@ -83,7 +83,7 @@
 
 #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 
-// Parses a starboard: URI scheme by splitting args at ';' boundries.
+// Parses a starboard: URI scheme by splitting args at ';' boundaries.
 std::vector<std::string> ParseStarboardUri(const std::string& uri) {
   std::vector<std::string> result;
   result.push_back(GetArgvZero());
@@ -210,8 +210,7 @@
   App() : previously_activated_(false) {}
 
   // IFrameworkView methods.
-  virtual void Initialize(
-      CoreApplicationView^ applicationView) {
+  virtual void Initialize(CoreApplicationView^ applicationView) {
     SbAudioSinkPrivate::Initialize();
     CoreApplication::Suspending +=
         ref new EventHandler<SuspendingEventArgs^>(this, &App::OnSuspending);
@@ -313,10 +312,10 @@
       }
     } else if (args->Kind == ActivationKind::DialReceiver) {
       if (!previously_activated_) {
-        DialReceiverActivatedEventArgs ^ dial_args =
-            dynamic_cast<DialReceiverActivatedEventArgs ^>(args);
+        DialReceiverActivatedEventArgs^ dial_args =
+            dynamic_cast<DialReceiverActivatedEventArgs^>(args);
         SB_CHECK(dial_args);
-        Platform::String ^ arguments = dial_args->Arguments;
+        Platform::String^ arguments = dial_args->Arguments;
         std::string activation_args =
             kYouTubeTVurl + sbwin32::platformStringToString(arguments);
         SB_DLOG(INFO) << "Dial Activation url: " << activation_args;
@@ -558,11 +557,15 @@
   SB_CHECK(LOBYTE(wsaData.wVersion) == kWinSockVersionMajor &&
            HIBYTE(wsaData.wVersion) == kWinSockVersionMinor);
 
+  HRESULT hr = MFStartup(MF_VERSION);
+  SB_DCHECK(SUCCEEDED(hr));
+
   starboard::shared::win32::RegisterMainThread();
 
   auto direct3DApplicationSource = ref new Direct3DApplicationSource();
   CoreApplication::Run(direct3DApplicationSource);
 
+  MFShutdown();
   WSACleanup();
 
   return main_return_value;
diff --git a/src/starboard/shared/uwp/cobalt/cobalt_platform.gyp b/src/starboard/shared/uwp/cobalt/cobalt_platform.gyp
index 9da1070..e7206c0 100644
--- a/src/starboard/shared/uwp/cobalt/cobalt_platform.gyp
+++ b/src/starboard/shared/uwp/cobalt/cobalt_platform.gyp
@@ -21,8 +21,16 @@
       'target_name': 'cobalt_platform',
       'type': 'static_library',
       'sources': [
+        'xb1_media_session_client.cc',
+        'xb1_media_session_client.h',
+        'xb1_media_session_updates.cc',
+        'xb1_media_session_button_press.cc',
+        'xb1_media_session_button_press.h',
         'xhr_modify_headers.cc',
       ],
+      'dependencies': [
+        '<(DEPTH)/cobalt/media_session/media_session.gyp:media_session',
+      ],
       'msvs_settings': {
         'VCCLCompilerTool': {
           'AdditionalOptions': [
diff --git a/src/starboard/shared/uwp/window_internal.cc b/src/starboard/shared/uwp/window_internal.cc
index 0b34b01..5363628 100644
--- a/src/starboard/shared/uwp/window_internal.cc
+++ b/src/starboard/shared/uwp/window_internal.cc
@@ -25,9 +25,7 @@
 // 1080 video, but perhaps 4k UI where applicable.
 SbWindowPrivate::SbWindowPrivate(const SbWindowOptions* /*options*/)
     : width(1920),
-      height(1080),
-      output_width(1920),
-      output_height(1080) {
+      height(1080) {
   egl_native_window_ = reinterpret_cast<EGLNativeWindowType>(
       starboard::shared::uwp::ApplicationUwp::Get()->GetCoreWindow().Get());
 }
diff --git a/src/starboard/shared/uwp/window_internal.h b/src/starboard/shared/uwp/window_internal.h
index ef0777e..583774b 100644
--- a/src/starboard/shared/uwp/window_internal.h
+++ b/src/starboard/shared/uwp/window_internal.h
@@ -25,16 +25,6 @@
   explicit SbWindowPrivate(const SbWindowOptions* options);
   ~SbWindowPrivate();
 
-  // Wait for the next video out vblank event.
-  void WaitForVBlank();
-
-  // Get the process time of the latest video out vblank event.
-  SbTime GetVBlankProcessTime();
-
-  // Get the video out refresh rate with the provided pointer. Return value
-  // indicates success.
-  bool GetRefreshRate(uint64_t* refresh_rate);
-
   EGLNativeWindowType egl_native_window() const { return egl_native_window_; }
 
   // The width of this window.
@@ -43,25 +33,8 @@
   // The height of this window.
   int height;
 
-  // The actual output resolution width.
-  int output_width;
-
-  // The actual output resolution height.
-  int output_height;
-
  private:
   EGLNativeWindowType egl_native_window_;
-
-  // Open and Initialize the video output port.
-  void SetupVideo();
-
-  // Close the video output port.
-  void ShutdownVideo();
-
-  // TODO: Ensure this gets called when the output resolution may have changed,
-  // such as when resuming after suspend.
-  // Retrieve the width and height from the video output resolution.
-  void RefreshOutputResolution();
 };
 
 #endif  // STARBOARD_SHARED_UWP_WINDOW_INTERNAL_H_
diff --git a/src/starboard/starboard.gyp b/src/starboard/starboard.gyp
index c7de30b..83c284b 100644
--- a/src/starboard/starboard.gyp
+++ b/src/starboard/starboard.gyp
@@ -59,6 +59,7 @@
         'types.h',
         'user.h',
         'window.h',
+        '<(DEPTH)/starboard/shared/media_session/playback_state.h',
         # Include private headers, if present.
         '<!@(python "<(DEPTH)/starboard/tools/find_private_files.py" "<(DEPTH)" "*.h")',
       ],
diff --git a/src/starboard/stub/application_stub.cc b/src/starboard/stub/application_stub.cc
index 20614d9..c54bff5 100644
--- a/src/starboard/stub/application_stub.cc
+++ b/src/starboard/stub/application_stub.cc
@@ -42,6 +42,7 @@
 
 shared::starboard::Application::Event*
 ApplicationStub::WaitForSystemEventWithTimeout(SbTime time) {
+  SB_UNREFERENCED_PARAMETER(time);
   return NULL;
 }
 
diff --git a/src/starboard/stub/starboard_platform.gyp b/src/starboard/stub/starboard_platform.gyp
index 7dfd774..a95ca89 100644
--- a/src/starboard/stub/starboard_platform.gyp
+++ b/src/starboard/stub/starboard_platform.gyp
@@ -24,6 +24,7 @@
         '<(DEPTH)/starboard/shared/starboard/event_schedule.cc',
         '<(DEPTH)/starboard/shared/starboard/file_mode_string_to_flags.cc',
         '<(DEPTH)/starboard/shared/starboard/log_message.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/filter/stub_player_components_impl.cc',
         '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
         '<(DEPTH)/starboard/shared/stub/accessibility_get_display_settings.cc',
         '<(DEPTH)/starboard/shared/stub/accessibility_get_text_to_speech_settings.cc',
@@ -145,8 +146,8 @@
         '<(DEPTH)/starboard/shared/stub/socket_create.cc',
         '<(DEPTH)/starboard/shared/stub/socket_destroy.cc',
         '<(DEPTH)/starboard/shared/stub/socket_free_resolution.cc',
-        '<(DEPTH)/starboard/shared/stub/socket_get_last_error.cc',
         '<(DEPTH)/starboard/shared/stub/socket_get_interface_address.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_get_last_error.cc',
         '<(DEPTH)/starboard/shared/stub/socket_get_local_address.cc',
         '<(DEPTH)/starboard/shared/stub/socket_get_local_interface_address.cc',
         '<(DEPTH)/starboard/shared/stub/socket_is_connected.cc',
diff --git a/src/starboard/win/console/starboard_platform.gyp b/src/starboard/win/console/starboard_platform.gyp
index ac1558d..343eec3 100644
--- a/src/starboard/win/console/starboard_platform.gyp
+++ b/src/starboard/win/console/starboard_platform.gyp
@@ -23,12 +23,12 @@
       '../shared/system_get_path.cc',
       '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
       '<(DEPTH)/starboard/shared/starboard/queue_application.h',
+      '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc',
+      '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc',
+      '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc',
+      '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc',
       '<(DEPTH)/starboard/shared/stub/system_clear_platform_error.cc',
       '<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
-      '<(DEPTH)/starboard/shared/stub/system_request_pause.cc',
-      '<(DEPTH)/starboard/shared/stub/system_request_stop.cc',
-      '<(DEPTH)/starboard/shared/stub/system_request_suspend.cc',
-      '<(DEPTH)/starboard/shared/stub/system_request_unpause.cc',
       '<(DEPTH)/starboard/shared/stub/window_create.cc',
       '<(DEPTH)/starboard/shared/stub/window_destroy.cc',
       '<(DEPTH)/starboard/shared/stub/window_get_platform_handle.cc',
diff --git a/src/starboard/win/shared/gyp_configuration.gypi b/src/starboard/win/shared/gyp_configuration.gypi
index cee97a6..32823bc 100644
--- a/src/starboard/win/shared/gyp_configuration.gypi
+++ b/src/starboard/win/shared/gyp_configuration.gypi
@@ -161,6 +161,14 @@
              'EnableCOMDATFolding' : '2',  # OPT:ICF
            },
          },
+         'msvs_disabled_warnings': [
+           # Unreferenced argument.
+           # Often variables are only referenced in DCHECKs.
+           4100,
+           # Unreferenced variable.
+           # Often variables are only referenced in DCHECKs.
+           4189,
+         ],
        },
        'msvs_gold': {
          'inherit_from': ['gold_base', 'msvs_base'],
@@ -177,6 +185,14 @@
              'EnableCOMDATFolding' : '2',  # OPT:ICF
            },
          },
+         'msvs_disabled_warnings': [
+           # Unreferenced argument.
+           # Often variables are only referenced in DCHECKs.
+           4100,
+           # Unreferenced variable.
+           # Often variables are only referenced in DCHECKs.
+           4189,
+         ],
        },
     },
     'defines': [
@@ -224,7 +240,7 @@
         'MinimalRebuild': 'false',
 
         # Treat warnings as errors.
-        'WarnAsError': 'false',
+        'WarnAsError': 'true',
 
         # Enable some warnings, even those that are disabled by default.
         # See https://msdn.microsoft.com/en-us/library/23k5d385.aspx
@@ -234,7 +250,6 @@
           '/errorReport:none', # Don't send error reports to MS.
           '/permissive-', # Visual C++ conformance mode.
           '/FS', # Force sync PDB updates for parallel compile.
-          '/w14389', # Turn on warnings for signed/unsigned mismatch.
         ],
       },
       'VCLinkerTool': {
@@ -267,13 +282,18 @@
       # Triggers in many legitimate cases, like branching on a constant declared
       # in type traits.
       4127,
+      # 4244 (Level 2) - Implicit conversion from float to int
+      # 4244 (Level 3) - Implicit conversion from int to something smaller
+      # than int.
+      # 4244 (Level 4) - Implicit conversion of types, which may result in
+      # data loss.
+      4244,
       # Class has virtual functions, but destructor is not virtual.
       # Far less useful than in GCC because doesn't take into account the fact
       # that destructor is not public.
       4265,
-      # no function prototype given: converting '()' to '(void)'.
-      # We do not care.
-      4255,
+      # Inconsistent DLL linkage
+      4273,
       # cast truncates constant value.
       # We do not care.
       4310,
diff --git a/src/starboard/win/shared/starboard_platform.gypi b/src/starboard/win/shared/starboard_platform.gypi
index 7c80fad..7307c9a 100644
--- a/src/starboard/win/shared/starboard_platform.gypi
+++ b/src/starboard/win/shared/starboard_platform.gypi
@@ -306,8 +306,8 @@
         '__WRL_NO_DEFAULT_LIB__',
       ],
       'dependencies': [
-        'convert_i18n_data'
-      ]
+        'convert_i18n_data',
+      ],
     },
     {
       'target_name': 'convert_i18n_data',
diff --git a/src/testing/gtest.gyp b/src/testing/gtest.gyp
index 888ce5f..5cd741d 100644
--- a/src/testing/gtest.gyp
+++ b/src/testing/gtest.gyp
@@ -27,7 +27,6 @@
         'gtest/include/gtest/internal/gtest-string.h',
         'gtest/include/gtest/internal/gtest-tuple.h',
         'gtest/include/gtest/internal/gtest-type-util.h',
-        'gtest/src/gtest-all.cc',
         'gtest/src/gtest-death-test.cc',
         'gtest/src/gtest-filepath.cc',
         'gtest/src/gtest-internal-inl.h',
@@ -40,9 +39,6 @@
         'multiprocess_func_list.h',
         'platform_test.h',
       ],
-      'sources!': [
-        'gtest/src/gtest-all.cc',  # Not needed by our build.
-      ],
       'include_dirs': [
         'gtest',
         'gtest/include',
diff --git a/src/third_party/freetype2/freetype2_cobalt.gyp b/src/third_party/freetype2/freetype2_cobalt.gyp
index 1ec9f02..0381b78 100644
--- a/src/third_party/freetype2/freetype2_cobalt.gyp
+++ b/src/third_party/freetype2/freetype2_cobalt.gyp
@@ -1,68 +1,79 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.

-# Use of this source code is governed by a BSD-style license that can be

-# found in the LICENSE file.

-

-{

- 'variables': {

-    'ft2_dir': '<(DEPTH)/third_party/freetype2',

- },

- 'targets': [

-    {

-      'target_name': 'freetype2',

-      'type': 'static_library',

-      'toolsets': ['target'],

-      'sources': [

-        '<(ft2_dir)/src/autofit/autofit.c',

-        '<(ft2_dir)/src/base/ftbase.c',

-        '<(ft2_dir)/src/base/ftbbox.c',

-        '<(ft2_dir)/src/base/ftbitmap.c',

-        '<(ft2_dir)/src/base/ftfntfmt.c',

-        '<(ft2_dir)/src/base/ftfstype.c',

-        '<(ft2_dir)/src/base/ftgasp.c',

-        '<(ft2_dir)/src/base/ftglyph.c',

-        '<(ft2_dir)/src/base/ftinit.c',

-        '<(ft2_dir)/src/base/ftlcdfil.c',

-        '<(ft2_dir)/src/base/ftmm.c',

-        '<(ft2_dir)/src/base/ftstroke.c',

-        '<(ft2_dir)/src/base/ftsystem.c',

-        '<(ft2_dir)/src/base/fttype1.c',

-        '<(ft2_dir)/src/cff/cff.c',

-        '<(ft2_dir)/src/gzip/ftgzip.c',

-        '<(ft2_dir)/src/pshinter/pshinter.c',

-        '<(ft2_dir)/src/psnames/psnames.c',

-        '<(ft2_dir)/src/raster/raster.c',

-        '<(ft2_dir)/src/sfnt/sfnt.c',

-        '<(ft2_dir)/src/smooth/smooth.c',

-        '<(ft2_dir)/src/truetype/truetype.c',

-      ],

-      'defines': [

-        'FT_CONFIG_OPTION_SYSTEM_ZLIB',

-        'FT2_BUILD_LIBRARY',

-        'FT_CONFIG_CONFIG_H="ftconfig.h"',

-        'FT_CONFIG_MODULES_H="ftmodule.h"',

-        'FT_CONFIG_OPTIONS_H="ftoption.h"',

-      ],

-      'include_dirs': [

-        '<(ft2_dir)/include_cobalt',

-        '<(ft2_dir)/include',

-      ],

-      'dependencies': [

-        '<(DEPTH)/third_party/libpng/libpng.gyp:libpng',

-        '<(DEPTH)/third_party/zlib/zlib.gyp:zlib',

-      ],

-      'direct_dependent_settings': {

-        'include_dirs': [

-          '<(ft2_dir)/include_cobalt',

-          '<(ft2_dir)/include',

-        ],

-        'defines': [

-          'FT_CONFIG_OPTION_SYSTEM_ZLIB',

-          'FT_CONFIG_CONFIG_H="ftconfig.h"',

-          'FT_CONFIG_MODULES_H="ftmodule.h"',

-          'FT_CONFIG_OPTIONS_H="ftoption.h"',

-        ],

-      },

-      'msvs_disabled_warnings': [4146],

-    },

-  ], # targets

-}

+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+    'ft2_dir': '<(DEPTH)/third_party/freetype2',
+ },
+ 'targets': [
+    {
+      'target_name': 'freetype2',
+      'type': 'static_library',
+      'toolsets': ['target'],
+      'sources': [
+        '<(ft2_dir)/src/autofit/autofit.c',
+        '<(ft2_dir)/src/base/ftbase.c',
+        '<(ft2_dir)/src/base/ftbbox.c',
+        '<(ft2_dir)/src/base/ftbitmap.c',
+        '<(ft2_dir)/src/base/ftfntfmt.c',
+        '<(ft2_dir)/src/base/ftfstype.c',
+        '<(ft2_dir)/src/base/ftgasp.c',
+        '<(ft2_dir)/src/base/ftglyph.c',
+        '<(ft2_dir)/src/base/ftinit.c',
+        '<(ft2_dir)/src/base/ftlcdfil.c',
+        '<(ft2_dir)/src/base/ftmm.c',
+        '<(ft2_dir)/src/base/ftstroke.c',
+        '<(ft2_dir)/src/base/ftsystem.c',
+        '<(ft2_dir)/src/base/fttype1.c',
+        '<(ft2_dir)/src/cff/cff.c',
+        '<(ft2_dir)/src/gzip/ftgzip.c',
+        '<(ft2_dir)/src/pshinter/pshinter.c',
+        '<(ft2_dir)/src/psnames/psnames.c',
+        '<(ft2_dir)/src/raster/raster.c',
+        '<(ft2_dir)/src/sfnt/sfnt.c',
+        '<(ft2_dir)/src/smooth/smooth.c',
+        '<(ft2_dir)/src/truetype/truetype.c',
+      ],
+      'defines': [
+        'FT_CONFIG_OPTION_SYSTEM_ZLIB',
+        'FT2_BUILD_LIBRARY',
+        'FT_CONFIG_CONFIG_H="ftconfig.h"',
+        'FT_CONFIG_MODULES_H="ftmodule.h"',
+        'FT_CONFIG_OPTIONS_H="ftoption.h"',
+      ],
+      'include_dirs': [
+        '<(ft2_dir)/include_cobalt',
+        '<(ft2_dir)/include',
+      ],
+      'dependencies': [
+        '<(DEPTH)/third_party/libpng/libpng.gyp:libpng',
+        '<(DEPTH)/third_party/zlib/zlib.gyp:zlib',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '<(ft2_dir)/include_cobalt',
+          '<(ft2_dir)/include',
+        ],
+        'defines': [
+          'FT_CONFIG_OPTION_SYSTEM_ZLIB',
+          'FT_CONFIG_CONFIG_H="ftconfig.h"',
+          'FT_CONFIG_MODULES_H="ftmodule.h"',
+          'FT_CONFIG_OPTIONS_H="ftoption.h"',
+        ],
+      },
+      'msvs_disabled_warnings': [
+        # Level 1 - Formal parameter 'number' is different from declaration.
+        4028,
+        # Level 1 - Incompatible types conversion.
+        4133,
+        # Level 2 - Unary minus operator applied to unsigned type; result is
+        # still unsigned.
+        4146,
+        # Level 1 - Conversion from 'type1' to 'type2' of a greater size.
+        # Typically when 32-bit value is assigned to a 64-bit pointer value.
+        4312,
+      ],
+    },
+  ], # targets
+}
diff --git a/src/third_party/harfbuzz-ng/harfbuzz.gyp b/src/third_party/harfbuzz-ng/harfbuzz.gyp
index ae2b33c..68d9a6d 100644
--- a/src/third_party/harfbuzz-ng/harfbuzz.gyp
+++ b/src/third_party/harfbuzz-ng/harfbuzz.gyp
@@ -150,7 +150,7 @@
             #   4267: on amd64. size_t -> int, size_t -> unsigned int
             #   4334: '<<' : result of 32-bit shift implicitly converted to 64
             #       bits (was 64-bit shift intended?)
-            ['actual_target_arch=="win"', {
+            ['target_arch=="win"', {
               'msvs_disabled_warnings': [4267, 4334],
             }],
           ],
diff --git a/src/third_party/icu/icu.gyp b/src/third_party/icu/icu.gyp
index bad1c71..e89f9b7 100644
--- a/src/third_party/icu/icu.gyp
+++ b/src/third_party/icu/icu.gyp
@@ -10,16 +10,7 @@
     'use_system_icu%': 0,
     'icu_use_data_file_flag%': 0,
     'want_separate_host_toolset%': 0,
-    'conditions': [
-      # On Windows MSVS's library archive tool won't create an empty
-      # library given zero object input. Therefore we set target type as
-      # none. On other platforms use static_library.
-      ['actual_target_arch=="win"', {
-        'icudata_target_type': 'none',
-      }, {
-        'icudata_target_type': 'static_library',
-      }],
-    ],
+    'icudata_target_type': 'static_library',
   },
   'target_defaults': {
     'direct_dependent_settings': {
@@ -105,7 +96,7 @@
       'source/common',
       'source/i18n',
     ],
-    'msvs_disabled_warnings': [4005, 4068, 4355, 4996, 4267],
+    'msvs_disabled_warnings': [4005, 4068, 4244, 4355, 4996, 4267],
   },
   'conditions': [
     ['use_system_icu==0 or want_separate_host_toolset==1', {
@@ -301,18 +292,11 @@
                     '-fno-builtin-sin',
                 ],
             }],
-            ['OS=="lb_shell" or OS=="starboard"', {
+            ['OS=="starboard"', {
               'defines': [
                 'U_HAVE_NL_LANGINFO_CODESET=0',
                 'U_HAVE_NL_LANGINFO=0'
               ],
-            }],
-            ['OS=="lb_shell"', {
-              'dependencies': [
-                '<(lbshell_root)/build/projects/posix_emulation.gyp:posix_emulation',
-              ],
-            }],
-            ['OS=="starboard"', {
               'dependencies': [
                 '<(DEPTH)/starboard/starboard.gyp:starboard',
                ],
@@ -455,11 +439,6 @@
                 '-frtti',
               ],
             }],
-            ['OS=="lb_shell"', {
-              'dependencies': [
-                '<(lbshell_root)/build/projects/posix_emulation.gyp:posix_emulation',
-              ],
-            }],
             ['OS=="starboard"', {
               'dependencies': [
                 '<(DEPTH)/starboard/starboard.gyp:starboard',
diff --git a/src/third_party/libjpeg/jerror.c b/src/third_party/libjpeg/jerror.c
index 88a1434..cf7ac72 100644
--- a/src/third_party/libjpeg/jerror.c
+++ b/src/third_party/libjpeg/jerror.c
@@ -34,7 +34,7 @@
 #include "starboard/system.h"
 #define sprintf SbStringFormatUnsafeF
 // Applications should not leave the standard error handler registered.
-#define exit(x) SbSystemBreakIntoDebugger
+#define exit(x) SbSystemBreakIntoDebugger(x)
 #endif
 
 #ifndef EXIT_FAILURE		/* define exit() codes if not provided */
diff --git a/src/third_party/libpng/libpng.gyp b/src/third_party/libpng/libpng.gyp
index 2a20b6b..990cf87 100644
--- a/src/third_party/libpng/libpng.gyp
+++ b/src/third_party/libpng/libpng.gyp
@@ -60,6 +60,10 @@
           'export_dependent_settings': [
             '../zlib/zlib.gyp:zlib',
           ],
+          'msvs_disabled_warnings': [
+            # Level 1 (but documentation says 3) - incompatible type conversion.
+            4133,
+          ],
           'conditions': [
             ['OS!="win"', {'product_name': 'png'}],
             ['OS=="win"', {
diff --git a/src/third_party/libxml/libxml.gyp b/src/third_party/libxml/libxml.gyp
index a1aaadd..86fe4a4 100644
--- a/src/third_party/libxml/libxml.gyp
+++ b/src/third_party/libxml/libxml.gyp
@@ -240,6 +240,20 @@
               'src/include',
             ],
           },
+          'msvs_disabled_warnings': [
+            # Disable unimportant 'unused variable' warning.
+            # signed/unsigned comparison.
+            4018,
+            # TODO(jschuh): http://crbug.com/167187 size_t -> int
+            4267,
+            # TODO(brucedawson): http://crbug.com/554200 fix C4311 warnings
+            # C4311 is a VS 2015 64-bit warning for pointer truncation
+            4311,
+            # Conversion from long (possibly 32-bit) to void*
+            4312,
+            # Uninitialized local variable used.
+            4700
+          ],
           'conditions': [
             ['OS=="starboard" or OS=="lb_shell"', {
               'dependencies!': [
@@ -260,22 +274,11 @@
             # in chrome. On linux, this is picked up by transitivity from
             # pkg-config output from build/linux/system.gyp.
             ['OS=="mac" or OS=="android"', {'defines': ['_REENTRANT']}],
-            ['OS=="win"', {
+            ['target_arch=="win"', {
               'product_name': 'libxml2',
-              # Disable unimportant 'unused variable' warning.
-              # TODO(jschuh): http://crbug.com/167187 size_t -> int
-              # TODO(brucedawson): http://crbug.com/554200 fix C4311 warnings
-              # C4311 is a VS 2015 64-bit warning for pointer truncation
-              'msvs_disabled_warnings': [ 4018, 4267, 4311, ],
             }, {  # else: OS!="win"
               'product_name': 'xml2',
             }],
-            ['actual_target_arch=="win"', {
-              # For Cobalt on Windows
-              # 4018 - signed/unsigned comparison.
-              # 4700 - uninitialized local variable used.
-              'msvs_disabled_warnings': [ 4018, 4700 ],
-            }],
             ['clang == 1', {
               'cflags': [
                 # libxml passes `const unsigned char*` through `const char*`.
diff --git a/src/third_party/mozjs-45/mozjs-45.gyp b/src/third_party/mozjs-45/mozjs-45.gyp
index 3cd5233..f331e80 100644
--- a/src/third_party/mozjs-45/mozjs-45.gyp
+++ b/src/third_party/mozjs-45/mozjs-45.gyp
@@ -104,7 +104,7 @@
       }],
 
       # TODO: Remove once ps4 configuration todos are addressed.
-      ['target_arch == "ps4" or actual_target_arch == "ps4" or sb_target_platform == "ps4"', {
+      ['target_arch == "ps4" or sb_target_platform == "ps4"', {
         'common_defines': [
           'JS_CPU_X64=1',
           'JS_CODEGEN_X64=1',
@@ -185,7 +185,7 @@
           ],
         }],
         # TODO: Remove "* == ps4" once ps4 configuration todos are addressed.
-        ['target_arch == "x64" or target_arch == "ps4" or actual_target_arch == "ps4" or sb_target_platform == "ps4"', {
+        ['target_arch == "x64" or target_arch == "ps4" or sb_target_platform == "ps4"', {
           'sources': [
             'js/src/jit/x64/Assembler-x64.cpp',
             'js/src/jit/x64/Bailouts-x64.cpp',
diff --git a/src/third_party/mozjs/mozjs.gyp b/src/third_party/mozjs/mozjs.gyp
index 0de26f2..9ba6a4b 100644
--- a/src/third_party/mozjs/mozjs.gyp
+++ b/src/third_party/mozjs/mozjs.gyp
@@ -42,10 +42,16 @@
     'msvs_disabled_warnings': [
       # Level 2, Typename first seen as 'type1', but then seen as 'type2'.
       4099,
+      # Level 1 - Conversion from 'type1' to 'type2' of a greater size.
+      # Typically when 32-bit value is assigned to a 64-bit pointer value.
+      4312,
       # Level 2, Possible loss of data due to type conversion.
       4244,
       # Level 3, Possible loss of data due to type conversion from size_t.
       4267,
+      # Level 1, No suitable definition provided for explicit template
+      # instantiation request.
+      4661,
     ],
     # Unfortunately, there is code that generate warnings in the headers.
     'direct_dependent_settings': {
diff --git a/src/third_party/openssl/openssl.gyp b/src/third_party/openssl/openssl.gyp
index 27a29c3..ba790a5 100644
--- a/src/third_party/openssl/openssl.gyp
+++ b/src/third_party/openssl/openssl.gyp
@@ -569,6 +569,10 @@
         'openssl/crypto/x509v3/v3_utl.c',
         'openssl/crypto/x509v3/v3err.c',
       ],
+      'msvs_disabled_warnings': [
+        # Level 1 - Pointer trunction warning.
+        4311,
+      ],
       'conditions': [
         ['os_posix==1 and OS!="android" and OS!="lb_shell"', {
           'defines': [
diff --git a/src/third_party/openssl/openssl/crypto/sha/sha512.c b/src/third_party/openssl/openssl/crypto/sha/sha512.c
index 14a8597..11aaa2b 100644
--- a/src/third_party/openssl/openssl/crypto/sha/sha512.c
+++ b/src/third_party/openssl/openssl/crypto/sha/sha512.c
@@ -357,7 +357,7 @@
                                 : "=r"(ret)             \
                                 : "r"(a),"K"(n)); ret;  })
 #    endif
-#   elif defined(_MSC_VER)
+#   elif defined(_MSC_VER) && !defined(STARBOARD)
 #    if defined(_WIN64)         /* applies to both IA-64 and AMD64 */
 #     pragma intrinsic(_rotr64)
 #     define ROTR(a,n)    _rotr64((a),n)
diff --git a/src/third_party/ots/ots.gyp b/src/third_party/ots/ots.gyp
index 2827c21..03eda8c 100644
--- a/src/third_party/ots/ots.gyp
+++ b/src/third_party/ots/ots.gyp
@@ -27,14 +27,10 @@
       'dependencies': [
         '../zlib/zlib.gyp:zlib',
       ],
-      'conditions': [
-        # Disable windows ots warnings:
-        #   4334: '<<' : result of 32-bit shift implicitly converted to 64
-        #       bits (was 64-bit shift intended?)
-        ['actual_target_arch=="win"', {
-          'msvs_disabled_warnings': [ 4334 ],
-        }],
-      ],
+      # Disable windows ots warnings:
+      #   4334: '<<' : result of 32-bit shift implicitly converted to 64
+      #       bits (was 64-bit shift intended?)
+      'msvs_disabled_warnings': [ 4334 ],
     },
   ],
 }
diff --git a/src/third_party/protobuf/protobuf.gyp b/src/third_party/protobuf/protobuf.gyp
index e985836..4e9a299 100644
--- a/src/third_party/protobuf/protobuf.gyp
+++ b/src/third_party/protobuf/protobuf.gyp
@@ -144,7 +144,7 @@
             'src/google/protobuf/stubs/mathlimits.h',
             'src/google/protobuf/stubs/substitute.cc',
             'src/google/protobuf/stubs/substitute.h',
-            'src/google/protobuf/stubs/singleton$.h',
+            'src/google/protobuf/stubs/singleton.h',
             'src/google/protobuf/text_format.cc',
             'src/google/protobuf/text_format.h',
             'src/google/protobuf/timestamp.pb.cc',
diff --git a/src/third_party/protobuf/src/google/protobuf/stubs/strutil.cc b/src/third_party/protobuf/src/google/protobuf/stubs/strutil.cc
index 296694c..688fabd 100644
--- a/src/third_party/protobuf/src/google/protobuf/stubs/strutil.cc
+++ b/src/third_party/protobuf/src/google/protobuf/stubs/strutil.cc
@@ -48,6 +48,7 @@
 
 #include <google/protobuf/stubs/stl_util.h>
 
+#if !defined(STARBOARD)
 #ifdef _WIN32
 // MSVC has only _snprintf, not snprintf.
 //
@@ -60,7 +61,8 @@
 // occurs with some input values, not all.  In any case, _snprintf does the
 // right thing, so we use it.
 #define snprintf _snprintf
-#endif
+#endif  // _WIN32
+#endif  // !defined(STARBOARD)
 
 namespace google {
 namespace protobuf {
diff --git a/src/third_party/skia/include/core/SkPixelRef.h b/src/third_party/skia/include/core/SkPixelRef.h
index 02d696e..abf5682 100644
--- a/src/third_party/skia/include/core/SkPixelRef.h
+++ b/src/third_party/skia/include/core/SkPixelRef.h
@@ -247,7 +247,8 @@
      *          not be created with the given config), or this PixelRef does not support deep
      *          copies.
      */
-    virtual SkPixelRef* deepCopy(SkColorType colortype, const SkIRect* subset) {
+    virtual SkPixelRef* deepCopy(SkColorType /*colortype*/,
+                                 const SkIRect* /*subset*/) {
         return NULL;
     }
 
diff --git a/src/third_party/skia/src/ports/SkFontHost_FreeType.cpp b/src/third_party/skia/src/ports/SkFontHost_FreeType.cpp
index b0f8e10..4499dac 100644
--- a/src/third_party/skia/src/ports/SkFontHost_FreeType.cpp
+++ b/src/third_party/skia/src/ports/SkFontHost_FreeType.cpp
@@ -15,6 +15,7 @@
 #include "SkFloatingPoint.h"
 #include "SkFontHost.h"
 #include "SkFontHost_FreeType_common.h"
+#include "SkFontStyle.h"
 #include "SkGlyph.h"
 #include "SkMask.h"
 #include "SkMaskGamma.h"
@@ -26,6 +27,7 @@
 #include "SkString.h"
 #include "SkTemplates.h"
 #include "SkThread.h"
+#include "SkTSearch.h"
 
 #if defined(STARBOARD)
 #include "starboard/log.h"
@@ -1703,8 +1705,56 @@
         return false;
     }
 
-    int tempStyle = SkTypeface::kNormal;
+    int weight = SkFontStyle::kNormal_Weight;
     if (face->style_flags & FT_STYLE_FLAG_BOLD) {
+        weight = SkFontStyle::kBold_Weight;
+    }
+
+    PS_FontInfoRec psFontInfo;
+    TT_OS2* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face, ft_sfnt_os2));
+    if (os2 && os2->version != 0xffff) {
+        weight = os2->usWeightClass;
+    } else if (0 == FT_Get_PS_Font_Info(face, &psFontInfo) && psFontInfo.weight) {
+        static const struct {
+            char const * const name;
+            int const weight;
+        } commonWeights [] = {
+            // There are probably more common names, but these are known to exist.
+            { "all", SkFontStyle::kNormal_Weight }, // Multiple Masters usually default to normal.
+            { "black", SkFontStyle::kBlack_Weight },
+            { "bold", SkFontStyle::kBold_Weight },
+            { "book", (SkFontStyle::kNormal_Weight + SkFontStyle::kLight_Weight)/2 },
+            { "demi", SkFontStyle::kSemiBold_Weight },
+            { "demibold", SkFontStyle::kSemiBold_Weight },
+            { "extra", SkFontStyle::kExtraBold_Weight },
+            { "extrabold", SkFontStyle::kExtraBold_Weight },
+            { "extralight", SkFontStyle::kExtraLight_Weight },
+            { "hairline", SkFontStyle::kThin_Weight },
+            { "heavy", SkFontStyle::kBlack_Weight },
+            { "light", SkFontStyle::kLight_Weight },
+            { "medium", SkFontStyle::kMedium_Weight },
+            { "normal", SkFontStyle::kNormal_Weight },
+            { "plain", SkFontStyle::kNormal_Weight },
+            { "regular", SkFontStyle::kNormal_Weight },
+            { "roman", SkFontStyle::kNormal_Weight },
+            { "semibold", SkFontStyle::kSemiBold_Weight },
+            { "standard", SkFontStyle::kNormal_Weight },
+            { "thin", SkFontStyle::kThin_Weight },
+            { "ultra", SkFontStyle::kExtraBold_Weight },
+            { "ultrabold", SkFontStyle::kExtraBold_Weight },
+            { "ultralight", SkFontStyle::kExtraLight_Weight },
+        };
+        int const index = SkStrLCSearch(&commonWeights[0].name, SK_ARRAY_COUNT(commonWeights),
+                                        psFontInfo.weight, sizeof(commonWeights[0]));
+        if (index >= 0) {
+            weight = commonWeights[index].weight;
+        } else {
+            SkDEBUGF(("Do not know weight for: %s (%s) \n", face->family_name, psFontInfo.weight));
+        }
+    }
+
+    int tempStyle = SkTypeface::kNormal;
+    if (weight > 500) {
         tempStyle |= SkTypeface::kBold;
     }
     if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
diff --git a/src/tools/gyp/pylib/gyp/generator/ninja.py b/src/tools/gyp/pylib/gyp/generator/ninja.py
index 0a1887d..c8b973a 100755
--- a/src/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/src/tools/gyp/pylib/gyp/generator/ninja.py
@@ -408,11 +408,17 @@
     assert targets == filter(None, targets), targets
     if len(targets) == 0:
       return None
-    if len(targets) > 1:
-      stamp = self.GypPathToUniqueOutput(name + '.stamp')
-      targets = self.ninja.build(stamp, 'stamp', targets)
-      self.ninja.newline()
-    return targets[0]
+    if len(targets) == 1:
+      return targets[0]
+
+    stamp = self.GypPathToUniqueOutput(name + '.stamp')
+    try:
+      raise NotImplementedError()  # TODO: Implement the abstract toolchain.
+    except NotImplementedError:
+      # Fall back to the legacy toolchain.
+      self.ninja.build(stamp, 'stamp', targets)
+    self.ninja.newline()
+    return stamp
 
   def WriteSpec(self, spec, config_name, generator_flags):
     """The main entry point for NinjaWriter: write the build rules for a spec.
@@ -520,7 +526,8 @@
           self.GypPathToNinja(f) for f in sources if f.endswith(self.obj_ext)
       ]
 
-    if self.flavor in microsoft_flavors and self.target.type == 'static_library':
+    if (self.flavor in microsoft_flavors and
+        self.target.type == 'static_library'):
       self.target.component_objs = link_deps
 
     # Write out a link step, if needed.
@@ -755,17 +762,21 @@
     # Renormalize with the separator character of the os on which ninja will run
     dst = self.path_module.normpath(dst)
 
-    output = self.ninja.build(dst, 'copy', src, order_only=prebuild)
-    if self.is_mac_bundle:
-      # gyp has mac_bundle_resources to copy things into a bundle's
-      # Resources folder, but there's no built-in way to copy files to other
-      # places in the bundle. Hence, some targets use copies for this. Check
-      # if this file is copied into the current bundle, and if so add it to
-      # the bundle depends so that dependent targets get rebuilt if the copy
-      # input changes.
-      if dst.startswith(self.xcode_settings.GetBundleContentsFolderPath()):
-        mac_bundle_depends.append(dst)
-    return output
+    try:
+      raise NotImplementedError()  # TODO: Implement the abstract toolchain.
+    except NotImplementedError:
+      # Fall back to the legacy toolchain.
+      self.ninja.build(dst, 'copy', src, order_only=prebuild)
+      if self.is_mac_bundle:
+        # gyp has mac_bundle_resources to copy things into a bundle's
+        # Resources folder, but there's no built-in way to copy files to other
+        # places in the bundle. Hence, some targets use copies for this. Check
+        # if this file is copied into the current bundle, and if so add it to
+        # the bundle depends so that dependent targets get rebuilt if the copy
+        # input changes.
+        if dst.startswith(self.xcode_settings.GetBundleContentsFolderPath()):
+          mac_bundle_depends.append(dst)
+    return [dst]
 
   def WriteCopies(self, copies, prebuild, mac_bundle_depends):
     outputs = []
@@ -847,157 +858,166 @@
   def WriteSources(self, config_name, config, sources, predepends,
                    precompiled_header, spec):
     """Write build rules to compile all of |sources|."""
-    if self.toolset == 'host':
-      self.ninja.variable('ar', '$ar_host')
-      self.ninja.variable('cc', '$cc_host')
-      self.ninja.variable('cxx', '$cxx_host')
-      self.ninja.variable('ld', '$ld_host')
 
-    extra_defines = []
-    if self.flavor == 'mac':
-      cflags = self.xcode_settings.GetCflags(config_name)
-      cflags_c = self.xcode_settings.GetCflagsC(config_name)
-      cflags_cc = self.xcode_settings.GetCflagsCC(config_name)
-      cflags_objc = ['$cflags_c'] + \
-                    self.xcode_settings.GetCflagsObjC(config_name)
-      cflags_objcc = ['$cflags_cc'] + \
-                     self.xcode_settings.GetCflagsObjCC(config_name)
-    elif GetToolchainOrNone(self.flavor):
-      cflags = GetToolchainOrNone(
-          self.flavor).GetCompilerSettings().GetCflags(config_name)
-      cflags_c = GetToolchainOrNone(
-          self.flavor).GetCompilerSettings().GetCflagsC(config_name)
-      cflags_cc = GetToolchainOrNone(
-          self.flavor).GetCompilerSettings().GetCflagsCC(config_name)
-      extra_defines = GetToolchainOrNone(
-          self.flavor).GetCompilerSettings().GetDefines(config_name)
-      obj = 'obj'
-      if self.toolset != 'target':
-        obj += '.' + self.toolset
-      pdbpath = os.path.normpath(
-          os.path.join(obj, self.base_dir, self.name + '.pdb'))
-      self.WriteVariableList('pdbname', [pdbpath])
-      self.WriteVariableList('pchprefix', [self.name])
-    else:
-      cflags = config.get('cflags', [])
-      cflags_c = config.get('cflags_c', [])
-      cflags_cc = config.get('cflags_cc', [])
+    try:
+      raise NotImplementedError()  # TODO: Implement the abstract toolchain.
+    except NotImplementedError:
+      # Fall back to the legacy toolchain.
 
-    cflags_host = config.get('cflags_host', cflags)
-    cflags_c_host = config.get('cflags_c_host', cflags_c)
-    cflags_cc_host = config.get('cflags_cc_host', cflags_cc)
+      if self.toolset == 'host':
+        self.ninja.variable('ar', '$ar_host')
+        self.ninja.variable('cc', '$cc_host')
+        self.ninja.variable('cxx', '$cxx_host')
+        self.ninja.variable('ld', '$ld_host')
 
-    defines = config.get('defines', []) + extra_defines
-    if GetToolchainOrNone(self.flavor):
-      self.WriteVariableList('defines', [
-          GetToolchainOrNone(self.flavor).Define(d) for d in defines
-      ])
-    else:
-      self.WriteVariableList('defines',
-                             [Define(d, self.flavor) for d in defines])
-    if GetToolchainOrNone(self.flavor):
-      self.WriteVariableList('rcflags', [
-          QuoteShellArgument(self.ExpandSpecial(f), self.flavor)
-          for f in GetToolchainOrNone(self.flavor).GetCompilerSettings()
-          .GetRcFlags(config_name, self.GypPathToNinja)
-      ])
-
-    include_dirs = config.get('include_dirs', [])
-    include_dirs += config.get('include_dirs_' + self.toolset, [])
-
-    if GetToolchainOrNone(self.flavor):
-      include_dirs = GetToolchainOrNone(
-          self.flavor).GetCompilerSettings().ProcessIncludeDirs(
-              include_dirs, config_name)
-      self.WriteVariableList('includes', [
-          '/I' + GetToolchainOrNone(self.flavor).QuoteForRspFile(
-              self.GypPathToNinja(i)) for i in include_dirs
-      ])
-    else:
-      self.WriteVariableList('includes', [
-          QuoteShellArgument('-I' + self.GypPathToNinja(i), self.flavor)
-          for i in include_dirs
-      ])
-
-    pch_commands = precompiled_header.GetPchBuildCommands()
-    if self.flavor == 'mac':
-      self.WriteVariableList('cflags_pch_c',
-                             [precompiled_header.GetInclude('c')])
-      self.WriteVariableList('cflags_pch_cc',
-                             [precompiled_header.GetInclude('cc')])
-      self.WriteVariableList('cflags_pch_objc',
-                             [precompiled_header.GetInclude('m')])
-      self.WriteVariableList('cflags_pch_objcc',
-                             [precompiled_header.GetInclude('mm')])
-
-    self.WriteVariableList('cflags', map(self.ExpandSpecial, cflags))
-    self.WriteVariableList('cflags_c', map(self.ExpandSpecial, cflags_c))
-    self.WriteVariableList('cflags_cc', map(self.ExpandSpecial, cflags_cc))
-
-    self.WriteVariableList('cflags_host', map(self.ExpandSpecial, cflags_host))
-    self.WriteVariableList('cflags_c_host',
-                           map(self.ExpandSpecial, cflags_c_host))
-    self.WriteVariableList('cflags_cc_host',
-                           map(self.ExpandSpecial, cflags_cc_host))
-
-    if self.flavor == 'mac':
-      self.WriteVariableList('cflags_objc', map(self.ExpandSpecial,
-                                                cflags_objc))
-      self.WriteVariableList('cflags_objcc',
-                             map(self.ExpandSpecial, cflags_objcc))
-    self.ninja.newline()
-    outputs = []
-    for source in sources:
-      filename, ext = os.path.splitext(source)
-      ext = ext[1:]
-      obj_ext = self.obj_ext
-      if ext in ('cc', 'cpp', 'cxx'):
-        command = 'cxx'
-      elif ext == 'c' or (ext == 'S' and self.flavor != 'win'):
-        command = 'cc'
-      elif ext == 's' and self.flavor != 'win':  # Doesn't generate .o.d files.
-        command = 'cc_s'
-      elif (self.flavor == 'win' and ext == 'asm' and GetToolchainOrNone(
-          self.flavor).GetCompilerSettings().GetArch(config_name) == 'x86' and
-            not GetToolchainOrNone(
-                self.flavor).GetCompilerSettings().HasExplicitAsmRules(spec)):
-        # Asm files only get auto assembled for x86 (not x64).
-        command = 'asm'
-        # Add the _asm suffix as msvs is capable of handling .cc and
-        # .asm files of the same name without collision.
-        obj_ext = '_asm.obj'
-      elif self.flavor == 'mac' and ext == 'm':
-        command = 'objc'
-      elif self.flavor == 'mac' and ext == 'mm':
-        command = 'objcxx'
-      elif self.flavor in microsoft_flavors and ext == 'rc':
-        # TODO: Starboardize this.
-        command = 'rc'
-        obj_ext = '.res'
+      extra_defines = []
+      if self.flavor == 'mac':
+        cflags = self.xcode_settings.GetCflags(config_name)
+        cflags_c = self.xcode_settings.GetCflagsC(config_name)
+        cflags_cc = self.xcode_settings.GetCflagsCC(config_name)
+        cflags_objc = ['$cflags_c'] + \
+                      self.xcode_settings.GetCflagsObjC(config_name)
+        cflags_objcc = ['$cflags_cc'] + \
+                       self.xcode_settings.GetCflagsObjCC(config_name)
+      elif GetToolchainOrNone(self.flavor):
+        cflags = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetCflags(config_name)
+        cflags_c = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetCflagsC(config_name)
+        cflags_cc = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetCflagsCC(config_name)
+        extra_defines = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetDefines(config_name)
+        obj = 'obj'
+        if self.toolset != 'target':
+          obj += '.' + self.toolset
+        pdbpath = os.path.normpath(
+            os.path.join(obj, self.base_dir, self.name + '.pdb'))
+        self.WriteVariableList('pdbname', [pdbpath])
+        self.WriteVariableList('pchprefix', [self.name])
       else:
-        # Ignore unhandled extensions.
-        continue
-      if self.toolset != 'target':
-        command += '_' + self.toolset
+        cflags = config.get('cflags', [])
+        cflags_c = config.get('cflags_c', [])
+        cflags_cc = config.get('cflags_cc', [])
 
-      input = self.GypPathToNinja(source)
-      output = self.GypPathToUniqueOutput(filename + obj_ext)
-      implicit = precompiled_header.GetObjDependencies([input], [output])
-      variables = []
+      cflags_host = config.get('cflags_host', cflags)
+      cflags_c_host = config.get('cflags_c_host', cflags_c)
+      cflags_cc_host = config.get('cflags_cc_host', cflags_cc)
+
+      defines = config.get('defines', []) + extra_defines
       if GetToolchainOrNone(self.flavor):
-        variables, output, implicit = precompiled_header.GetFlagsModifications(
-            input, output, implicit, command, cflags_c, cflags_cc,
-            self.ExpandSpecial)
-      self.ninja.build(
-          output,
-          command,
-          input,
-          implicit=[gch for _, _, gch in implicit],
-          order_only=predepends,
-          variables=variables)
-      outputs.append(output)
+        self.WriteVariableList('defines', [
+            GetToolchainOrNone(self.flavor).Define(d) for d in defines
+        ])
+      else:
+        self.WriteVariableList('defines',
+                               [Define(d, self.flavor) for d in defines])
+      if GetToolchainOrNone(self.flavor):
+        self.WriteVariableList('rcflags', [
+            QuoteShellArgument(self.ExpandSpecial(f), self.flavor)
+            for f in GetToolchainOrNone(self.flavor).GetCompilerSettings()
+            .GetRcFlags(config_name, self.GypPathToNinja)
+        ])
 
-    self.WritePchTargets(pch_commands)
+      include_dirs = config.get('include_dirs', [])
+      include_dirs += config.get('include_dirs_' + self.toolset, [])
+
+      if GetToolchainOrNone(self.flavor):
+        include_dirs = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().ProcessIncludeDirs(
+                include_dirs, config_name)
+        self.WriteVariableList('includes', [
+            '/I' + GetToolchainOrNone(self.flavor).QuoteForRspFile(
+                self.GypPathToNinja(i)) for i in include_dirs
+        ])
+      else:
+        self.WriteVariableList('includes', [
+            QuoteShellArgument('-I' + self.GypPathToNinja(i), self.flavor)
+            for i in include_dirs
+        ])
+
+      pch_commands = precompiled_header.GetPchBuildCommands()
+      if self.flavor == 'mac':
+        self.WriteVariableList('cflags_pch_c',
+                               [precompiled_header.GetInclude('c')])
+        self.WriteVariableList('cflags_pch_cc',
+                               [precompiled_header.GetInclude('cc')])
+        self.WriteVariableList('cflags_pch_objc',
+                               [precompiled_header.GetInclude('m')])
+        self.WriteVariableList('cflags_pch_objcc',
+                               [precompiled_header.GetInclude('mm')])
+
+      self.WriteVariableList('cflags', map(self.ExpandSpecial, cflags))
+      self.WriteVariableList('cflags_c', map(self.ExpandSpecial, cflags_c))
+      self.WriteVariableList('cflags_cc', map(self.ExpandSpecial, cflags_cc))
+
+      self.WriteVariableList('cflags_host', map(self.ExpandSpecial,
+                                                cflags_host))
+      self.WriteVariableList('cflags_c_host',
+                             map(self.ExpandSpecial, cflags_c_host))
+      self.WriteVariableList('cflags_cc_host',
+                             map(self.ExpandSpecial, cflags_cc_host))
+
+      if self.flavor == 'mac':
+        self.WriteVariableList('cflags_objc',
+                               map(self.ExpandSpecial, cflags_objc))
+        self.WriteVariableList('cflags_objcc',
+                               map(self.ExpandSpecial, cflags_objcc))
+      self.ninja.newline()
+
+      outputs = []
+      for source in sources:
+        filename, ext = os.path.splitext(source)
+        ext = ext[1:]
+        obj_ext = self.obj_ext
+        if ext in ('cc', 'cpp', 'cxx'):
+          command = 'cxx'
+        elif ext == 'c' or (ext == 'S' and self.flavor != 'win'):
+          command = 'cc'
+        elif ext == 's' and self.flavor != 'win':  # Doesn't generate .o.d files.
+          command = 'cc_s'
+        elif (self.flavor == 'win' and ext == 'asm' and GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetArch(config_name) == 'x86' and
+              not GetToolchainOrNone(
+                  self.flavor).GetCompilerSettings().HasExplicitAsmRules(spec)):
+          # Asm files only get auto assembled for x86 (not x64).
+          command = 'asm'
+          # Add the _asm suffix as msvs is capable of handling .cc and
+          # .asm files of the same name without collision.
+          obj_ext = '_asm.obj'
+        elif self.flavor == 'mac' and ext == 'm':
+          command = 'objc'
+        elif self.flavor == 'mac' and ext == 'mm':
+          command = 'objcxx'
+        elif self.flavor in microsoft_flavors and ext == 'rc':
+          # TODO: Starboardize this.
+          command = 'rc'
+          obj_ext = '.res'
+        else:
+          # Ignore unhandled extensions.
+          continue
+        if self.toolset != 'target':
+          command += '_' + self.toolset
+
+        input = self.GypPathToNinja(source)
+        output = self.GypPathToUniqueOutput(filename + obj_ext)
+        implicit = precompiled_header.GetObjDependencies([input], [output])
+        variables = []
+        if GetToolchainOrNone(self.flavor):
+          (variables, output,
+           implicit) = precompiled_header.GetFlagsModifications(
+               input, output, implicit, command, cflags_c, cflags_cc,
+               self.ExpandSpecial)
+        self.ninja.build(
+            output,
+            command,
+            input,
+            implicit=[gch for _, _, gch in implicit],
+            order_only=predepends,
+            variables=variables)
+        outputs.append(output)
+
+      self.WritePchTargets(pch_commands)
 
     self.ninja.newline()
     return outputs
@@ -1027,180 +1047,192 @@
   def WriteLink(self, spec, config_name, config, link_deps):
     """Write out a link step. Fills out target.binary. """
 
-    command = {
-        'executable': 'link',
-        'loadable_module': 'solink_module',
-        'shared_library': 'solink',
-    }[spec['type']]
+    try:
+      raise NotImplementedError()  # TODO: Implement the abstract toolchain.
+    except NotImplementedError:
+      # Fall back to the legacy toolchain.
 
-    implicit_deps = set()
-    order_only_deps = set()
-    solibs = set()
+      command = {
+          'executable': 'link',
+          'loadable_module': 'solink_module',
+          'shared_library': 'solink',
+      }[spec['type']]
 
-    if 'dependencies' in spec:
-      # Two kinds of dependencies:
-      # - Linkable dependencies (like a .a or a .so): add them to the link line.
-      # - Non-linkable dependencies (like a rule that generates a file
-      #   and writes a stamp file): add them to implicit_deps or order_only_deps
-      extra_link_deps = []
-      for dep in spec['dependencies']:
-        target = self.target_outputs.get(dep)
-        if not target:
-          continue
-        linkable = target.Linkable()
-        # TODO: Starboardize.
-        if linkable:
-          if (self.flavor in microsoft_flavors and target.component_objs and
-              GetToolchainOrNone(self.flavor).GetCompilerSettings()
-              .IsUseLibraryDependencyInputs(config_name)):
-            extra_link_deps.extend(target.component_objs)
-          elif (self.flavor in (microsoft_flavors + ['ps3']) and
-                target.import_lib):
-            extra_link_deps.append(target.import_lib)
-          elif target.UsesToc(self.flavor):
-            solibs.add(target.binary)
-            implicit_deps.add(target.binary + '.TOC')
-          else:
-            extra_link_deps.append(target.binary)
+      implicit_deps = set()
+      order_only_deps = set()
+      solibs = set()
 
-        final_output = target.FinalOutput()
-        if not linkable or final_output != target.binary:
-          order_only_deps.add(final_output)
+      if 'dependencies' in spec:
+        # Two kinds of dependencies:
+        # - Linkable dependencies (like a .a or a .so): add them to the link
+        #   line.
+        # - Non-linkable dependencies (like a rule that generates a file
+        #   and writes a stamp file): add them to implicit_deps or
+        #   order_only_deps
+        extra_link_deps = []
+        for dep in spec['dependencies']:
+          target = self.target_outputs.get(dep)
+          if not target:
+            continue
+          linkable = target.Linkable()
+          # TODO: Starboardize.
+          if linkable:
+            if (self.flavor in microsoft_flavors and target.component_objs and
+                GetToolchainOrNone(self.flavor).GetCompilerSettings()
+                .IsUseLibraryDependencyInputs(config_name)):
+              extra_link_deps.extend(target.component_objs)
+            elif (self.flavor in (microsoft_flavors + ['ps3']) and
+                  target.import_lib):
+              extra_link_deps.append(target.import_lib)
+            elif target.UsesToc(self.flavor):
+              solibs.add(target.binary)
+              implicit_deps.add(target.binary + '.TOC')
+            else:
+              extra_link_deps.append(target.binary)
 
-      # dedup the extra link deps while preserving order
-      seen = set()
-      extra_link_deps = [
-          x for x in extra_link_deps if x not in seen and not seen.add(x)
-      ]
+          final_output = target.FinalOutput()
+          if not linkable or final_output != target.binary:
+            order_only_deps.add(final_output)
 
-      link_deps.extend(extra_link_deps)
+        # dedup the extra link deps while preserving order
+        seen = set()
+        extra_link_deps = [
+            x for x in extra_link_deps if x not in seen and not seen.add(x)
+        ]
 
-    extra_bindings = []
-    if self.is_mac_bundle:
-      output = self.ComputeMacBundleBinaryOutput()
-    else:
-      output = self.ComputeOutput(spec)
-      extra_bindings.append(('postbuilds', self.GetPostbuildCommand(
-          spec, output, output)))
+        link_deps.extend(extra_link_deps)
 
-    if self.flavor == 'mac':
-      ldflags = self.xcode_settings.GetLdflags(
-          config_name,
-          self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
-          self.GypPathToNinja)
-    elif GetToolchainOrNone(self.flavor):
-      libflags = GetToolchainOrNone(
-          self.flavor).GetCompilerSettings().GetLibFlags(
-              config_name, self.GypPathToNinja)
-      self.WriteVariableList(
-          'libflags', gyp.common.uniquer(map(self.ExpandSpecial, libflags)))
-      is_executable = spec['type'] == 'executable'
-      manifest_name = self.GypPathToUniqueOutput(
-          self.ComputeOutputFileName(spec))
-      ldflags, manifest_files = GetToolchainOrNone(
-          self.flavor).GetCompilerSettings().GetLdFlags(config_name, **{
-              'gyp_path_to_ninja': self.GypPathToNinja,
-              'expand_special': self.ExpandSpecial,
-              'manifest_name': manifest_name,
-              'is_executable': is_executable
-          })
-      self.WriteVariableList('manifests', manifest_files)
-    else:
-      ldflags = config.get('ldflags', [])
-      ldflags_host = config.get('ldflags_host', ldflags)
-
-    self.WriteVariableList('ldflags',
-                           gyp.common.uniquer(map(self.ExpandSpecial, ldflags)))
-    if ('ldflags_host' in locals()):
-      self.WriteVariableList(
-          'ldflags_host',
-          gyp.common.uniquer(map(self.ExpandSpecial, ldflags_host)))
-
-    if self.toolset == 'host':
-      libs = spec.get('libraries_host', [])
-      libs.extend(config.get('libraries_host', []))
-    else:
-      libs = spec.get('libraries', [])
-      libs.extend(config.get('libraries', []))
-
-    libraries = gyp.common.uniquer(map(self.ExpandSpecial, libs))
-
-    if self.flavor == 'mac':
-      libraries = self.xcode_settings.AdjustLibraries(libraries)
-    elif GetToolchainOrNone(self.flavor):
-      libraries = GetToolchainOrNone(
-          self.flavor).GetCompilerSettings().ProcessLibraries(libraries)
-    self.WriteVariableList('libs', libraries)
-
-    self.target.binary = output
-
-    if command in ('solink', 'solink_module'):
-      extra_bindings.append(('soname', os.path.split(output)[1]))
-      extra_bindings.append(('lib',
-                             gyp.common.EncodePOSIXShellArgument(output)))
-      # TODO: Starboardize.
-      if self.flavor in microsoft_flavors:
-        extra_bindings.append(('dll', output))
-        if '/NOENTRY' not in ldflags:
-          self.target.import_lib = output + '.lib'
-          extra_bindings.append(('implibflag',
-                                 '/IMPLIB:%s' % self.target.import_lib))
-          output = [output, self.target.import_lib]
-      elif self.flavor in ['ps3']:
-        # Tell Ninja we'll be generating a .sprx and a stub library.
-        # Bind the variable '$prx' to our output binary so we can
-        # refer to it in the linker rules.
-        prx_output = output
-        prx_output_base, prx_output_ext = os.path.splitext(prx_output)
-        assert prx_output_ext == '.sprx'
-
-        extra_bindings.append(('prx', output))
-        # TODO: Figure out how to suppress the "removal" warning
-        # generated from the prx generator when we remove a function.
-        # For now, we'll just delete the 'verlog.txt' file before linking.
-        # Bind it here so we can refer to it as $verlog in the PS3 solink rule.
-        verlog = output.replace(prx_output_ext, '_verlog.txt')
-        extra_bindings.append(('verlog', verlog))
-        self.target.import_lib = output.replace(prx_output_ext, '_stub.a')
-        output = [prx_output, self.target.import_lib]
-
-        # For PRXs, we need to convert any c++ exports into C. This is done
-        # with an "export pickup" step that runs over the object files
-        # and produces a new .c file. That .c file should be compiled and linked
-        # into the PRX.
-        gen_files_dir = os.path.join(
-            self.ExpandSpecial(
-                generator_default_variables['SHARED_INTERMEDIATE_DIR']), 'prx')
-
-        export_pickup_output = os.path.join(
-            gen_files_dir, os.path.basename(prx_output_base) + '.prx_export.c')
-        prx_export_obj_file = export_pickup_output[:-2] + '.o'
-        self.ninja.build(
-            export_pickup_output,
-            'prx_export_pickup',
-            link_deps,
-            implicit=list(implicit_deps),
-            order_only=list(order_only_deps))
-
-        self.ninja.build(prx_export_obj_file, 'cc', export_pickup_output)
-        link_deps.append(prx_export_obj_file)
-
+      extra_bindings = []
+      if self.is_mac_bundle:
+        output = self.ComputeMacBundleBinaryOutput()
       else:
-        output = [output, output + '.TOC']
+        output = self.ComputeOutput(spec)
+        extra_bindings.append(('postbuilds', self.GetPostbuildCommand(
+            spec, output, output)))
 
-    if len(solibs):
-      extra_bindings.append(('solibs', gyp.common.EncodePOSIXShellList(solibs)))
+      if self.flavor == 'mac':
+        ldflags = self.xcode_settings.GetLdflags(
+            config_name,
+            self.ExpandSpecial(generator_default_variables['PRODUCT_DIR']),
+            self.GypPathToNinja)
+      elif GetToolchainOrNone(self.flavor):
+        libflags = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetLibFlags(
+                config_name, self.GypPathToNinja)
+        self.WriteVariableList(
+            'libflags', gyp.common.uniquer(map(self.ExpandSpecial, libflags)))
+        is_executable = spec['type'] == 'executable'
+        manifest_name = self.GypPathToUniqueOutput(
+            self.ComputeOutputFileName(spec))
+        ldflags, manifest_files = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().GetLdFlags(
+                config_name, **{
+                    'gyp_path_to_ninja': self.GypPathToNinja,
+                    'expand_special': self.ExpandSpecial,
+                    'manifest_name': manifest_name,
+                    'is_executable': is_executable
+                })
+        self.WriteVariableList('manifests', manifest_files)
+      else:
+        ldflags = config.get('ldflags', [])
+        ldflags_host = config.get('ldflags_host', ldflags)
 
-    if self.toolset != 'target':
-      command += '_' + self.toolset
+      self.WriteVariableList(
+          'ldflags', gyp.common.uniquer(map(self.ExpandSpecial, ldflags)))
+      if ('ldflags_host' in locals()):
+        self.WriteVariableList(
+            'ldflags_host',
+            gyp.common.uniquer(map(self.ExpandSpecial, ldflags_host)))
 
-    self.ninja.build(
-        output,
-        command,
-        link_deps,
-        implicit=list(implicit_deps),
-        order_only=list(order_only_deps),
-        variables=extra_bindings)
+      if self.toolset == 'host':
+        libs = spec.get('libraries_host', [])
+        libs.extend(config.get('libraries_host', []))
+      else:
+        libs = spec.get('libraries', [])
+        libs.extend(config.get('libraries', []))
+
+      libraries = gyp.common.uniquer(map(self.ExpandSpecial, libs))
+
+      if self.flavor == 'mac':
+        libraries = self.xcode_settings.AdjustLibraries(libraries)
+      elif GetToolchainOrNone(self.flavor):
+        libraries = GetToolchainOrNone(
+            self.flavor).GetCompilerSettings().ProcessLibraries(libraries)
+      self.WriteVariableList('libs', libraries)
+
+      self.target.binary = output
+
+      if command in ('solink', 'solink_module'):
+        extra_bindings.append(('soname', os.path.split(output)[1]))
+        extra_bindings.append(('lib',
+                               gyp.common.EncodePOSIXShellArgument(output)))
+        # TODO: Starboardize.
+        if self.flavor in microsoft_flavors:
+          extra_bindings.append(('dll', output))
+          if '/NOENTRY' not in ldflags:
+            self.target.import_lib = output + '.lib'
+            extra_bindings.append(('implibflag',
+                                   '/IMPLIB:%s' % self.target.import_lib))
+            output = [output, self.target.import_lib]
+        elif self.flavor in ['ps3']:
+          # Tell Ninja we'll be generating a .sprx and a stub library.
+          # Bind the variable '$prx' to our output binary so we can
+          # refer to it in the linker rules.
+          prx_output = output
+          prx_output_base, prx_output_ext = os.path.splitext(prx_output)
+          assert prx_output_ext == '.sprx'
+
+          extra_bindings.append(('prx', output))
+          # TODO: Figure out how to suppress the "removal" warning
+          # generated from the prx generator when we remove a function.
+          # For now, we'll just delete the 'verlog.txt' file before linking.
+          # Bind it here so we can refer to it as $verlog in the PS3 solink
+          # rule.
+          verlog = output.replace(prx_output_ext, '_verlog.txt')
+          extra_bindings.append(('verlog', verlog))
+          self.target.import_lib = output.replace(prx_output_ext, '_stub.a')
+          output = [prx_output, self.target.import_lib]
+
+          # For PRXs, we need to convert any c++ exports into C. This is done
+          # with an "export pickup" step that runs over the object files
+          # and produces a new .c file. That .c file should be compiled and
+          # linked into the PRX.
+          gen_files_dir = os.path.join(
+              self.ExpandSpecial(
+                  generator_default_variables['SHARED_INTERMEDIATE_DIR']),
+              'prx')
+
+          export_pickup_output = os.path.join(
+              gen_files_dir,
+              os.path.basename(prx_output_base) + '.prx_export.c')
+          prx_export_obj_file = export_pickup_output[:-2] + '.o'
+          self.ninja.build(
+              export_pickup_output,
+              'prx_export_pickup',
+              link_deps,
+              implicit=list(implicit_deps),
+              order_only=list(order_only_deps))
+
+          self.ninja.build(prx_export_obj_file, 'cc', export_pickup_output)
+          link_deps.append(prx_export_obj_file)
+
+        else:
+          output = [output, output + '.TOC']
+
+      if len(solibs):
+        extra_bindings.append(('solibs',
+                               gyp.common.EncodePOSIXShellList(solibs)))
+
+      if self.toolset != 'target':
+        command += '_' + self.toolset
+
+      self.ninja.build(
+          output,
+          command,
+          link_deps,
+          implicit=list(implicit_deps),
+          order_only=list(order_only_deps),
+          variables=extra_bindings)
 
   def WriteTarget(self, spec, config_name, config, link_deps, compile_deps):
     if spec['type'] == 'none':
@@ -1209,34 +1241,40 @@
       self.target.binary = compile_deps
     elif spec['type'] == 'static_library':
       self.target.binary = self.ComputeOutput(spec)
-      variables = []
-      if GetToolchainOrNone(self.flavor):
-        libflags = GetToolchainOrNone(
-            self.flavor).GetCompilerSettings().GetLibFlags(
-                config_name, self.GypPathToNinja)
-        # TODO: Starboardize libflags vs libtool_flags.
-        variables.append(('libflags', ' '.join(libflags)))
-      postbuild = self.GetPostbuildCommand(spec, self.target.binary,
-                                           self.target.binary)
-      if postbuild:
-        variables.append(('postbuilds', postbuild))
-      if self.xcode_settings:
-        variables.append(('libtool_flags',
-                          self.xcode_settings.GetLibtoolflags(config_name)))
-      # TODO: Starboardize.
-      if (self.flavor not in (['mac'] + microsoft_flavors) and
-          not self.is_standalone_static_library):
-        command = 'alink_thin'
-      else:
-        command = 'alink'
-      if self.toolset != 'target':
-        command += '_' + self.toolset
-      self.ninja.build(
-          self.target.binary,
-          command,
-          link_deps,
-          order_only=compile_deps,
-          variables=variables)
+
+      try:
+        raise NotImplementedError()  # TODO: Implement the abstract toolchain.
+      except NotImplementedError:
+        # Fall back to the legacy toolchain.
+
+        variables = []
+        if GetToolchainOrNone(self.flavor):
+          libflags = GetToolchainOrNone(
+              self.flavor).GetCompilerSettings().GetLibFlags(
+                  config_name, self.GypPathToNinja)
+          # TODO: Starboardize libflags vs libtool_flags.
+          variables.append(('libflags', ' '.join(libflags)))
+        postbuild = self.GetPostbuildCommand(spec, self.target.binary,
+                                             self.target.binary)
+        if postbuild:
+          variables.append(('postbuilds', postbuild))
+        if self.xcode_settings:
+          variables.append(('libtool_flags',
+                            self.xcode_settings.GetLibtoolflags(config_name)))
+        # TODO: Starboardize.
+        if (self.flavor not in (['mac'] + microsoft_flavors) and
+            not self.is_standalone_static_library):
+          command = 'alink_thin'
+        else:
+          command = 'alink'
+        if self.toolset != 'target':
+          command += '_' + self.toolset
+        self.ninja.build(
+            self.target.binary,
+            command,
+            link_deps,
+            order_only=compile_deps,
+            variables=variables)
     else:
       self.WriteLink(spec, config_name, config, link_deps)
     return self.target.binary
@@ -1687,579 +1725,591 @@
       OpenOutput(os.path.join(toplevel_build, 'build.ninja')), width=120)
   case_sensitive_filesystem = True
 
-  # Put build-time support tools in out/{config_name}.
-  gyp.common.CopyTool(flavor, toplevel_build)
-
-  # Grab make settings for CC/CXX.
-  # The rules are
-  # - The priority from low to high is gcc/g++, the 'make_global_settings' in
-  #   gyp, the environment variable.
-  # - If there is no 'make_global_settings' for CC.host/CXX.host or
-  #   'CC_host'/'CXX_host' enviroment variable, cc_host/cxx_host should be set
-  #   to cc/cxx.
-  if (flavor in sony_flavors and is_windows):
-    cc = 'cl.exe'
-    cxx = 'cl.exe'
-    ld = 'link.exe'
-    gyp.msvs_emulation.GenerateEnvironmentFiles(toplevel_build, generator_flags,
-                                                OpenOutput)
-    ld_host = '$ld'
-  elif GetToolchainOrNone(flavor):
-    # TODO: starboardize.
-    cc = 'cl.exe'
-    cxx = 'cl.exe'
-    ld = 'link.exe'
-    GetToolchainOrNone(flavor).GenerateEnvironmentFiles(
-        toplevel_build, generator_flags, OpenOutput)
-    ld_host = '$ld'
-  else:
-    cc = 'gcc'
-    cxx = 'g++'
-    ld = '$cxx'
-    ld_host = '$cxx_host'
-
-  cc_host = None
-  cxx_host = None
-  cc_host_global_setting = None
-  cxx_host_global_setting = None
-
   build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
   make_global_settings = data[build_file].get('make_global_settings', [])
-  build_to_root = InvertRelativePath(build_dir)
-  for key, value in make_global_settings:
-    if key == 'CC':
-      cc = os.path.join(build_to_root, value)
-    if key == 'CXX':
-      cxx = os.path.join(build_to_root, value)
-    if key == 'LD':
-      ld = os.path.join(build_to_root, value)
-    if key == 'CC.host':
-      cc_host = os.path.join(build_to_root, value)
-      cc_host_global_setting = value
-    if key == 'CXX.host':
-      cxx_host = os.path.join(build_to_root, value)
-      cxx_host_global_setting = value
-    if key == 'LD.host':
-      ld_host = os.path.join(build_to_root, value)
 
-  flock = 'flock'
-  if flavor == 'mac':
-    flock = './gyp-mac-tool flock'
-  cc = GetEnvironFallback(['CC_target', 'CC'], cc)
-  master_ninja.variable('cc', cc)
-  cxx = GetEnvironFallback(['CXX_target', 'CXX'], cxx)
-  master_ninja.variable('cxx', cxx)
-  ld = GetEnvironFallback(['LD_target', 'LD'], ld)
-  rc = GetEnvironFallback(['RC'], 'rc.exe')
+  try:
+    raise NotImplementedError()  # TODO: Implement the abstract toolchain.
+  except NotImplementedError:
+    # Fall back to the legacy toolchain.
 
-  if not cc_host:
-    cc_host = cc
-  if not cxx_host:
-    cxx_host = cxx
+    # Put build-time support tools in out/{config_name}.
+    gyp.common.CopyTool(flavor, toplevel_build)
 
-  # gyp-win-tool wrappers have a winpython only flock implementation.
-  if sys.platform == 'cygwin':
-    python_exec = '$python'
-  else:
-    python_exec = sys.executable
+    # Grab make settings for CC/CXX.
+    # The rules are
+    # - The priority from low to high is gcc/g++, the 'make_global_settings' in
+    #   gyp, the environment variable.
+    # - If there is no 'make_global_settings' for CC.host/CXX.host or
+    #   'CC_host'/'CXX_host' enviroment variable, cc_host/cxx_host should be set
+    #   to cc/cxx.
+    if (flavor in sony_flavors and is_windows):
+      cc = 'cl.exe'
+      cxx = 'cl.exe'
+      ld = 'link.exe'
+      gyp.msvs_emulation.GenerateEnvironmentFiles(toplevel_build,
+                                                  generator_flags, OpenOutput)
+      ld_host = '$ld'
+    elif GetToolchainOrNone(flavor):
+      # TODO: starboardize.
+      cc = 'cl.exe'
+      cxx = 'cl.exe'
+      ld = 'link.exe'
+      GetToolchainOrNone(flavor).GenerateEnvironmentFiles(
+          toplevel_build, generator_flags, OpenOutput)
+      ld_host = '$ld'
+    else:
+      cc = 'gcc'
+      cxx = 'g++'
+      ld = '$cxx'
+      ld_host = '$cxx_host'
 
-  ar_flags = ''
-  if flavor in microsoft_flavors:
-    master_ninja.variable('ld', ld)
-    master_ninja.variable('ar', os.environ.get('AR', 'ar'))
-    master_ninja.variable('rc', rc)
-    master_ninja.variable('asm', 'ml.exe')
-    master_ninja.variable('mt', 'mt.exe')
-    master_ninja.variable('use_dep_database', '1')
-  elif flavor in sony_flavors:
-    # Require LD to be set.
-    master_ninja.variable('ld', os.environ.get('LD'))
-    master_ninja.variable('ar', os.environ.get('AR', 'ar'))
-    if flavor in ['ps3']:
-      master_ninja.variable('prx_export_pickup',
-                            os.environ['PRX_EXPORT_PICKUP'])
-    ar_flags = os.environ.get('ARFLAGS', 'rcs')
-    master_ninja.variable('arFlags', ar_flags)
-    # On the PS3, when we use ps3snarl.exe with a response file, we cannot
-    # pass it flags (like 'rcs'), so ARFLAGS is likely set to '' for this
-    # platform.  In that case, do not append the thin archive 'T' flag
-    # to the flags string.
-    # Likewise for PS4, but using orbis-snarl.exe
-    thin_flag_to_add = ''
-    if len(ar_flags) >= 1 and ar_flags.find('T') == -1:
-      thin_flag_to_add = 'T'
-    master_ninja.variable('arThinFlags', ar_flags + thin_flag_to_add)
+    cc_host = None
+    cxx_host = None
+    cc_host_global_setting = None
+    cxx_host_global_setting = None
 
-  else:
-    master_ninja.variable('ld', ld)
-    master_ninja.variable('ar', GetEnvironFallback(['AR_target', 'AR'], 'ar'))
-    ar_flags = os.environ.get('ARFLAGS', 'rcs')
-    master_ninja.variable('arFlags', ar_flags)
-    thin_flag_to_add = ''
-    if ar_flags.find('T') == -1:
-      thin_flag_to_add = 'T'
-    master_ninja.variable('arThinFlags', ar_flags + thin_flag_to_add)
-  master_ninja.variable('ar_host', GetEnvironFallback(['AR_host'], 'ar'))
-  cc_host = GetEnvironFallback(['CC_host'], cc_host)
-  cxx_host = GetEnvironFallback(['CXX_host'], cxx_host)
-  ld_host = GetEnvironFallback(['LD_host'], ld_host)
-  arflags_host = GetEnvironFallback(['ARFLAGS_host'], ar_flags)
-  arthinflags_host = GetEnvironFallback(['ARTHINFLAGS_host'], arflags_host)
+    build_to_root = InvertRelativePath(build_dir)
+    for key, value in make_global_settings:
+      if key == 'CC':
+        cc = os.path.join(build_to_root, value)
+      if key == 'CXX':
+        cxx = os.path.join(build_to_root, value)
+      if key == 'LD':
+        ld = os.path.join(build_to_root, value)
+      if key == 'CC.host':
+        cc_host = os.path.join(build_to_root, value)
+        cc_host_global_setting = value
+      if key == 'CXX.host':
+        cxx_host = os.path.join(build_to_root, value)
+        cxx_host_global_setting = value
+      if key == 'LD.host':
+        ld_host = os.path.join(build_to_root, value)
 
-  # The environment variable could be used in 'make_global_settings', like
-  # ['CC.host', '$(CC)'] or ['CXX.host', '$(CXX)'], transform them here.
-  if '$(CC)' in cc_host and cc_host_global_setting:
-    cc_host = cc_host_global_setting.replace('$(CC)', cc)
-  if '$(CXX)' in cxx_host and cxx_host_global_setting:
-    cxx_host = cxx_host_global_setting.replace('$(CXX)', cxx)
-  master_ninja.variable('cc_host', cc_host)
-  master_ninja.variable('cxx_host', cxx_host)
-  master_ninja.variable('arFlags_host', arflags_host)
-  master_ninja.variable('arThinFlags_host', arthinflags_host)
-  master_ninja.variable('ld_host', ld_host)
+    flock = 'flock'
+    if flavor == 'mac':
+      flock = './gyp-mac-tool flock'
+    cc = GetEnvironFallback(['CC_target', 'CC'], cc)
+    master_ninja.variable('cc', cc)
+    cxx = GetEnvironFallback(['CXX_target', 'CXX'], cxx)
+    master_ninja.variable('cxx', cxx)
+    ld = GetEnvironFallback(['LD_target', 'LD'], ld)
+    rc = GetEnvironFallback(['RC'], 'rc.exe')
 
-  if sys.platform == 'cygwin':
-    python_path = cygpath.to_nt('/cygdrive/c/python_27_amd64/files/python.exe')
-  else:
-    python_path = 'python'
-  master_ninja.variable('python', python_path)
-  master_ninja.newline()
+    if not cc_host:
+      cc_host = cc
+    if not cxx_host:
+      cxx_host = cxx
 
-  master_ninja.pool('link_pool', depth=GetDefaultConcurrentLinks())
-  master_ninja.newline()
+    # gyp-win-tool wrappers have a winpython only flock implementation.
+    if sys.platform == 'cygwin':
+      python_exec = '$python'
+    else:
+      python_exec = sys.executable
 
-  if flavor not in microsoft_flavors:
-    if flavor in sony_flavors:
-      # uca := Unnamed Console A
-      dep_format = 'snc' if (flavor in ['ps3']) else 'uca'
+    ar_flags = ''
+    if flavor in microsoft_flavors:
+      master_ninja.variable('ld', ld)
+      master_ninja.variable('ar', os.environ.get('AR', 'ar'))
+      master_ninja.variable('rc', rc)
+      master_ninja.variable('asm', 'ml.exe')
+      master_ninja.variable('mt', 'mt.exe')
+      master_ninja.variable('use_dep_database', '1')
+    elif flavor in sony_flavors:
+      # Require LD to be set.
+      master_ninja.variable('ld', os.environ.get('LD'))
+      master_ninja.variable('ar', os.environ.get('AR', 'ar'))
+      if flavor in ['ps3']:
+        master_ninja.variable('prx_export_pickup',
+                              os.environ['PRX_EXPORT_PICKUP'])
+      ar_flags = os.environ.get('ARFLAGS', 'rcs')
+      master_ninja.variable('arFlags', ar_flags)
+      # On the PS3, when we use ps3snarl.exe with a response file, we cannot
+      # pass it flags (like 'rcs'), so ARFLAGS is likely set to '' for this
+      # platform.  In that case, do not append the thin archive 'T' flag
+      # to the flags string.
+      # Likewise for PS4, but using orbis-snarl.exe
+      thin_flag_to_add = ''
+      if len(ar_flags) >= 1 and ar_flags.find('T') == -1:
+        thin_flag_to_add = 'T'
+      master_ninja.variable('arThinFlags', ar_flags + thin_flag_to_add)
+
+    else:
+      master_ninja.variable('ld', ld)
+      master_ninja.variable('ar', GetEnvironFallback(['AR_target', 'AR'], 'ar'))
+      ar_flags = os.environ.get('ARFLAGS', 'rcs')
+      master_ninja.variable('arFlags', ar_flags)
+      thin_flag_to_add = ''
+      if ar_flags.find('T') == -1:
+        thin_flag_to_add = 'T'
+      master_ninja.variable('arThinFlags', ar_flags + thin_flag_to_add)
+    master_ninja.variable('ar_host', GetEnvironFallback(['AR_host'], 'ar'))
+    cc_host = GetEnvironFallback(['CC_host'], cc_host)
+    cxx_host = GetEnvironFallback(['CXX_host'], cxx_host)
+    ld_host = GetEnvironFallback(['LD_host'], ld_host)
+    arflags_host = GetEnvironFallback(['ARFLAGS_host'], ar_flags)
+    arthinflags_host = GetEnvironFallback(['ARTHINFLAGS_host'], arflags_host)
+
+    # The environment variable could be used in 'make_global_settings', like
+    # ['CC.host', '$(CC)'] or ['CXX.host', '$(CXX)'], transform them here.
+    if '$(CC)' in cc_host and cc_host_global_setting:
+      cc_host = cc_host_global_setting.replace('$(CC)', cc)
+    if '$(CXX)' in cxx_host and cxx_host_global_setting:
+      cxx_host = cxx_host_global_setting.replace('$(CXX)', cxx)
+    master_ninja.variable('cc_host', cc_host)
+    master_ninja.variable('cxx_host', cxx_host)
+    master_ninja.variable('arFlags_host', arflags_host)
+    master_ninja.variable('arThinFlags_host', arthinflags_host)
+    master_ninja.variable('ld_host', ld_host)
+
+    if sys.platform == 'cygwin':
+      python_path = cygpath.to_nt(
+          '/cygdrive/c/python_27_amd64/files/python.exe')
+    else:
+      python_path = 'python'
+    master_ninja.variable('python', python_path)
+    master_ninja.newline()
+
+    master_ninja.pool('link_pool', depth=GetDefaultConcurrentLinks())
+    master_ninja.newline()
+
+    if flavor not in microsoft_flavors:
+      if flavor in sony_flavors:
+        # uca := Unnamed Console A
+        dep_format = 'snc' if (flavor in ['ps3']) else 'uca'
+        master_ninja.rule(
+            'cc',
+            description='CC $out',
+            command=('$cc @$out.rsp'),
+            rspfile='$out.rsp',
+            rspfile_content=('-c $in -o $out '
+                             '-MMD $defines $includes $cflags $cflags_c '
+                             '$cflags_pch_c'),
+            depfile='$out_no_ext.d',
+            deps='gcc',
+            depformat=dep_format)
+        master_ninja.rule(
+            'cxx',
+            description='CXX $out',
+            command=('$cxx @$out.rsp'),
+            rspfile='$out.rsp',
+            rspfile_content=('-c $in -o $out '
+                             '-MMD $defines $includes $cflags $cflags_cc '
+                             '$cflags_pch_cc'),
+            depfile='$out_no_ext.d',
+            deps='gcc',
+            depformat=dep_format)
+      else:
+        master_ninja.rule(
+            'cc',
+            description='CC $out',
+            command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_c '
+                     '$cflags_pch_c -c $in -o $out'),
+            deps='gcc',
+            depfile='$out.d')
+        master_ninja.rule(
+            'cc_s',
+            description='CC $out',
+            command=('$cc $defines $includes $cflags $cflags_c '
+                     '$cflags_pch_c -c $in -o $out'))
+        master_ninja.rule(
+            'cxx',
+            description='CXX $out',
+            command=(
+                '$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc '
+                '$cflags_pch_cc -c $in -o $out'),
+            deps='gcc',
+            depfile='$out.d')
+
+    else:
+      cc_command = ('$cc /nologo /showIncludes /FC '
+                    '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
+      cxx_command = ('$cxx /nologo /showIncludes /FC '
+                     '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
       master_ninja.rule(
           'cc',
           description='CC $out',
-          command=('$cc @$out.rsp'),
+          command=cc_command,
+          deps='msvc',
           rspfile='$out.rsp',
-          rspfile_content=('-c $in -o $out '
-                           '-MMD $defines $includes $cflags $cflags_c '
-                           '$cflags_pch_c'),
-          depfile='$out_no_ext.d',
-          deps='gcc',
-          depformat=dep_format)
+          rspfile_content='$defines $includes $cflags $cflags_c')
       master_ninja.rule(
           'cxx',
           description='CXX $out',
-          command=('$cxx @$out.rsp'),
+          command=cxx_command,
+          deps='msvc',
           rspfile='$out.rsp',
-          rspfile_content=('-c $in -o $out '
-                           '-MMD $defines $includes $cflags $cflags_cc '
-                           '$cflags_pch_cc'),
-          depfile='$out_no_ext.d',
-          deps='gcc',
-          depformat=dep_format)
+          rspfile_content='$defines $includes $cflags $cflags_cc')
+
+      master_ninja.rule(
+          'rc',
+          description='RC $in',
+          # Note: $in must be last otherwise rc.exe complains.
+          command=('%s gyp-win-tool rc-wrapper '
+                   '$arch $rc $defines $includes $rcflags /fo$out $in' %
+                   python_exec))
+      master_ninja.rule(
+          'asm',
+          description='ASM $in',
+          command=(
+              '%s gyp-win-tool asm-wrapper '
+              '$arch $asm $defines $includes /c /Fo $out $in' % python_exec))
+
+    if flavor not in (['mac'] + microsoft_flavors):
+      alink_command = 'rm -f $out && $ar $arFlags $out @$out.rsp'
+      # TODO: Use rcsT on Linux only.
+      alink_thin_command = 'rm -f $out && $ar $arThinFlags $out @$out.rsp'
+
+      ld_cmd = '$ld'
+
+      if flavor in sony_flavors and is_windows:
+        alink_command = 'cmd.exe /c ' + alink_command
+        alink_thin_command = 'cmd.exe /c ' + alink_thin_command
+        ld_cmd = '%s gyp-win-tool link-wrapper $arch $ld' % python_exec
+
+      master_ninja.rule(
+          'alink',
+          description='AR $out',
+          command=alink_command,
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline')
+      master_ninja.rule(
+          'alink_thin',
+          description='AR $out',
+          command=alink_thin_command,
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline')
+
+      if flavor in ['ps3']:
+        # TODO: Can we suppress the warnings from verlog.txt rather than
+        # rm'ing it?
+        ld_cmd = 'rm -f $verlog && ' + ld_cmd
+        if is_windows:
+          ld_cmd = 'cmd.exe /c ' + ld_cmd
+
+        prx_flags = '--oformat=fsprx --prx-with-runtime --zgenprx -zgenstub'
+        master_ninja.rule(
+            'solink',
+            description='LINK(PRX) $lib',
+            restat=True,
+            command=ld_cmd + ' @$prx.rsp',
+            rspfile='$prx.rsp',
+            rspfile_content='$ldflags %s -o $prx $in $libs' % prx_flags,
+            pool='link_pool')
+        master_ninja.rule(
+            'prx_export_pickup',
+            description='PRX-EXPORT-PICKUP $out',
+            command='$prx_export_pickup --output-src=$out $in')
+
+      else:  # Assume it is a Linux platform
+        # This allows targets that only need to depend on $lib's API to declare
+        # an order-only dependency on $lib.TOC and avoid relinking such
+        # downstream dependencies when $lib changes only in non-public ways.
+        # The resulting string leaves an uninterpolated %{suffix} which
+        # is used in the final substitution below.
+        mtime_preserving_solink_base = (
+            'if [ ! -e $lib -o ! -e ${lib}.TOC ]; then %(solink)s && '
+            '%(extract_toc)s > ${lib}.TOC; else %(solink)s && %(extract_toc)s '
+            '> ${lib}.tmp && if ! cmp -s ${lib}.tmp ${lib}.TOC; then mv '
+            '${lib}.tmp ${lib}.TOC ; fi; fi' % {
+                'solink': (
+                    ld_cmd +
+                    ' -shared $ldflags -o $lib -Wl,-soname=$soname %(suffix)s'),
+                'extract_toc': ('{ readelf -d ${lib} | grep SONAME ; '
+                                'nm -gD -f p ${lib} | cut -f1-2 -d\' \'; }')
+            })
+
+        master_ninja.rule(
+            'solink',
+            description='SOLINK $lib',
+            restat=True,
+            command=(mtime_preserving_solink_base % {
+                'suffix':
+                    '-Wl,--whole-archive $in $solibs -Wl,--no-whole-archive '
+                    '$libs'
+            }))
+        master_ninja.rule(
+            'solink_module',
+            description='SOLINK(module) $lib',
+            restat=True,
+            command=(mtime_preserving_solink_base % {
+                'suffix': '-Wl,--start-group $in $solibs -Wl,--end-group $libs'
+            }))
+
+      if flavor in sony_flavors:
+        # PS3 and PS4 linkers don't know about rpath.
+        rpath = ''
+      else:
+        rpath = r'-Wl,-rpath=\$$ORIGIN/lib'
+
+      master_ninja.rule(
+          'link',
+          description='LINK $out',
+          command=(ld_cmd + ' @$out.rsp'),
+          rspfile='$out.rsp',
+          rspfile_content=('$ldflags -o $out %s -Wl,--start-group $in $solibs '
+                           '-Wl,--end-group $libs' % rpath),
+          pool='link_pool')
+    elif flavor in microsoft_flavors:
+      master_ninja.rule(
+          'alink',
+          description='LIB $out',
+          command=(
+              '%s gyp-win-tool link-wrapper $arch '
+              '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' % python_exec),
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline $libflags')
+      dlldesc = 'LINK(DLL) $dll'
+      dllcmd = ('%s gyp-win-tool link-wrapper $arch '
+                '$ld /nologo $implibflag /DLL /OUT:$dll '
+                '/PDB:$dll.pdb @$dll.rsp' % python_exec)
+      if not flavor in microsoft_flavors:
+        # XB1 doesn't need a manifest.
+        dllcmd += (
+            ' && %s gyp-win-tool manifest-wrapper $arch '
+            '$mt -nologo -manifest $manifests -out:$dll.manifest' % python_exec)
+      master_ninja.rule(
+          'solink',
+          description=dlldesc,
+          command=dllcmd,
+          rspfile='$dll.rsp',
+          rspfile_content='$libs $in_newline $ldflags',
+          restat=True)
+      master_ninja.rule(
+          'solink_module',
+          description=dlldesc,
+          command=dllcmd,
+          rspfile='$dll.rsp',
+          rspfile_content='$libs $in_newline $ldflags',
+          restat=True)
+      # Note that ldflags goes at the end so that it has the option of
+      # overriding default settings earlier in the command line.
+      if flavor == 'win':
+        link_command = ('%s gyp-win-tool link-wrapper $arch '
+                        '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp && '
+                        '%s gyp-win-tool manifest-wrapper $arch '
+                        '$mt -nologo -manifest $manifests -out:$out.manifest' %
+                        (python_exec, python_exec))
+      else:
+        assert flavor in microsoft_flavors
+        # XB1 doesn't need a manifest.
+        link_command = ('%s gyp-win-tool link-wrapper $arch '
+                        '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp' %
+                        (python_exec))
+
+      master_ninja.rule(
+          'link',
+          description='LINK $out',
+          command=link_command,
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline $libs $ldflags',
+          pool='link_pool')
     else:
       master_ninja.rule(
-          'cc',
-          description='CC $out',
-          command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_c '
-                   '$cflags_pch_c -c $in -o $out'),
-          deps='gcc',
+          'objc',
+          description='OBJC $out',
+          command=(
+              '$cc -MMD -MF $out.d $defines $includes $cflags $cflags_objc '
+              '$cflags_pch_objc -c $in -o $out'),
           depfile='$out.d')
       master_ninja.rule(
-          'cc_s',
-          description='CC $out',
-          command=('$cc $defines $includes $cflags $cflags_c '
-                   '$cflags_pch_c -c $in -o $out'))
-      master_ninja.rule(
-          'cxx',
-          description='CXX $out',
-          command=('$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_cc '
-                   '$cflags_pch_cc -c $in -o $out'),
-          deps='gcc',
+          'objcxx',
+          description='OBJCXX $out',
+          command=(
+              '$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_objcc '
+              '$cflags_pch_objcc -c $in -o $out'),
           depfile='$out.d')
-
-  else:
-    cc_command = ('$cc /nologo /showIncludes /FC '
-                  '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
-    cxx_command = ('$cxx /nologo /showIncludes /FC '
-                   '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
-    master_ninja.rule(
-        'cc',
-        description='CC $out',
-        command=cc_command,
-        deps='msvc',
-        rspfile='$out.rsp',
-        rspfile_content='$defines $includes $cflags $cflags_c')
-    master_ninja.rule(
-        'cxx',
-        description='CXX $out',
-        command=cxx_command,
-        deps='msvc',
-        rspfile='$out.rsp',
-        rspfile_content='$defines $includes $cflags $cflags_cc')
-
-    master_ninja.rule(
-        'rc',
-        description='RC $in',
-        # Note: $in must be last otherwise rc.exe complains.
-        command=(
-            '%s gyp-win-tool rc-wrapper '
-            '$arch $rc $defines $includes $rcflags /fo$out $in' % python_exec))
-    master_ninja.rule(
-        'asm',
-        description='ASM $in',
-        command=('%s gyp-win-tool asm-wrapper '
-                 '$arch $asm $defines $includes /c /Fo $out $in' % python_exec))
-
-  if flavor not in (['mac'] + microsoft_flavors):
-    alink_command = 'rm -f $out && $ar $arFlags $out @$out.rsp'
-    # TODO: Use rcsT on Linux only.
-    alink_thin_command = 'rm -f $out && $ar $arThinFlags $out @$out.rsp'
-
-    ld_cmd = '$ld'
-
-    if flavor in sony_flavors and is_windows:
-      alink_command = 'cmd.exe /c ' + alink_command
-      alink_thin_command = 'cmd.exe /c ' + alink_thin_command
-      ld_cmd = '%s gyp-win-tool link-wrapper $arch $ld' % python_exec
-
-    master_ninja.rule(
-        'alink',
-        description='AR $out',
-        command=alink_command,
-        rspfile='$out.rsp',
-        rspfile_content='$in_newline')
-    master_ninja.rule(
-        'alink_thin',
-        description='AR $out',
-        command=alink_thin_command,
-        rspfile='$out.rsp',
-        rspfile_content='$in_newline')
-
-    if flavor in ['ps3']:
-      # TODO: Can we suppress the warnings from verlog.txt rather than
-      # rm'ing it?
-      ld_cmd = 'rm -f $verlog && ' + ld_cmd
-      if is_windows:
-        ld_cmd = 'cmd.exe /c ' + ld_cmd
-
-      prx_flags = '--oformat=fsprx --prx-with-runtime --zgenprx -zgenstub'
       master_ninja.rule(
-          'solink',
-          description='LINK(PRX) $lib',
-          restat=True,
-          command=ld_cmd + ' @$prx.rsp',
-          rspfile='$prx.rsp',
-          rspfile_content='$ldflags %s -o $prx $in $libs' % prx_flags,
-          pool='link_pool')
-      master_ninja.rule(
-          'prx_export_pickup',
-          description='PRX-EXPORT-PICKUP $out',
-          command='$prx_export_pickup --output-src=$out $in')
+          'alink',
+          description='LIBTOOL-STATIC $out, POSTBUILDS',
+          command='rm -f $out && '
+          './gyp-mac-tool filter-libtool libtool $libtool_flags '
+          '-static -o $out $in'
+          '$postbuilds')
 
-    else:  # Assume it is a Linux platform
-      # This allows targets that only need to depend on $lib's API to declare an
-      # order-only dependency on $lib.TOC and avoid relinking such downstream
-      # dependencies when $lib changes only in non-public ways.
-      # The resulting string leaves an uninterpolated %{suffix} which
-      # is used in the final substitution below.
+      # Record the public interface of $lib in $lib.TOC. See the corresponding
+      # comment in the posix section above for details.
       mtime_preserving_solink_base = (
-          'if [ ! -e $lib -o ! -e ${lib}.TOC ]; then '
-          '%(solink)s && %(extract_toc)s > ${lib}.TOC; else '
+          'if [ ! -e $lib -o ! -e ${lib}.TOC ] || '
+          # Always force dependent targets to relink if this library
+          # reexports something. Handling this correctly would require
+          # recursive TOC dumping but this is rare in practice, so punt.
+          'otool -l $lib | grep -q LC_REEXPORT_DYLIB ; then '
+          '%(solink)s && %(extract_toc)s > ${lib}.TOC; '
+          'else '
           '%(solink)s && %(extract_toc)s > ${lib}.tmp && '
-          'if ! cmp -s ${lib}.tmp ${lib}.TOC; then mv ${lib}.tmp ${lib}.TOC ; '
-          'fi; fi' % {
-              'solink':
-                  (ld_cmd +
-                   ' -shared $ldflags -o $lib -Wl,-soname=$soname %(suffix)s'),
-              'extract_toc': ('{ readelf -d ${lib} | grep SONAME ; '
-                              'nm -gD -f p ${lib} | cut -f1-2 -d\' \'; }')
+          'if ! cmp -s ${lib}.tmp ${lib}.TOC; then '
+          'mv ${lib}.tmp ${lib}.TOC ; '
+          'fi; '
+          'fi' % {
+              'solink': '$ld -shared $ldflags -o $lib %(suffix)s',
+              'extract_toc':
+                  '{ otool -l $lib | grep LC_ID_DYLIB -A 5; '
+                  'nm -gP $lib | cut -f1-2 -d\' \' | grep -v U$$; true; }'
           })
 
+      # TODO(thakis): The solink_module rule is likely wrong. Xcode seems to
+      # pass -bundle -single_module here (for osmesa.so).
       master_ninja.rule(
           'solink',
-          description='SOLINK $lib',
+          description='SOLINK $lib, POSTBUILDS',
           restat=True,
           command=(mtime_preserving_solink_base % {
-              'suffix':
-                  '-Wl,--whole-archive $in $solibs -Wl,--no-whole-archive '
-                  '$libs'
+              'suffix': '$in $solibs $libs$postbuilds'
           }))
       master_ninja.rule(
           'solink_module',
-          description='SOLINK(module) $lib',
+          description='SOLINK(module) $lib, POSTBUILDS',
           restat=True,
           command=(mtime_preserving_solink_base % {
-              'suffix': '-Wl,--start-group $in $solibs -Wl,--end-group $libs'
+              'suffix': '$in $solibs $libs$postbuilds'
           }))
 
-    if flavor in sony_flavors:
-      # PS3 and PS4 linkers don't know about rpath.
-      rpath = ''
+      master_ninja.rule(
+          'link',
+          description='LINK $out, POSTBUILDS',
+          command=('$ld $ldflags -o $out '
+                   '$in $solibs $libs$postbuilds'),
+          pool='link_pool')
+      master_ninja.rule(
+          'infoplist',
+          description='INFOPLIST $out',
+          command=('$cc -E -P -Wno-trigraphs -x c $defines $in -o $out && '
+                   'plutil -convert xml1 $out $out'))
+      master_ninja.rule(
+          'mac_tool',
+          description='MACTOOL $mactool_cmd $in',
+          command='$env ./gyp-mac-tool $mactool_cmd $in $out')
+      master_ninja.rule(
+          'package_framework',
+          description='PACKAGE FRAMEWORK $out, POSTBUILDS',
+          command='./gyp-mac-tool package-framework $out $version$postbuilds '
+          '&& touch $out')
+    if flavor in microsoft_flavors:
+      master_ninja.rule(
+          'stamp',
+          description='STAMP $out',
+          command='%s gyp-win-tool stamp $out' % python_exec)
+      master_ninja.rule(
+          'copy',
+          description='COPY $in $out',
+          command='%s gyp-win-tool recursive-mirror $in $out' % python_exec)
+    elif sys.platform in ['cygwin', 'win32']:
+      master_ninja.rule(
+          'stamp',
+          description='STAMP $out',
+          command='$python gyp-win-tool stamp $out')
+      master_ninja.rule(
+          'copy',
+          description='COPY $in $out',
+          command='$python gyp-win-tool recursive-mirror $in $out')
     else:
-      rpath = r'-Wl,-rpath=\$$ORIGIN/lib'
+      master_ninja.rule(
+          'stamp', description='STAMP $out', command='${postbuilds}touch $out')
+      master_ninja.rule(
+          'copy',
+          description='COPY $in $out',
+          command='rm -rf $out && cp -af $in $out')
+    master_ninja.newline()
 
-    master_ninja.rule(
-        'link',
-        description='LINK $out',
-        command=(ld_cmd + ' @$out.rsp'),
-        rspfile='$out.rsp',
-        rspfile_content=('$ldflags -o $out %s -Wl,--start-group $in $solibs '
-                         '-Wl,--end-group $libs' % rpath),
-        pool='link_pool')
-  elif flavor in microsoft_flavors:
-    master_ninja.rule(
-        'alink',
-        description='LIB $out',
-        command=('%s gyp-win-tool link-wrapper $arch '
-                 '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' % python_exec),
-        rspfile='$out.rsp',
-        rspfile_content='$in_newline $libflags')
-    dlldesc = 'LINK(DLL) $dll'
-    dllcmd = ('%s gyp-win-tool link-wrapper $arch '
-              '$ld /nologo $implibflag /DLL /OUT:$dll '
-              '/PDB:$dll.pdb @$dll.rsp' % python_exec)
-    if not flavor in microsoft_flavors:
-      # XB1 doesn't need a manifest.
-      dllcmd += (
-          ' && %s gyp-win-tool manifest-wrapper $arch '
-          '$mt -nologo -manifest $manifests -out:$dll.manifest' % python_exec)
-    master_ninja.rule(
-        'solink',
-        description=dlldesc,
-        command=dllcmd,
-        rspfile='$dll.rsp',
-        rspfile_content='$libs $in_newline $ldflags',
-        restat=True)
-    master_ninja.rule(
-        'solink_module',
-        description=dlldesc,
-        command=dllcmd,
-        rspfile='$dll.rsp',
-        rspfile_content='$libs $in_newline $ldflags',
-        restat=True)
-    # Note that ldflags goes at the end so that it has the option of
-    # overriding default settings earlier in the command line.
-    if flavor == 'win':
-      link_command = ('%s gyp-win-tool link-wrapper $arch '
-                      '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp && '
-                      '%s gyp-win-tool manifest-wrapper $arch '
-                      '$mt -nologo -manifest $manifests -out:$out.manifest' %
-                      (python_exec, python_exec))
-    else:
-      assert flavor in microsoft_flavors
-      # XB1 doesn't need a manifest.
+    # Output host building rules
+    if is_windows:
+      cc_command = ('$cc /nologo /showIncludes /FC '
+                    '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
+      cxx_command = ('$cxx /nologo /showIncludes /FC '
+                     '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
+      master_ninja.rule(
+          'cc_host',
+          description='CC_HOST $out',
+          command=cc_command,
+          deps='msvc',
+          rspfile='$out.rsp',
+          rspfile_content='$defines $includes $cflags_host $cflags_c_host')
+      master_ninja.rule(
+          'cxx_host',
+          description='CXX_HOST $out',
+          command=cxx_command,
+          deps='msvc',
+          rspfile='$out.rsp',
+          rspfile_content='$defines $includes $cflags_host $cflags_cc_host')
+
+      master_ninja.rule(
+          'alink_host',
+          description='LIB_HOST $out',
+          command=(
+              '%s gyp-win-tool link-wrapper $arch '
+              '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' % python_exec),
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline $libflags_host')
+
+      master_ninja.rule(
+          'alink_thin_host',
+          description='LIB_HOST $out',
+          command=(
+              '%s gyp-win-tool link-wrapper $arch '
+              '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' % python_exec),
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline $libflags_host')
+
       link_command = ('%s gyp-win-tool link-wrapper $arch '
                       '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp' %
                       (python_exec))
 
-    master_ninja.rule(
-        'link',
-        description='LINK $out',
-        command=link_command,
-        rspfile='$out.rsp',
-        rspfile_content='$in_newline $libs $ldflags',
-        pool='link_pool')
-  else:
-    master_ninja.rule(
-        'objc',
-        description='OBJC $out',
-        command=('$cc -MMD -MF $out.d $defines $includes $cflags $cflags_objc '
-                 '$cflags_pch_objc -c $in -o $out'),
-        depfile='$out.d')
-    master_ninja.rule(
-        'objcxx',
-        description='OBJCXX $out',
-        command=(
-            '$cxx -MMD -MF $out.d $defines $includes $cflags $cflags_objcc '
-            '$cflags_pch_objcc -c $in -o $out'),
-        depfile='$out.d')
-    master_ninja.rule(
-        'alink',
-        description='LIBTOOL-STATIC $out, POSTBUILDS',
-        command='rm -f $out && '
-        './gyp-mac-tool filter-libtool libtool $libtool_flags '
-        '-static -o $out $in'
-        '$postbuilds')
+      master_ninja.rule(
+          'link_host',
+          description='LINK_HOST $out',
+          command=link_command,
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline $libs $ldflags',
+          pool='link_pool')
+    else:
+      cc_command = 'bash -c "$cc_host @$out.rsp"'
+      cxx_command = 'bash -c "$cxx_host @$out.rsp"'
+      master_ninja.rule(
+          'cc_host',
+          description='CC_HOST $out',
+          command=cc_command,
+          rspfile='$out.rsp',
+          rspfile_content=('-MMD -MF $out.d $defines $includes $cflags_host '
+                           '$cflags_c_host $cflags_pch_c -c $in -o $out'),
+          depfile='$out.d')
+      master_ninja.rule(
+          'cxx_host',
+          description='CXX_HOST $out',
+          command=cxx_command,
+          rspfile='$out.rsp',
+          rspfile_content=('-MMD -MF $out.d $defines $includes $cflags_host '
+                           '$cflags_cc_host $cflags_pch_cc -c $in -o $out'),
+          depfile='$out.d')
 
-    # Record the public interface of $lib in $lib.TOC. See the corresponding
-    # comment in the posix section above for details.
-    mtime_preserving_solink_base = (
-        'if [ ! -e $lib -o ! -e ${lib}.TOC ] || '
-        # Always force dependent targets to relink if this library
-        # reexports something. Handling this correctly would require
-        # recursive TOC dumping but this is rare in practice, so punt.
-        'otool -l $lib | grep -q LC_REEXPORT_DYLIB ; then '
-        '%(solink)s && %(extract_toc)s > ${lib}.TOC; '
-        'else '
-        '%(solink)s && %(extract_toc)s > ${lib}.tmp && '
-        'if ! cmp -s ${lib}.tmp ${lib}.TOC; then '
-        'mv ${lib}.tmp ${lib}.TOC ; '
-        'fi; '
-        'fi' % {
-            'solink': '$ld -shared $ldflags -o $lib %(suffix)s',
-            'extract_toc':
-                '{ otool -l $lib | grep LC_ID_DYLIB -A 5; '
-                'nm -gP $lib | cut -f1-2 -d\' \' | grep -v U$$; true; }'
-        })
+      alink_command = 'rm -f $out && $ar_host $arFlags_host $out @$out.rsp'
+      alink_thin_command = ('rm -f $out && $ar_host $arThinFlags_host $out '
+                            '@$out.rsp')
 
-    # TODO(thakis): The solink_module rule is likely wrong. Xcode seems to pass
-    # -bundle -single_module here (for osmesa.so).
-    master_ninja.rule(
-        'solink',
-        description='SOLINK $lib, POSTBUILDS',
-        restat=True,
-        command=(mtime_preserving_solink_base % {
-            'suffix': '$in $solibs $libs$postbuilds'
-        }))
-    master_ninja.rule(
-        'solink_module',
-        description='SOLINK(module) $lib, POSTBUILDS',
-        restat=True,
-        command=(mtime_preserving_solink_base % {
-            'suffix': '$in $solibs $libs$postbuilds'
-        }))
-
-    master_ninja.rule(
-        'link',
-        description='LINK $out, POSTBUILDS',
-        command=('$ld $ldflags -o $out '
-                 '$in $solibs $libs$postbuilds'),
-        pool='link_pool')
-    master_ninja.rule(
-        'infoplist',
-        description='INFOPLIST $out',
-        command=('$cc -E -P -Wno-trigraphs -x c $defines $in -o $out && '
-                 'plutil -convert xml1 $out $out'))
-    master_ninja.rule(
-        'mac_tool',
-        description='MACTOOL $mactool_cmd $in',
-        command='$env ./gyp-mac-tool $mactool_cmd $in $out')
-    master_ninja.rule(
-        'package_framework',
-        description='PACKAGE FRAMEWORK $out, POSTBUILDS',
-        command='./gyp-mac-tool package-framework $out $version$postbuilds '
-        '&& touch $out')
-  if flavor in microsoft_flavors:
-    master_ninja.rule(
-        'stamp',
-        description='STAMP $out',
-        command='%s gyp-win-tool stamp $out' % python_exec)
-    master_ninja.rule(
-        'copy',
-        description='COPY $in $out',
-        command='%s gyp-win-tool recursive-mirror $in $out' % python_exec)
-  elif sys.platform in ['cygwin', 'win32']:
-    master_ninja.rule(
-        'stamp',
-        description='STAMP $out',
-        command='$python gyp-win-tool stamp $out')
-    master_ninja.rule(
-        'copy',
-        description='COPY $in $out',
-        command='$python gyp-win-tool recursive-mirror $in $out')
-  else:
-    master_ninja.rule(
-        'stamp', description='STAMP $out', command='${postbuilds}touch $out')
-    master_ninja.rule(
-        'copy',
-        description='COPY $in $out',
-        command='rm -rf $out && cp -af $in $out')
-  master_ninja.newline()
-
-  # Output host building rules
-  if is_windows:
-    cc_command = ('$cc /nologo /showIncludes /FC '
-                  '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
-    cxx_command = ('$cxx /nologo /showIncludes /FC '
-                   '@$out.rsp /c $in /Fo$out /Fd$pdbname ')
-    master_ninja.rule(
-        'cc_host',
-        description='CC_HOST $out',
-        command=cc_command,
-        deps='msvc',
-        rspfile='$out.rsp',
-        rspfile_content='$defines $includes $cflags_host $cflags_c_host')
-    master_ninja.rule(
-        'cxx_host',
-        description='CXX_HOST $out',
-        command=cxx_command,
-        deps='msvc',
-        rspfile='$out.rsp',
-        rspfile_content='$defines $includes $cflags_host $cflags_cc_host')
-
-    master_ninja.rule(
-        'alink_host',
-        description='LIB_HOST $out',
-        command=('%s gyp-win-tool link-wrapper $arch '
-                 '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' % python_exec),
-        rspfile='$out.rsp',
-        rspfile_content='$in_newline $libflags_host')
-
-    master_ninja.rule(
-        'alink_thin_host',
-        description='LIB_HOST $out',
-        command=('%s gyp-win-tool link-wrapper $arch '
-                 '$ar /nologo /ignore:4221 /OUT:$out @$out.rsp' % python_exec),
-        rspfile='$out.rsp',
-        rspfile_content='$in_newline $libflags_host')
-
-    link_command = ('%s gyp-win-tool link-wrapper $arch '
-                    '$ld /nologo /OUT:$out /PDB:$out.pdb @$out.rsp' %
-                    (python_exec))
-
-    master_ninja.rule(
-        'link_host',
-        description='LINK_HOST $out',
-        command=link_command,
-        rspfile='$out.rsp',
-        rspfile_content='$in_newline $libs $ldflags',
-        pool='link_pool')
-  else:
-    cc_command = 'bash -c "$cc_host @$out.rsp"'
-    cxx_command = 'bash -c "$cxx_host @$out.rsp"'
-    master_ninja.rule(
-        'cc_host',
-        description='CC_HOST $out',
-        command=cc_command,
-        rspfile='$out.rsp',
-        rspfile_content=('-MMD -MF $out.d $defines $includes $cflags_host '
-                         '$cflags_c_host $cflags_pch_c -c $in -o $out'),
-        depfile='$out.d')
-    master_ninja.rule(
-        'cxx_host',
-        description='CXX_HOST $out',
-        command=cxx_command,
-        rspfile='$out.rsp',
-        rspfile_content=('-MMD -MF $out.d $defines $includes $cflags_host '
-                         '$cflags_cc_host $cflags_pch_cc -c $in -o $out'),
-        depfile='$out.d')
-
-    alink_command = 'rm -f $out && $ar_host $arFlags_host $out @$out.rsp'
-    alink_thin_command = ('rm -f $out && $ar_host $arThinFlags_host $out '
-                          '@$out.rsp')
-
-    master_ninja.rule(
-        'alink_host',
-        description='AR_HOST $out',
-        command='bash -c "' + alink_command + '"',
-        rspfile='$out.rsp',
-        rspfile_content='$in_newline')
-    master_ninja.rule(
-        'alink_thin_host',
-        description='AR_HOST $out',
-        command='bash -c "' + alink_thin_command + '"',
-        rspfile='$out.rsp',
-        rspfile_content='$in_newline')
-    beginlinkinlibs = ''
-    endlinkinlibs = ''
-    if is_linux:
-      beginlinkinlibs = '-Wl,--start-group'
-      endlinkinlibs = '-Wl,--end-group'
-    rpath = '-Wl,-rpath=\$$ORIGIN/lib'
-    master_ninja.rule(
-        'link_host',
-        description='LINK_HOST $out',
-        command=('bash -c "$ld_host $ldflags_host -o $out %s '
-                 '%s $in $solibs %s $libs"' % (rpath, beginlinkinlibs,
-                                               endlinkinlibs)))
+      master_ninja.rule(
+          'alink_host',
+          description='AR_HOST $out',
+          command='bash -c "' + alink_command + '"',
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline')
+      master_ninja.rule(
+          'alink_thin_host',
+          description='AR_HOST $out',
+          command='bash -c "' + alink_thin_command + '"',
+          rspfile='$out.rsp',
+          rspfile_content='$in_newline')
+      beginlinkinlibs = ''
+      endlinkinlibs = ''
+      if is_linux:
+        beginlinkinlibs = '-Wl,--start-group'
+        endlinkinlibs = '-Wl,--end-group'
+      rpath = '-Wl,-rpath=\$$ORIGIN/lib'
+      master_ninja.rule(
+          'link_host',
+          description='LINK_HOST $out',
+          command=('bash -c "$ld_host $ldflags_host -o $out %s '
+                   '%s $in $solibs %s $libs"' % (rpath, beginlinkinlibs,
+                                                 endlinkinlibs)))
 
   all_targets = set()
   for build_file in params['build_files']: