Import Cobalt 2.10060 2016-08-29
diff --git a/codereview.settings b/codereview.settings
new file mode 100644
index 0000000..1950c32
--- /dev/null
+++ b/codereview.settings
@@ -0,0 +1,3 @@
+GERRIT_HOST: cobalt-review.googlesource.com
+GERRIT_AUTODETECT_BRANCH: true
+CODE_REVIEW_SERVER: cobalt-review.googlesource.com
diff --git a/src/CONTRIBUTING.md b/src/CONTRIBUTING.md
new file mode 100644
index 0000000..bd99ed6
--- /dev/null
+++ b/src/CONTRIBUTING.md
@@ -0,0 +1,62 @@
+# Contributing to Cobalt
+
+We'd love to hear about how you would like to contribute to Cobalt! It's worth
+reading through this modest document first, to understand the process and to
+make sure you know what to expect.
+
+
+## Before You Contribute
+
+### As an Individual
+
+Before Cobalt can use your code, as an unaffiliated individual, you must sign
+the [Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual) (CLA), which you can do online.
+
+### As a Company
+
+If you are a company that wishes to have one or more employees contribute to
+Cobalt on-the-clock, that is covered by a different agreement, the
+[Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate).
+
+### What is a CLA?
+
+The Contributor License Agreement is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things — for instance that you'll tell us if
+you know that your code infringes on other people's patents. You don't have to
+sign the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+Before you start working on a larger contribution, you should get in touch with
+us first with your idea so that we can help out and possibly guide
+you. Coordinating up front makes it much easier to avoid frustration later on.
+
+
+### Code Reviews
+
+All submissions, including submissions by project members, require review. We
+currently use [Gerrit Code Review](https://www.gerritcodereview.com/) for this
+purpose. Currently, team-member submissions go through private reviews, and
+external submissions go through public reviews.
+
+
+## Submission Process
+
+We admit that this submission process is currently not completely optimized to
+make contributions easy, and we hope to make improvements to it in the
+future. It will always include some form of signing the CLA and submitting the
+code for review before merging changes into the Cobalt master tree.
+
+  1. Ensure you or your company have signed the appropriate CLA (see "Before You
+     Contribute" above).
+  1. Rebase your changes down into a single git commit.
+  1. Run `git cl upload` to upload the review to
+     [Cobalt's Gerrit instance](https://cobalt-review.googlesource.com/).
+  1. Someone from the maintainers team will review the code, putting up comments
+     on any things that need to change for submission.
+  1. If you need to make changes, make them locally, test them, then `git commit
+     --amend` to add them to the *existing* commit. Then return to step 2.
+  1. If you do not need to make any more changes, a maintainer will integrate
+     the change into our private repository, and it will get pushed out to the
+     public repository after some time.
+
diff --git a/src/README.cobalt.txt b/src/README.cobalt.txt
deleted file mode 100644
index bc2d9c7..0000000
--- a/src/README.cobalt.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This is a fork of the chromium repository at http://git.chromium.org/git/chromium.git
-
diff --git a/src/README.md b/src/README.md
index fb912c9..025610b 100644
--- a/src/README.md
+++ b/src/README.md
@@ -241,12 +241,12 @@
 optimized, with the most debug information at the top (debug) to the fastest,
 most optimized, and with the least debug information at the bottom (gold):
 
- | Type  | Optimizations | Logging | Asserts | Debug Info | Console  |
- | :---- | :------------ | :------ | :------ | :--------- | :------- |
- | debug | None          | Full    | Full    | Full       | Enabled  |
- | devel | Full          | Full    | Full    | Full       | Enabled  |
- | qa    | Full          | Limited | None    | None       | Enabled  |
- | gold  | Full          | None    | None    | None       | Disabled |
+ Type  | Optimizations | Logging | Asserts | Debug Info | Console
+ :---- | :------------ | :------ | :------ | :--------- | :-------
+ debug | None          | Full    | Full    | Full       | Enabled
+ devel | Full          | Full    | Full    | Full       | Enabled
+ qa    | Full          | Limited | None    | None       | Enabled
+ gold  | Full          | None    | None    | None       | Disabled
 
 When building for release, you should always use a gold build for the final
 product.
@@ -254,3 +254,9 @@
     $ cobalt/build/gyp_cobalt -C gold linux-x64x11
     $ ninja -C out/linux-x64x11_gold cobalt
     $ out/linux-x64x11_gold/cobalt
+
+
+## Origin of this Repository
+
+This is a fork of the chromium repository at http://git.chromium.org/git/chromium.git
+
diff --git a/src/base/debug/leak_annotations.h b/src/base/debug/leak_annotations.h
index 97be127..35a7bec 100644
--- a/src/base/debug/leak_annotations.h
+++ b/src/base/debug/leak_annotations.h
@@ -7,6 +7,17 @@
 
 #include "build/build_config.h"
 
+// By default, Leak Sanitizer and Address Sanitizer is expected
+// to exist together. However, this is not true for all
+// platforms (e.g. PS4).
+// HAS_LEAK_SANTIZIER=0 explicitly removes the Leak Sanitizer from code.
+#ifdef ADDRESS_SANITIZER
+#ifndef HAS_LEAK_SANITIZER
+// Default is that Leak Sanitizer exists whenever Address Sanitizer does.
+#define HAS_LEAK_SANITIZER 1
+#endif
+#endif
+
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_NACL) && \
     defined(USE_HEAPCHECKER)
 
@@ -29,7 +40,7 @@
 #define ANNOTATE_LEAKING_OBJECT_PTR(X) \
     HeapLeakChecker::IgnoreObject(X)
 
-#elif defined(ADDRESS_SANITIZER)
+#elif defined(ADDRESS_SANITIZER) && HAS_LEAK_SANITIZER
 #include <sanitizer/lsan_interface.h>
 
 class ScopedLeakSanitizerDisabler {
diff --git a/src/base/synchronization/condition_variable_unittest.cc b/src/base/synchronization/condition_variable_unittest.cc
index bc8201f..49d138b 100644
--- a/src/base/synchronization/condition_variable_unittest.cc
+++ b/src/base/synchronization/condition_variable_unittest.cc
@@ -350,6 +350,9 @@
   // Game consoles don't support that many threads. We have a max threads
   // macro in pthread.h. Leave a few to system and test with the rest.
   const int kThreadCount = SHELL_MAX_THREADS - 8;
+#elif defined(ADDRESS_SANITIZER)
+  // AddressSanitizer adds additional stack space to the threads.
+  const int kThreadCount = 50;
 #elif defined(OS_STARBOARD)
   const int kThreadCount = SB_MAX_THREADS - 8;
 #else
diff --git a/src/cobalt/account/starboard/account_manager.cc b/src/cobalt/account/starboard/account_manager.cc
index e6b4834..3a546bb 100644
--- a/src/cobalt/account/starboard/account_manager.cc
+++ b/src/cobalt/account/starboard/account_manager.cc
@@ -18,6 +18,7 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "cobalt/base/event_dispatcher.h"
 #include "starboard/user.h"
@@ -88,16 +89,13 @@
   return GetCurrentUserProperty(kSbUserPropertyUserId);
 }
 
-void AccountManagerStarboard::StartSignIn() { SbUserStartSignIn(); }
+void AccountManagerStarboard::StartSignIn() {
+  NOTREACHED() << "Should be handled internally by platform.";
+}
 
 bool AccountManagerStarboard::IsAgeRestricted() {
-  SbUser user = SbUserGetCurrent();
-
-  if (!SbUserIsValid(user)) {
-    return false;
-  }
-
-  return SbUserIsAgeRestricted(user);
+  NOTREACHED() << "Should be handled internally by platform.";
+  return false;
 }
 
 }  // namespace account
diff --git a/src/cobalt/audio/audio_device.cc b/src/cobalt/audio/audio_device.cc
index 9a9e092..5f8d205 100644
--- a/src/cobalt/audio/audio_device.cc
+++ b/src/cobalt/audio/audio_device.cc
@@ -45,6 +45,38 @@
 
 #if defined(SB_USE_SB_AUDIO_SINK)
 
+namespace {
+// Helper function to compute the size of the two valid starboard audio sample
+// types.
+size_t GetSampleSize(SbMediaAudioSampleType sample_type) {
+  switch (sample_type) {
+    case kSbMediaAudioSampleTypeFloat32:
+      return sizeof(float);
+    case kSbMediaAudioSampleTypeInt16:
+      return sizeof(int16);
+  }
+  NOTREACHED();
+  return 0u;
+}
+
+const float kMaxInt16AsFloat32 = 32767.0f;
+
+template <typename SourceType, typename DestType>
+DestType ConvertSample(SourceType sample);
+
+template <>
+int16 ConvertSample<float, int16>(float sample) {
+  DCHECK(-1.0 <= sample && sample <= 1.0)
+      << "Sample of type float32 must lie on interval [-1.0, 1.0]";
+  return static_cast<int16>(sample * kMaxInt16AsFloat32);
+}
+
+template <>
+float ConvertSample<float, float>(float sample) {
+  return sample;
+}
+}  // namespace
+
 class AudioDevice::Impl {
  public:
   Impl(int number_of_channels, RenderCallback* callback);
@@ -62,7 +94,11 @@
 
   void FillOutputAudioBus();
 
+  template <typename OutputType>
+  inline void FillOutputAudioBusForType();
+
   int number_of_channels_;
+  SbMediaAudioSampleType output_sample_type_;
   RenderCallback* render_callback_;
 
   // The |render_callback_| returns audio data in planar form.  So we read it
@@ -70,11 +106,14 @@
   // |output_frame_buffer_|.
   ShellAudioBus input_audio_bus_;
 
-  std::vector<float> output_frame_buffer_;
+  scoped_array<uint8> output_frame_buffer_;
+
   void* frame_buffers_[1];
   int64 frames_rendered_;  // Frames retrieved from |render_callback_|.
   int64 frames_consumed_;  // Accumulated frames consumed reported by the sink.
 
+  bool was_silence_last_update_;
+
   SbAudioSink audio_sink_;
 
   DISALLOW_COPY_AND_ASSIGN(Impl);
@@ -83,13 +122,19 @@
 // AudioDevice::Impl.
 AudioDevice::Impl::Impl(int number_of_channels, RenderCallback* callback)
     : number_of_channels_(number_of_channels),
+      output_sample_type_(
+          SbAudioSinkIsAudioSampleTypeSupported(kSbMediaAudioSampleTypeFloat32)
+              ? kSbMediaAudioSampleTypeFloat32
+              : kSbMediaAudioSampleTypeInt16),
       render_callback_(callback),
       input_audio_bus_(static_cast<size_t>(number_of_channels),
                        static_cast<size_t>(kRenderBufferSizeFrames),
                        ShellAudioBus::kFloat32, ShellAudioBus::kPlanar),
-      output_frame_buffer_(kFramesPerChannel * number_of_channels),
+      output_frame_buffer_(new uint8[kFramesPerChannel * number_of_channels_ *
+                                       GetSampleSize(output_sample_type_)]),
       frames_rendered_(0),
       frames_consumed_(0),
+      was_silence_last_update_(false),
       audio_sink_(kSbAudioSinkInvalid) {
   DCHECK(number_of_channels_ == 1 || number_of_channels_ == 2)
       << "Invalid number of channels: " << number_of_channels_;
@@ -97,15 +142,14 @@
   DCHECK(SbAudioSinkIsAudioFrameStorageTypeSupported(
       kSbMediaAudioFrameStorageTypeInterleaved))
       << "Only interleaved frame storage is supported.";
-  DCHECK(SbAudioSinkIsAudioSampleTypeSupported(kSbMediaAudioSampleTypeFloat32))
-      << "Only float sample is supported.";
+  DCHECK(SbAudioSinkIsAudioSampleTypeSupported(output_sample_type_))
+      << "Output sample type " << output_sample_type_ << " is not supported";
 
-  frame_buffers_[0] = &output_frame_buffer_[0];
+  frame_buffers_[0] = output_frame_buffer_.get();
   audio_sink_ = SbAudioSinkCreate(
-      number_of_channels_, kStandardOutputSampleRate,
-      kSbMediaAudioSampleTypeFloat32, kSbMediaAudioFrameStorageTypeInterleaved,
-      frame_buffers_, kFramesPerChannel,
-      &AudioDevice::Impl::UpdateSourceStatusFunc,
+      number_of_channels_, kStandardOutputSampleRate, output_sample_type_,
+      kSbMediaAudioFrameStorageTypeInterleaved, frame_buffers_,
+      kFramesPerChannel, &AudioDevice::Impl::UpdateSourceStatusFunc,
       &AudioDevice::Impl::ConsumeFramesFunc, this);
   DCHECK(SbAudioSinkIsValid(audio_sink_));
 }
@@ -155,7 +199,12 @@
   if ((kFramesPerChannel - *frames_in_buffer) >= kRenderBufferSizeFrames) {
     bool silence = false;
 
-    input_audio_bus_.ZeroAllFrames();
+    // If there was silence last time we were called, then the buffer has
+    // already been zeroed out and we don't need to do it again.
+    if (!was_silence_last_update_) {
+      input_audio_bus_.ZeroAllFrames();
+    }
+
     // Fill our temporary buffer with planar PCM float samples.
     render_callback_->FillAudioBus(&input_audio_bus_, &silence);
 
@@ -165,31 +214,46 @@
       frames_rendered_ += kRenderBufferSizeFrames;
       *frames_in_buffer += kRenderBufferSizeFrames;
     }
+
+    was_silence_last_update_ = silence;
   }
 
   *offset_in_frames = frames_consumed_ % kFramesPerChannel;
+  *is_playing = (frames_rendered_ != frames_consumed_);
 }
 
 void AudioDevice::Impl::ConsumeFrames(int frames_consumed) {
   frames_consumed_ += frames_consumed;
 }
 
-void AudioDevice::Impl::FillOutputAudioBus() {
+template <typename OutputType>
+inline void AudioDevice::Impl::FillOutputAudioBusForType() {
   // Determine the offset into the audio bus that represents the tail of
   // buffered data.
   uint64 channel_offset = frames_rendered_ % kFramesPerChannel;
 
-  float* output_buffer = &output_frame_buffer_[0];
+  OutputType* output_buffer =
+      reinterpret_cast<OutputType*>(output_frame_buffer_.get());
   output_buffer += channel_offset * number_of_channels_;
-
   for (size_t frame = 0; frame < kRenderBufferSizeFrames; ++frame) {
     for (size_t channel = 0; channel < input_audio_bus_.channels(); ++channel) {
-      *output_buffer = input_audio_bus_.GetFloat32Sample(channel, frame);
+      *output_buffer = ConvertSample<float, OutputType>(
+          input_audio_bus_.GetFloat32Sample(channel, frame));
       ++output_buffer;
     }
   }
 }
 
+void AudioDevice::Impl::FillOutputAudioBus() {
+  if (output_sample_type_ == kSbMediaAudioSampleTypeFloat32) {
+    FillOutputAudioBusForType<float>();
+  } else if (output_sample_type_ == kSbMediaAudioSampleTypeInt16) {
+    FillOutputAudioBusForType<int16>();
+  } else {
+    NOTREACHED();
+  }
+}
+
 #else  // defined(SB_USE_SB_AUDIO_SINK)
 
 class AudioDevice::Impl : public ::media::ShellAudioStream {
diff --git a/src/cobalt/base/c_val.cc b/src/cobalt/base/c_val.cc
index e719bb5..812433b 100644
--- a/src/cobalt/base/c_val.cc
+++ b/src/cobalt/base/c_val.cc
@@ -29,15 +29,15 @@
   // and so this allows its size to be more consistent (and avoids compiler
   // warnings on some platforms).
   registered_vars_ = new NameVarMap();
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
   on_changed_hook_set_ = new base::hash_set<OnChangedHook*>();
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
 }
 
 CValManager::~CValManager() {
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
   delete on_changed_hook_set_;
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
   delete registered_vars_;
 }
 
@@ -62,7 +62,7 @@
   }
 }
 
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
 void CValManager::PushValueChangedEvent(const CValDetail::CValBase* cval,
                                         const CValGenericValue& value) {
   base::AutoLock auto_lock(hooks_lock_);
@@ -92,7 +92,7 @@
   size_t values_erased ALLOW_UNUSED = cvm->on_changed_hook_set_->erase(this);
   DCHECK_EQ(values_erased, 1);
 }
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
 
 std::set<std::string> CValManager::GetOrderedCValNames() {
   std::set<std::string> ret;
diff --git a/src/cobalt/base/c_val.h b/src/cobalt/base/c_val.h
index 767fdb6..787f51a 100644
--- a/src/cobalt/base/c_val.h
+++ b/src/cobalt/base/c_val.h
@@ -217,7 +217,7 @@
 
 }  // namespace CValDetail
 
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
 // This class is passed back to the CVal modified event handlers so that they
 // can examine the new CVal value.  This class knows its type, which can be
 // checked through GetType, and then the actual value can be retrieved by
@@ -281,7 +281,7 @@
 };
 
 }  // namespace CValDetail
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
 
 // Manager class required for the CVal tracking system to function.
 // This class is designed to be a singleton, instanced only through the methods
@@ -292,7 +292,7 @@
   // Method to get the singleton instance of this class.
   static CValManager* GetInstance();
 
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
   // In order for a system to receive notifications when a tracked CVal changes,
   // it should create a subclass of OnChangedHook with OnValueChanged. When
   // instantiated, OnChangedHook will be called whenever a CVal changes.
@@ -304,7 +304,7 @@
     virtual void OnValueChanged(const std::string& name,
                                 const CValGenericValue& value) = 0;
   };
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
 
   friend struct StaticMemorySingletonTraits<CValManager>;
 
@@ -332,22 +332,22 @@
   void RegisterCVal(const CValDetail::CValBase* cval);
   void UnregisterCVal(const CValDetail::CValBase* cval);
 
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
   // Called whenever a CVal is modified, and does the work of notifying all
   // hooks.
   void PushValueChangedEvent(const CValDetail::CValBase* cval,
                              const CValGenericValue& value);
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
 
   // Helper function to remove code duplication between GetValueAsString
   // and GetValueAsPrettyString.
   optional<std::string> GetCValStringValue(const std::string& name,
                                            bool pretty);
 
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
   // Lock that protects against changes to hooks.
   base::Lock hooks_lock_;
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
 
   // Lock that protects against CVals being registered/deregistered.
   base::Lock cvals_lock_;
@@ -359,11 +359,11 @@
   typedef base::hash_map<std::string, const CValDetail::CValBase*> NameVarMap;
   NameVarMap* registered_vars_;
 
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
   // The set of hooks that we should notify whenever a CVal is modified.
   typedef base::hash_set<OnChangedHook*> OnChangeHookSet;
   OnChangeHookSet* on_changed_hook_set_;
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
 
   template <typename T>
   friend class CValDetail::CValImpl;
@@ -427,11 +427,11 @@
         value_ = rhs;
       }
     }
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
     if (value_changed) {
       OnValueChanged();
     }
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
     return *this;
   }
 
@@ -440,9 +440,9 @@
       base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
       value_ += rhs;
     }
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
     OnValueChanged();
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
     return *this;
   }
 
@@ -451,9 +451,9 @@
       base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
       value_ -= rhs;
     }
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
     OnValueChanged();
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
     return *this;
   }
 
@@ -462,9 +462,9 @@
       base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
       ++value_;
     }
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
     OnValueChanged();
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
     return *this;
   }
 
@@ -473,9 +473,9 @@
       base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
       --value_;
     }
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
     OnValueChanged();
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
     return *this;
   }
 
@@ -505,13 +505,13 @@
     }
   }
 
-#if defined(ENABLE_DEBUG_CONSOLE)
+#if defined(ENABLE_DEBUG_C_VAL)
   void OnValueChanged() {
     // Push the value changed event to all listeners.
     CValManager::GetInstance()->PushValueChangedEvent(
         this, CValSpecificValue<T>(value_));
   }
-#endif  // ENABLE_DEBUG_CONSOLE
+#endif  // ENABLE_DEBUG_C_VAL
 
   T value_;
   mutable bool registered_;
diff --git a/src/cobalt/bindings/IDLExtendedAttributes.txt b/src/cobalt/bindings/IDLExtendedAttributes.txt
index 56b0590..7918baa 100644
--- a/src/cobalt/bindings/IDLExtendedAttributes.txt
+++ b/src/cobalt/bindings/IDLExtendedAttributes.txt
@@ -73,7 +73,9 @@
 
 # Call the Cobalt function this property is bound to with the corresponding
 # object added to the head of the function's parameters.
-CallWith=EnvironmentSettings
+# StackTrace is a custom addition to CallWith for the purpose of testing
+# GetStackTrace, and is not specified in the spec.
+CallWith=EnvironmentSettings|StackTrace
 ConstructorCallWith=EnvironmentSettings
 
 # The constructor/attribute/operation may raise an exception. A pointer to an
diff --git a/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc b/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc
index 32f9f26..1fb9cf2 100644
--- a/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc
+++ b/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc
@@ -287,6 +287,11 @@
     JSC::ExecState* exec,
     JSC::JSObject* this_object,
     JSC::JSValue value);
+JSC::JSValue getJSwindow(
+    JSC::ExecState* exec_state,
+    JSC::JSValue slot_base,
+    JSC::PropertyName property_name);
+JSC::EncodedJSValue functionJSgetStackTrace(JSC::ExecState*);
 JSC::EncodedJSValue functionJSwindowOperation(JSC::ExecState*);
 
 // These are declared unconditionally, but only defined if needed by the
@@ -603,6 +608,18 @@
         reinterpret_cast<intptr_t>(setJSwindowProperty),
         JSC::NoIntrinsic
     },
+    { "window",
+        JSC::DontDelete | JSC::ReadOnly,
+        reinterpret_cast<intptr_t>(getJSwindow),
+        0,
+        JSC::NoIntrinsic
+    },
+    { "getStackTrace",
+        JSC::DontDelete | JSC::Function,
+        reinterpret_cast<intptr_t>(functionJSgetStackTrace),
+        static_cast<intptr_t>(0),
+        JSC::NoIntrinsic
+    },
     { "windowOperation",
         JSC::DontDelete | JSC::Function,
         reinterpret_cast<intptr_t>(functionJSwindowOperation),
@@ -614,8 +631,8 @@
 
 // static
 const JSC::HashTable JSCWindow::property_table_prototype = {
-    9,  // compactSize
-    7,  // compactSizeMask
+    19,  // compactSize
+    15,  // compactSizeMask
     property_table_values,
     NULL  // table allocated at runtime
 };  // JSCWindow::property_table_prototype
@@ -1019,6 +1036,44 @@
   }
 }
 
+JSC::JSValue getJSwindow(
+    JSC::ExecState* exec_state,
+    JSC::JSValue slot_base,
+    JSC::PropertyName property_name) {
+  TRACE_EVENT0("JSCWindow", "get window");
+  JSCGlobalObject* global_object =
+      JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
+  Window* impl =
+      GetWrappableOrSetException<Window>(exec_state, slot_base);
+  if (!impl) {
+    return exec_state->exception();
+  }
+
+  JSC::JSValue result = ToJSValue(
+      global_object,
+      impl->window());
+  return result;
+}
+
+JSC::EncodedJSValue functionJSgetStackTrace(
+    JSC::ExecState* exec_state) {
+  TRACE_EVENT0("JSCWindow", "call getStackTrace");
+  JSCGlobalObject* global_object =
+      JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
+  JSCExceptionState exception_state(global_object);
+  JSC::JSObject* this_object =
+      exec_state->hostThisValue().toThisObject(exec_state);
+  Window* impl =
+      GetWrappableOrSetException<Window>(exec_state, this_object);
+  if (!impl) {
+    return JSC::JSValue::encode(exec_state->exception());
+  }
+
+  TypeTraits<std::string >::ReturnType return_value = impl->GetStackTrace(global_object->GetStackTrace());
+  return JSC::JSValue::encode(ToJSValue(global_object, return_value));
+
+}
+
 JSC::EncodedJSValue functionJSwindowOperation(
     JSC::ExecState* exec_state) {
   TRACE_EVENT0("JSCWindow", "call windowOperation");
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
index d314658..546197c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.cc
@@ -205,6 +205,26 @@
 static base::LazyInstance<MozjsAnonymousIndexedGetterInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsAnonymousIndexedGetterInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -253,6 +273,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -306,14 +327,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -392,8 +411,11 @@
 // static
 JSObject* MozjsAnonymousIndexedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -401,34 +423,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsAnonymousIndexedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsAnonymousIndexedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsAnonymousIndexedGetterInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsAnonymousIndexedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsAnonymousIndexedGetterInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.h
index 56a2226..1f01c81 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousIndexedGetterInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
index 7cc34a6..9cb9a00 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.cc
@@ -205,6 +205,26 @@
 static base::LazyInstance<MozjsAnonymousNamedGetterInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsAnonymousNamedGetterInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -253,6 +273,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -278,14 +299,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -364,8 +383,11 @@
 // static
 JSObject* MozjsAnonymousNamedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -373,34 +395,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsAnonymousNamedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsAnonymousNamedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsAnonymousNamedGetterInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsAnonymousNamedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsAnonymousNamedGetterInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.h
index 36537ae..3b02269 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedGetterInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
index 519c86f..0b1e79d 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.cc
@@ -296,6 +296,26 @@
 static base::LazyInstance<MozjsAnonymousNamedIndexedGetterInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsAnonymousNamedIndexedGetterInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -344,6 +364,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -397,14 +418,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -483,8 +502,11 @@
 // static
 JSObject* MozjsAnonymousNamedIndexedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -492,34 +514,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsAnonymousNamedIndexedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsAnonymousNamedIndexedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsAnonymousNamedIndexedGetterInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsAnonymousNamedIndexedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsAnonymousNamedIndexedGetterInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.h
index 6665fe1..3c53111 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsAnonymousNamedIndexedGetterInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
index eb16ae9..4073689 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.cc
@@ -115,6 +115,26 @@
     proxy_handler;
 
 JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsArbitraryInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   interface_object_class->construct = Constructor;
   return interface_data;
 }
@@ -274,14 +295,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -370,8 +389,11 @@
 // static
 JSObject* MozjsArbitraryInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -379,34 +401,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsArbitraryInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsArbitraryInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsArbitraryInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsArbitraryInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsArbitraryInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.h
index 1ca5d0d..d1f6fa5 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsArbitraryInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc
index 1213bf6..f0e5922 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.cc
@@ -115,6 +115,26 @@
     proxy_handler;
 
 JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsBaseInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   interface_object_class->construct = Constructor;
   return interface_data;
 }
@@ -252,14 +273,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -348,8 +367,11 @@
 // static
 JSObject* MozjsBaseInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -357,34 +379,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsBaseInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsBaseInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsBaseInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsBaseInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsBaseInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.h
index 6a9f2c0..2312b77 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBaseInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
index b334f88..86e82f3 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsBooleanTypeTestInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsBooleanTypeTestInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -332,14 +353,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -418,8 +437,11 @@
 // static
 JSObject* MozjsBooleanTypeTestInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -427,34 +449,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsBooleanTypeTestInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsBooleanTypeTestInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsBooleanTypeTestInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsBooleanTypeTestInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsBooleanTypeTestInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.h
index d240a38..fa3f0e3 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
index a6360ce..379afa8 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
@@ -118,6 +118,26 @@
 static base::LazyInstance<MozjsCallbackFunctionInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsCallbackFunctionInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -561,14 +582,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -647,8 +666,11 @@
 // static
 JSObject* MozjsCallbackFunctionInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -656,34 +678,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsCallbackFunctionInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsCallbackFunctionInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsCallbackFunctionInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsCallbackFunctionInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsCallbackFunctionInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.h
index e85e0f2..dea49b2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
index 3a9b54c..b387cf6 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
@@ -118,6 +118,26 @@
 static base::LazyInstance<MozjsCallbackInterfaceInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsCallbackInterfaceInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -330,14 +351,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -416,8 +435,11 @@
 // static
 JSObject* MozjsCallbackInterfaceInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -425,34 +447,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsCallbackInterfaceInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsCallbackInterfaceInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsCallbackInterfaceInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsCallbackInterfaceInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsCallbackInterfaceInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.h
index ea10dca..788a86f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
index eae8530..dcf4ed6 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.cc
@@ -116,6 +116,26 @@
 static base::LazyInstance<MozjsConditionalInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsConditionalInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -164,6 +184,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -375,14 +396,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -461,8 +480,11 @@
 // static
 JSObject* MozjsConditionalInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -470,34 +492,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsConditionalInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsConditionalInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsConditionalInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsConditionalInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsConditionalInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.h
index 76eae81..ea935c1 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConditionalInterface.h
@@ -43,8 +43,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc
index 06ca83e..467b6de 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.cc
@@ -143,6 +143,26 @@
   return !exception_state.is_exception_set();
 }
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsConstantsInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -191,6 +211,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -240,14 +261,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -326,8 +345,11 @@
 // static
 JSObject* MozjsConstantsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -335,34 +357,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsConstantsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsConstantsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsConstantsInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsConstantsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsConstantsInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.h
index fe793ef..3501f0f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstantsInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
index 7ca19b8..8367aeb 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
@@ -115,6 +115,26 @@
     proxy_handler;
 
 JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsConstructorInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   interface_object_class->construct = Constructor;
   return interface_data;
 }
@@ -189,14 +210,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -285,8 +304,11 @@
 // static
 JSObject* MozjsConstructorInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -294,34 +316,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsConstructorInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsConstructorInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsConstructorInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsConstructorInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsConstructorInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.h
index d04a69f..ccf6f57 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
index cdc6b94..bcf7385 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
@@ -115,6 +115,26 @@
     proxy_handler;
 
 JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsConstructorWithArgumentsInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   interface_object_class->construct = Constructor;
   return interface_data;
 }
@@ -273,14 +294,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -369,8 +388,11 @@
 // static
 JSObject* MozjsConstructorWithArgumentsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -378,34 +400,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsConstructorWithArgumentsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsConstructorWithArgumentsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsConstructorWithArgumentsInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsConstructorWithArgumentsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsConstructorWithArgumentsInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.h
index 44d36d4..76c43fc 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
index bc6eb8b..18dd40a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsDOMStringTestInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsDOMStringTestInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -443,14 +464,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -529,8 +548,11 @@
 // static
 JSObject* MozjsDOMStringTestInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -538,34 +560,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsDOMStringTestInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsDOMStringTestInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsDOMStringTestInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsDOMStringTestInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsDOMStringTestInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.h
index 0cde0d8..875490c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDOMStringTestInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
index 7770e5c..e84fa83 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
@@ -296,6 +296,26 @@
 static base::LazyInstance<MozjsDerivedGetterSetterInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsDerivedGetterSetterInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -344,6 +364,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -608,16 +629,14 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
-      context, bindings::testing::MozjsNamedIndexedGetterInterface::GetPrototype(context));
+      context, bindings::testing::MozjsNamedIndexedGetterInterface::GetPrototype(context, global_object));
   DCHECK(parent_prototype);
 
   // Create the Prototype object.
@@ -694,8 +713,11 @@
 // static
 JSObject* MozjsDerivedGetterSetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -703,34 +725,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsDerivedGetterSetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsDerivedGetterSetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsDerivedGetterSetterInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsDerivedGetterSetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsDerivedGetterSetterInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.h
index 6913c19..b0164cab 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.h
@@ -42,8 +42,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc
index 96a27ce..3edab69 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.cc
@@ -115,6 +115,26 @@
     proxy_handler;
 
 JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsDerivedInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   interface_object_class->construct = Constructor;
   return interface_data;
 }
@@ -252,16 +273,14 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
-      context, bindings::testing::MozjsBaseInterface::GetPrototype(context));
+      context, bindings::testing::MozjsBaseInterface::GetPrototype(context, global_object));
   DCHECK(parent_prototype);
 
   // Create the Prototype object.
@@ -348,8 +367,11 @@
 // static
 JSObject* MozjsDerivedInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -357,34 +379,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsDerivedInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsDerivedInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsDerivedInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsDerivedInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsDerivedInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.h
index 59beb06..ac9780c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedInterface.h
@@ -42,8 +42,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
index baf4573..54c8308 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.cc
@@ -116,6 +116,26 @@
 static base::LazyInstance<MozjsDisabledInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsDisabledInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -164,6 +184,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -274,14 +295,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -360,8 +379,11 @@
 // static
 JSObject* MozjsDisabledInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -369,34 +391,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsDisabledInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsDisabledInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsDisabledInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsDisabledInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsDisabledInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.h
index 360c946..bbef7b3 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDisabledInterface.h
@@ -43,8 +43,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
index 2ed75aa..1ec0bac 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
@@ -124,6 +124,26 @@
     proxy_handler;
 
 JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsEnumerationInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -172,6 +192,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   interface_object_class->construct = Constructor;
   return interface_data;
 }
@@ -248,14 +269,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -344,8 +363,11 @@
 // static
 JSObject* MozjsEnumerationInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -353,34 +375,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsEnumerationInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsEnumerationInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsEnumerationInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsEnumerationInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsEnumerationInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.h
index b4b3e19..34f404e 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc
index 498e223..8a5b4b0 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.cc
@@ -43,6 +43,7 @@
 #include "cobalt/script/mozjs/wrapper_private.h"
 #include "cobalt/script/property_enumerator.h"
 #include "third_party/mozjs/js/src/jsapi.h"
+#include "third_party/mozjs/js/src/jsexn.h"
 #include "third_party/mozjs/js/src/jsfriendapi.h"
 
 namespace {
@@ -114,6 +115,26 @@
 static base::LazyInstance<MozjsExceptionObjectInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsExceptionObjectInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +183,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -243,22 +265,22 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
 
-  // Create the Prototype object.
-  interface_data->prototype = JS_NewObjectWithGivenProto(
-      context, &interface_data->prototype_class_definition, parent_prototype,
-      NULL);
+  JS::RootedObject prototype(context);
+  // Get Error prototype.
+  bool success_check = js_GetClassPrototype(
+      context, GetExceptionProtoKey(JSEXN_ERR), &prototype);
+  DCHECK(success_check);
+  interface_data->prototype = prototype;
   bool success = JS_DefineProperties(
       context, interface_data->prototype, prototype_properties);
   DCHECK(success);
@@ -329,8 +351,11 @@
 // static
 JSObject* MozjsExceptionObjectInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -338,34 +363,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsExceptionObjectInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsExceptionObjectInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsExceptionObjectInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsExceptionObjectInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsExceptionObjectInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.h
index 0ba0055..4c8282d 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionObjectInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
index 21cbe31..c58594c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.cc
@@ -115,6 +115,26 @@
     proxy_handler;
 
 JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsExceptionsInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   interface_object_class->construct = Constructor;
   return interface_data;
 }
@@ -274,14 +295,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -370,8 +389,11 @@
 // static
 JSObject* MozjsExceptionsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -379,34 +401,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsExceptionsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsExceptionsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsExceptionsInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsExceptionsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsExceptionsInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
@@ -420,6 +453,10 @@
 
   scoped_refptr<ExceptionsInterface> new_object =
       new ExceptionsInterface(&exception_state);
+  // In case that an exception is thrown from constructor.
+  if (exception_state.is_exception_set()) {
+    return false;
+  }
   JS::RootedValue result_value(context);
   ToJSValue(context, new_object, &result_value);
   DCHECK(result_value.isObject());
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.h
index b5fe100..fa0457d 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExceptionsInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc
index 06bcf72..3753f38 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsExtendedIDLAttributesInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsExtendedIDLAttributesInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -224,14 +245,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -310,8 +329,11 @@
 // static
 JSObject* MozjsExtendedIDLAttributesInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -319,34 +341,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsExtendedIDLAttributesInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsExtendedIDLAttributesInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsExtendedIDLAttributesInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsExtendedIDLAttributesInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsExtendedIDLAttributesInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.h
index 68909d5..b99f5b7 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsExtendedIDLAttributesInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
index fbfc60a..1a71dae 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
@@ -115,6 +115,26 @@
     proxy_handler;
 
 JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsGetOpaqueRootInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   interface_object_class->construct = Constructor;
   return interface_data;
 }
@@ -189,14 +210,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -285,8 +304,11 @@
 // static
 JSObject* MozjsGetOpaqueRootInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -294,34 +316,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsGetOpaqueRootInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsGetOpaqueRootInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsGetOpaqueRootInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsGetOpaqueRootInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsGetOpaqueRootInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.h
index 343e465..cfc9474 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc
index 27e94db..e02ee9c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsGlobalInterfaceParentHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsGlobalInterfaceParent::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -222,14 +243,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -308,8 +327,11 @@
 // static
 JSObject* MozjsGlobalInterfaceParent::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -317,34 +339,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsGlobalInterfaceParent::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsGlobalInterfaceParent::GetPrototype(JSContext* context) {
+JSObject* MozjsGlobalInterfaceParent::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsGlobalInterfaceParent::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsGlobalInterfaceParent::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.h
index 0ed43cb..2747058 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGlobalInterfaceParent.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
index e67543f..a392376 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
@@ -220,6 +220,26 @@
 static base::LazyInstance<MozjsIndexedGetterInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsIndexedGetterInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -268,6 +288,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -501,14 +522,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -587,8 +606,11 @@
 // static
 JSObject* MozjsIndexedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -596,34 +618,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsIndexedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsIndexedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsIndexedGetterInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsIndexedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsIndexedGetterInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.h
index a61619c..28984fe 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc
index 5831dae..d629315 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsInterfaceWithUnsupportedPropertiesHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsInterfaceWithUnsupportedProperties::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -215,14 +236,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -301,8 +320,11 @@
 // static
 JSObject* MozjsInterfaceWithUnsupportedProperties::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -310,34 +332,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsInterfaceWithUnsupportedProperties::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsInterfaceWithUnsupportedProperties::GetPrototype(JSContext* context) {
+JSObject* MozjsInterfaceWithUnsupportedProperties::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsInterfaceWithUnsupportedProperties::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsInterfaceWithUnsupportedProperties::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.h
index 417e204..24c2964 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsInterfaceWithUnsupportedProperties.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc
index f0a1359..bdb7519 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.cc
@@ -115,6 +115,26 @@
     proxy_handler;
 
 JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp);
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsNamedConstructorInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -163,6 +183,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   interface_object_class->construct = Constructor;
   return interface_data;
 }
@@ -189,14 +210,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -285,8 +304,11 @@
 // static
 JSObject* MozjsNamedConstructorInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -294,34 +316,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsNamedConstructorInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsNamedConstructorInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNamedConstructorInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsNamedConstructorInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNamedConstructorInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.h
index 670e6fc..bee4c6b 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedConstructorInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
index d9debc4..f77d8de 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
@@ -220,6 +220,26 @@
 static base::LazyInstance<MozjsNamedGetterInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsNamedGetterInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -268,6 +288,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -473,14 +494,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -559,8 +578,11 @@
 // static
 JSObject* MozjsNamedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -568,34 +590,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsNamedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsNamedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNamedGetterInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsNamedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNamedGetterInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.h
index 613c1b9..0d06347 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
index e63ec48..bc60f6a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
@@ -296,6 +296,26 @@
 static base::LazyInstance<MozjsNamedIndexedGetterInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsNamedIndexedGetterInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -344,6 +364,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -734,14 +755,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -820,8 +839,11 @@
 // static
 JSObject* MozjsNamedIndexedGetterInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -829,34 +851,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsNamedIndexedGetterInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsNamedIndexedGetterInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNamedIndexedGetterInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsNamedIndexedGetterInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNamedIndexedGetterInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.h
index d0cc78a..ef5bbfa 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
index e665fea..d30656e 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.cc
@@ -118,6 +118,26 @@
 static base::LazyInstance<MozjsNestedPutForwardsInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsNestedPutForwardsInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -263,14 +284,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -349,8 +368,11 @@
 // static
 JSObject* MozjsNestedPutForwardsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -358,34 +380,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsNestedPutForwardsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsNestedPutForwardsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNestedPutForwardsInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsNestedPutForwardsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNestedPutForwardsInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.h
index 47b1965..50e0e3c 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNestedPutForwardsInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc
index ecf9e98..1848abb 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsNoConstructorInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsNoConstructorInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -187,14 +208,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -273,8 +292,11 @@
 // static
 JSObject* MozjsNoConstructorInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -282,34 +304,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsNoConstructorInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsNoConstructorInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNoConstructorInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsNoConstructorInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNoConstructorInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.h
index 1c2a1c8..8fe1474 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoConstructorInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc
index 27d50a2..1ad2cbb 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsNoInterfaceObjectInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsNoInterfaceObjectInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -187,14 +208,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -233,8 +252,11 @@
 // static
 JSObject* MozjsNoInterfaceObjectInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -242,24 +264,31 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsNoInterfaceObjectInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsNoInterfaceObjectInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNoInterfaceObjectInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.h
index 8d5c0f1..1d0061f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNoInterfaceObjectInterface.h
@@ -41,7 +41,8 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
index 3176045..04c7ec4 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
@@ -118,6 +118,26 @@
 static base::LazyInstance<MozjsNullableTypesTestInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsNullableTypesTestInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -771,14 +792,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -857,8 +876,11 @@
 // static
 JSObject* MozjsNullableTypesTestInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -866,34 +888,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsNullableTypesTestInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsNullableTypesTestInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNullableTypesTestInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsNullableTypesTestInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNullableTypesTestInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.h
index 69bfddd..7b7bcb2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
index bfa31b4..546ed1a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsNumericTypesTestInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsNumericTypesTestInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -1637,14 +1658,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -1723,8 +1742,11 @@
 // static
 JSObject* MozjsNumericTypesTestInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -1732,34 +1754,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsNumericTypesTestInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsNumericTypesTestInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsNumericTypesTestInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsNumericTypesTestInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsNumericTypesTestInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.h
index f33342b..e02d41a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
index 5e32d87..4dbc0b3 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.cc
@@ -126,6 +126,26 @@
 static base::LazyInstance<MozjsObjectTypeBindingsInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsObjectTypeBindingsInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -174,6 +194,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -377,14 +398,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -463,8 +482,11 @@
 // static
 JSObject* MozjsObjectTypeBindingsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -472,34 +494,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsObjectTypeBindingsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsObjectTypeBindingsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsObjectTypeBindingsInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsObjectTypeBindingsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsObjectTypeBindingsInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.h
index 27aa23c..8ae6e03 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsObjectTypeBindingsInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
index 473b292..7d9c1b0 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
@@ -118,6 +118,26 @@
 static base::LazyInstance<MozjsOperationsTestInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsOperationsTestInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -1460,14 +1481,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -1546,8 +1565,11 @@
 // static
 JSObject* MozjsOperationsTestInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -1555,34 +1577,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsOperationsTestInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsOperationsTestInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsOperationsTestInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsOperationsTestInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsOperationsTestInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.h
index d0e54e1..3968437 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
index b977879..c632988 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.cc
@@ -118,6 +118,26 @@
 static base::LazyInstance<MozjsPutForwardsInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsPutForwardsInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -304,14 +325,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -390,8 +409,11 @@
 // static
 JSObject* MozjsPutForwardsInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -399,34 +421,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsPutForwardsInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsPutForwardsInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsPutForwardsInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsPutForwardsInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsPutForwardsInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.h
index 06a6435..f0f5881 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsPutForwardsInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
index 210586c..7cd708f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
@@ -118,6 +118,26 @@
 static base::LazyInstance<MozjsStaticPropertiesInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsStaticPropertiesInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -166,6 +186,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -486,14 +507,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -572,8 +591,11 @@
 // static
 JSObject* MozjsStaticPropertiesInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -581,34 +603,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsStaticPropertiesInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsStaticPropertiesInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsStaticPropertiesInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsStaticPropertiesInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsStaticPropertiesInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.h
index db46890..27cb5e2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
index d77b60e..2471dfc 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsStringifierAnonymousOperationInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsStringifierAnonymousOperationInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -226,14 +247,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -312,8 +331,11 @@
 // static
 JSObject* MozjsStringifierAnonymousOperationInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -321,34 +343,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsStringifierAnonymousOperationInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsStringifierAnonymousOperationInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsStringifierAnonymousOperationInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsStringifierAnonymousOperationInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsStringifierAnonymousOperationInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.h
index 0115c6a..b18e5a5 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
index d652475..f97b025 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsStringifierAttributeInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsStringifierAttributeInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -276,14 +297,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -362,8 +381,11 @@
 // static
 JSObject* MozjsStringifierAttributeInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -371,34 +393,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsStringifierAttributeInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsStringifierAttributeInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsStringifierAttributeInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsStringifierAttributeInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsStringifierAttributeInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.h
index 813ec74..fcf8292 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
index 30a5d06..3a96a4b 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsStringifierOperationInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsStringifierOperationInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -267,14 +288,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -353,8 +372,11 @@
 // static
 JSObject* MozjsStringifierOperationInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -362,34 +384,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsStringifierOperationInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsStringifierOperationInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsStringifierOperationInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsStringifierOperationInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsStringifierOperationInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.h
index 135e07a..a5f76d1 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc
index b7d73d0..49786d1 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.cc
@@ -114,6 +114,26 @@
 static base::LazyInstance<MozjsTargetInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsTargetInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -162,6 +182,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -257,14 +278,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -343,8 +362,11 @@
 // static
 JSObject* MozjsTargetInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -352,34 +374,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsTargetInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsTargetInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsTargetInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsTargetInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsTargetInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.h
index 71f1e20..34254e0 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsTargetInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
index 8d181ac..bc19f25 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.cc
@@ -122,6 +122,26 @@
 static base::LazyInstance<MozjsUnionTypesInterfaceHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsUnionTypesInterface::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -170,6 +190,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -395,14 +416,12 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   DCHECK(parent_prototype);
@@ -481,8 +500,11 @@
 // static
 JSObject* MozjsUnionTypesInterface::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -490,34 +512,45 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsUnionTypesInterface::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsUnionTypesInterface::GetPrototype(JSContext* context) {
+JSObject* MozjsUnionTypesInterface::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsUnionTypesInterface::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsUnionTypesInterface::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.h
index eba6b2f..7de2382 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsUnionTypesInterface.h
@@ -41,8 +41,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
index b626b88..f52bcf2 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
@@ -298,6 +298,26 @@
 static base::LazyInstance<MozjsWindowHandler>
     proxy_handler;
 
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, MozjsWindow::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -346,6 +366,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
   return interface_data;
 }
 
@@ -393,6 +414,64 @@
   return !exception_state.is_exception_set();
 }
 
+JSBool get_window(
+    JSContext* context, JS::HandleObject object, JS::HandleId id,
+    JS::MutableHandleValue vp) {
+  MozjsExceptionState exception_state(context);
+  JS::RootedValue result_value(context);
+
+  WrapperPrivate* wrapper_private =
+      WrapperPrivate::GetFromObject(context, object);
+  Window* impl =
+      wrapper_private->wrappable<Window>().get();
+
+  if (!exception_state.is_exception_set()) {
+    ToJSValue(context,
+              impl->window(),
+              &result_value);
+  }
+  if (!exception_state.is_exception_set()) {
+    vp.set(result_value);
+  }
+  return !exception_state.is_exception_set();
+}
+
+JSBool fcn_getStackTrace(
+    JSContext* context, uint32_t argc, JS::Value *vp) {
+  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+  // Compute the 'this' value.
+  JS::RootedValue this_value(context, JS_ComputeThis(context, vp));
+  // 'this' should be an object.
+  JS::RootedObject object(context);
+  if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) {
+    NOTREACHED();
+    return false;
+  }
+  if (!JS_ValueToObject(context, this_value, object.address())) {
+    NOTREACHED();
+    return false;
+  }
+  MozjsExceptionState exception_state(context);
+  JS::RootedValue result_value(context);
+
+  WrapperPrivate* wrapper_private =
+      WrapperPrivate::GetFromObject(context, object);
+  Window* impl =
+      wrapper_private->wrappable<Window>().get();
+  MozjsGlobalObjectProxy* global_object_proxy =
+      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
+
+  if (!exception_state.is_exception_set()) {
+    ToJSValue(context,
+              impl->GetStackTrace(global_object_proxy->GetStackTrace()),
+              &result_value);
+  }
+  if (!exception_state.is_exception_set()) {
+    args.rval().set(result_value);
+  }
+  return !exception_state.is_exception_set();
+}
+
 JSBool fcn_windowOperation(
     JSContext* context, uint32_t argc, JS::Value *vp) {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
@@ -429,11 +508,24 @@
       JSOP_WRAPPER(&get_windowProperty),
       JSOP_WRAPPER(&set_windowProperty),
   },
+  {  // Readonly attribute
+      "window", 0,
+      JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_READONLY,
+      JSOP_WRAPPER(&get_window),
+      JSOP_NULLWRAPPER,
+  },
   JS_PS_END
 };
 
 const JSFunctionSpec prototype_functions[] = {
   {
+      "getStackTrace",
+      JSOP_WRAPPER(&fcn_getStackTrace),
+      0,
+      JSPROP_ENUMERATE,
+      NULL,
+  },
+  {
       "windowOperation",
       JSOP_WRAPPER(&fcn_windowOperation),
       0,
@@ -456,16 +548,14 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   JS::RootedObject parent_prototype(
-      context, bindings::testing::MozjsGlobalInterfaceParent::GetPrototype(context));
+      context, bindings::testing::MozjsGlobalInterfaceParent::GetPrototype(context, global_object));
   DCHECK(parent_prototype);
 
   // Create the Prototype object.
@@ -556,13 +646,8 @@
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
 
-  // Set the global object pointer, so we can access the standard classes such
-  // as the base Object prototype when looking up our prototype.
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  global_object_proxy->SetGlobalObject(global_object);
-
-  JS::RootedObject prototype(context, MozjsWindow::GetPrototype(context));
+  JS::RootedObject prototype(
+      context, MozjsWindow::GetPrototype(context, global_object));
   DCHECK(prototype);
   JS_SetPrototype(context, global_object, prototype);
 
@@ -573,34 +658,51 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, global_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
+
+  // Set the global object proxy pointer, so we can access the standard classes
+  // such as the base Object prototype when looking up our prototype.
+  MozjsGlobalObjectProxy* global_object_proxy =
+      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
+  global_object_proxy->SetGlobalObjectProxyAndWrapper(proxy, wrappable);
   return proxy;
 }
 
 //static
 const JSClass* MozjsWindow::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* MozjsWindow::GetPrototype(JSContext* context) {
+JSObject* MozjsWindow::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
 }
 
 // static
-JSObject* MozjsWindow::GetInterfaceObject(JSContext* context) {
+JSObject* MozjsWindow::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
@@ -629,7 +731,8 @@
       context, global_interface);
   mozjs_global_object_proxy->SetEnvironmentSettings(environment_settings);
 
-  WrapperFactory* wrapper_factory = mozjs_global_object_proxy->wrapper_factory();
+  WrapperFactory* wrapper_factory =
+      mozjs_global_object_proxy->wrapper_factory();
   wrapper_factory->RegisterWrappableType(
       AnonymousIndexedGetterInterface::AnonymousIndexedGetterInterfaceWrappableType(),
       base::Bind(MozjsAnonymousIndexedGetterInterface::CreateProxy),
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.h
index c7e508c..50db9dd 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.h
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.h
@@ -42,8 +42,10 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 };
 
 }  // namespace bindings
diff --git a/src/cobalt/bindings/mozjs/templates/interface.cc.template b/src/cobalt/bindings/mozjs/templates/interface.cc.template
index ad65ba4..16134d5 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.cc.template
@@ -41,6 +41,9 @@
 #include "cobalt/script/mozjs/wrapper_private.h"
 #include "cobalt/script/property_enumerator.h"
 #include "third_party/mozjs/js/src/jsapi.h"
+{% if is_exception_interface %}
+#include "third_party/mozjs/js/src/jsexn.h"
+{% endif %}
 #include "third_party/mozjs/js/src/jsfriendapi.h"
 {% endblock includes %}
 {% block using_directives %}
@@ -317,6 +320,26 @@
 }
 
 {% endfor %}
+JSBool HasInstance(JSContext *context, JS::HandleObject type,
+                   JS::MutableHandleValue vp, JSBool *success) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, type));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(
+      context, {{binding_class}}::GetPrototype(context, global_object));
+
+  // |IsDelegate| walks the prototype chain of an object returning true if
+  // .prototype is found.
+  bool is_delegate;
+  if (!IsDelegate(context, prototype, vp, &is_delegate)) {
+    *success = false;
+    return false;
+  }
+
+  *success = is_delegate;
+  return true;
+}
 
 InterfaceData* CreateCachedInterfaceData() {
   InterfaceData* interface_data = new InterfaceData();
@@ -366,6 +389,7 @@
   interface_object_class->enumerate = JS_EnumerateStub;
   interface_object_class->resolve = JS_ResolveStub;
   interface_object_class->convert = JS_ConvertStub;
+  interface_object_class->hasInstance = &HasInstance;
 {% if constructor %}
   interface_object_class->construct = Constructor;
 {% endif %}
@@ -380,8 +404,13 @@
 JSBool get_{{attribute.idl_name}}(
     JSContext* context, JS::HandleObject object, JS::HandleId id,
     JS::MutableHandleValue vp) {
+  JS::RootedObject global_object(
+      context, JS_GetGlobalForObject(context, object));
+  DCHECK(global_object);
+
   JS::RootedObject interface_object(context,
-      Mozjs{{attribute.interface_name}}::GetInterfaceObject(context));
+      Mozjs{{attribute.interface_name}}::GetInterfaceObject(
+          context, global_object));
   vp.set(JS::ObjectValue(*interface_object));
   return true;
 }
@@ -626,27 +655,34 @@
 };
 
 void InitializePrototypeAndInterfaceObject(
-    InterfaceData* interface_data, JSContext* context) {
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
   DCHECK(!interface_data->prototype);
   DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(global_object));
 
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  JS::RootedObject global_object(context, global_object_proxy->global_object());
-  DCHECK(global_object);
   {% if parent_interface %}
   JS::RootedObject parent_prototype(
-      context, {{parent_interface}}::GetPrototype(context));
+      context, {{parent_interface}}::GetPrototype(context, global_object));
   {% else %}
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
   {% endif %}
   DCHECK(parent_prototype);
 
+{% if is_exception_interface %}
+  JS::RootedObject prototype(context);
+  // Get Error prototype.
+  bool success_check = js_GetClassPrototype(
+      context, GetExceptionProtoKey(JSEXN_ERR), &prototype);
+  DCHECK(success_check);
+  interface_data->prototype = prototype;
+{% else %}
   // Create the Prototype object.
   interface_data->prototype = JS_NewObjectWithGivenProto(
       context, &interface_data->prototype_class_definition, parent_prototype,
       NULL);
+{% endif %}
   bool success = JS_DefineProperties(
       context, interface_data->prototype, prototype_properties);
   DCHECK(success);
@@ -746,13 +782,8 @@
   JS::RootedObject parent_prototype(
       context, JS_GetObjectPrototype(context, global_object));
 
-  // Set the global object pointer, so we can access the standard classes such
-  // as the base Object prototype when looking up our prototype.
-  MozjsGlobalObjectProxy* global_object_proxy =
-      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
-  global_object_proxy->SetGlobalObject(global_object);
-
-  JS::RootedObject prototype(context, {{binding_class}}::GetPrototype(context));
+  JS::RootedObject prototype(
+      context, {{binding_class}}::GetPrototype(context, global_object));
   DCHECK(prototype);
   JS_SetPrototype(context, global_object, prototype);
 
@@ -763,7 +794,13 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, global_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
+
+  // Set the global object proxy pointer, so we can access the standard classes
+  // such as the base Object prototype when looking up our prototype.
+  MozjsGlobalObjectProxy* global_object_proxy =
+      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
+  global_object_proxy->SetGlobalObjectProxyAndWrapper(proxy, wrappable);
   return proxy;
 }
 
@@ -771,8 +808,11 @@
 // static
 JSObject* {{binding_class}}::CreateProxy(
     JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
   InterfaceData* interface_data = GetInterfaceData(context);
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   DCHECK(prototype);
   JS::RootedObject new_object(context, JS_NewObjectWithGivenProto(
       context, &interface_data->instance_class_definition, prototype, NULL));
@@ -780,7 +820,7 @@
   JS::RootedObject proxy(context,
       ProxyHandler::NewProxy(context, new_object, prototype, NULL,
                              proxy_handler.Pointer()));
-  WrapperPrivate::AddPrivateData(proxy, wrappable);
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
   return proxy;
 }
 
@@ -788,17 +828,24 @@
 //static
 const JSClass* {{binding_class}}::PrototypeClass(
       JSContext* context) {
-  JS::RootedObject prototype(context, GetPrototype(context));
+  JS::RootedObject global_object(context, JS_GetGlobalForScopeChain(context));
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
   JSClass* proto_class = JS_GetClass(*prototype.address());
   return proto_class;
 }
 
 // static
-JSObject* {{binding_class}}::GetPrototype(JSContext* context) {
+JSObject* {{binding_class}}::GetPrototype(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->prototype) {
     // Create new prototype that has all the props and methods
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->prototype);
   return interface_data->prototype;
@@ -806,10 +853,14 @@
 
 {% if has_interface_object %}
 // static
-JSObject* {{binding_class}}::GetInterfaceObject(JSContext* context) {
+JSObject* {{binding_class}}::GetInterfaceObject(
+    JSContext* context, JS::HandleObject global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   InterfaceData* interface_data = GetInterfaceData(context);
   if (!interface_data->interface_object) {
-    InitializePrototypeAndInterfaceObject(interface_data, context);
+    InitializePrototypeAndInterfaceObject(
+        interface_data, context, global_object);
   }
   DCHECK(interface_data->interface_object);
   return interface_data->interface_object;
@@ -847,7 +898,8 @@
       context, global_interface);
   mozjs_global_object_proxy->SetEnvironmentSettings(environment_settings);
 
-  WrapperFactory* wrapper_factory = mozjs_global_object_proxy->wrapper_factory();
+  WrapperFactory* wrapper_factory =
+      mozjs_global_object_proxy->wrapper_factory();
 {% for interface in all_interfaces %}
 {% if interface.conditional %}
 #if defined({{interface.conditional}})
diff --git a/src/cobalt/bindings/mozjs/templates/interface.h.template b/src/cobalt/bindings/mozjs/templates/interface.h.template
index f7ca8b6..fbef85c 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.h.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.h.template
@@ -24,9 +24,11 @@
   static JSObject* CreateProxy(JSContext* context,
       const scoped_refptr<script::Wrappable>& wrappable);
   static const JSClass* PrototypeClass(JSContext* context);
-  static JSObject* GetPrototype(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
 {% if has_interface_object %}
-  static JSObject* GetInterfaceObject(JSContext* context);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
 {% endif %}
 };
 {% endblock implementation %}
diff --git a/src/cobalt/bindings/mozjs/templates/macros.cc.template b/src/cobalt/bindings/mozjs/templates/macros.cc.template
index 36770e2..dd3bdca 100644
--- a/src/cobalt/bindings/mozjs/templates/macros.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/macros.cc.template
@@ -336,6 +336,12 @@
                        constructor.call_with) }}
   scoped_refptr<{{impl_class}}> new_object =
       new {{impl_class}}({{arguments_list|join(', ')}});
+{% if constructor.raises_exception %}
+  // In case that an exception is thrown from constructor.
+  if (exception_state.is_exception_set()) {
+    return false;
+  }
+{% endif %}
   JS::RootedValue result_value(context);
   ToJSValue(context, new_object, &result_value);
   DCHECK(result_value.isObject());
diff --git a/src/cobalt/bindings/testing/Window.idl b/src/cobalt/bindings/testing/Window.idl
index 9967ccf..161266f 100644
--- a/src/cobalt/bindings/testing/Window.idl
+++ b/src/cobalt/bindings/testing/Window.idl
@@ -17,4 +17,6 @@
 interface Window : GlobalInterfaceParent {
   void windowOperation();
   attribute DOMString windowProperty;
+  readonly attribute Window window;
+  [CallWith=StackTrace] DOMString getStackTrace();
 };
diff --git a/src/cobalt/bindings/testing/exceptions_bindings_test.cc b/src/cobalt/bindings/testing/exceptions_bindings_test.cc
index 0010125..13d6d0e 100644
--- a/src/cobalt/bindings/testing/exceptions_bindings_test.cc
+++ b/src/cobalt/bindings/testing/exceptions_bindings_test.cc
@@ -24,7 +24,7 @@
 using ::testing::InSequence;
 using ::testing::Invoke;
 using ::testing::Return;
-using ::testing::StrictMock;
+using ::testing::NiceMock;
 using ::testing::WithArg;
 
 #define EXPECT_SUBSTRING(needle, haystack) \
@@ -54,8 +54,7 @@
  public:
   explicit ExceptionObjectSetter(
       const scoped_refptr<ExceptionObjectInterface>& exception)
-      : exception_object_(
-            make_scoped_refptr<script::ScriptException>(exception.get())) {}
+      : exception_object_(exception) {}
   void FireException(script::ExceptionState* exception) {
     exception->SetException(exception_object_);
   }
@@ -117,13 +116,12 @@
 
 TEST_F(ExceptionsBindingsTest, ThrowExceptionObject) {
   scoped_refptr<ExceptionObjectInterface> exception_object =
-      make_scoped_refptr(new StrictMock<ExceptionObjectInterface>());
+      make_scoped_refptr(new NiceMock<ExceptionObjectInterface>());
   ExceptionObjectSetter exception_setter(exception_object);
 
   InSequence in_sequence_dummy;
   EXPECT_CALL(test_mock(), FunctionThrowsException(_)).WillOnce(
       Invoke(&exception_setter, &ExceptionObjectSetter::FireException));
-  EXPECT_CALL(*exception_object, message()).WillOnce(Return("the message"));
   EXPECT_TRUE(EvaluateScript(
       "var error = null;"
       "try { test.functionThrowsException(); }"
diff --git a/src/cobalt/bindings/testing/global_interface_bindings_test.cc b/src/cobalt/bindings/testing/global_interface_bindings_test.cc
index 175426e..5f8b90c 100644
--- a/src/cobalt/bindings/testing/global_interface_bindings_test.cc
+++ b/src/cobalt/bindings/testing/global_interface_bindings_test.cc
@@ -37,6 +37,10 @@
 };
 }  // namespace
 
+TEST_F(GlobalInterfaceBindingsTest, GlobalWindowIsThis) {
+  EXPECT_TRUE(EvaluateScript("window === this;", NULL));
+}
+
 TEST_F(GlobalInterfaceBindingsTest, GlobalOperation) {
   EXPECT_CALL(test_mock(), WindowOperation());
   EXPECT_TRUE(EvaluateScript("windowOperation();", NULL));
diff --git a/src/cobalt/bindings/testing/stack_trace_test.cc b/src/cobalt/bindings/testing/stack_trace_test.cc
new file mode 100644
index 0000000..c9e39a8
--- /dev/null
+++ b/src/cobalt/bindings/testing/stack_trace_test.cc
@@ -0,0 +1,69 @@
+/*
+ * 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/bindings/testing/bindings_test_base.h"
+
+namespace cobalt {
+namespace bindings {
+namespace testing {
+
+namespace {
+class StackTraceTest : public BindingsTestBase {};
+}  // namespace
+
+TEST_F(StackTraceTest, GetStackTrace) {
+  std::string result;
+
+  // We expect the to be in bar (line 2), called from foo (line 6),
+  // called from foo (line 8) 4 times, called outside of a function (line
+  // 11).
+  std::string script =
+      "function bar() {\n"
+      "return getStackTrace();\n"
+      "}\n"
+      "function foo(depth) {\n"
+      "  if  (depth <= 0) {\n"
+      "    return bar();\n"
+      "  } else {\n"
+      "    return foo(depth - 1);\n"
+      "  }\n"
+      "}\n"
+      "foo(4)";
+  EXPECT_TRUE(EvaluateScript(script, &result));
+
+  // Expect that bar is on top.
+  std::string match_line = "bar @ [object BindingsTestBase]:2\n";
+  size_t position = result.find(match_line);
+  EXPECT_TRUE(position != std::string::npos);
+  // Expect a foo at line 6.
+  match_line = "foo @ [object BindingsTestBase]:6\n";
+  position = result.find(match_line, ++position);
+  EXPECT_TRUE(position != std::string::npos);
+  // Expect 4 subsequent foos at line 8.
+  match_line = "foo @ [object BindingsTestBase]:8\n";
+  for (int i = 0; i < 4; ++i) {
+    position = result.find(match_line, ++position);
+    EXPECT_TRUE(position != std::string::npos);
+  }
+  // Expect global code at line 11.
+  match_line = "global code @ [object BindingsTestBase]:11";
+  position = result.find(match_line, ++position);
+  EXPECT_TRUE(position != std::string::npos);
+}
+
+}  // namespace testing
+}  // namespace bindings
+}  // namespace cobalt
diff --git a/src/cobalt/bindings/testing/testing.gyp b/src/cobalt/bindings/testing/testing.gyp
index 49c20e4..b820608 100644
--- a/src/cobalt/bindings/testing/testing.gyp
+++ b/src/cobalt/bindings/testing/testing.gyp
@@ -139,6 +139,7 @@
         'operations_bindings_test.cc',
         'optional_arguments_bindings_test.cc',
         'put_forwards_test.cc',
+        'stack_trace_test.cc',
         'static_properties_bindings_test.cc',
         'stringifier_bindings_test.cc',
         'union_type_bindings_test.cc',
diff --git a/src/cobalt/bindings/testing/window.h b/src/cobalt/bindings/testing/window.h
index 8c6dded..0bc8115 100644
--- a/src/cobalt/bindings/testing/window.h
+++ b/src/cobalt/bindings/testing/window.h
@@ -17,7 +17,12 @@
 #ifndef COBALT_BINDINGS_TESTING_WINDOW_H_
 #define COBALT_BINDINGS_TESTING_WINDOW_H_
 
+#include <string>
+#include <vector>
+
 #include "cobalt/bindings/testing/global_interface_parent.h"
+#include "cobalt/script/environment_settings.h"
+#include "cobalt/script/global_object_proxy.h"
 
 namespace cobalt {
 namespace bindings {
@@ -29,6 +34,12 @@
   virtual std::string window_property() { return ""; }
   virtual void set_window_property(const std::string&) {}
 
+  std::string GetStackTrace(
+      const std::vector<script::StackFrame>& stack_frame) {
+    return StackTraceToString(stack_frame);
+  }
+  scoped_refptr<Window> window() { return this; }
+
   DEFINE_WRAPPABLE_TYPE(Window);
 };
 
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index 5ec73ec..4327e96 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -36,7 +36,7 @@
 #include "cobalt/loader/image/image_decoder.h"
 #include "cobalt/math/size.h"
 #include "cobalt/network/network_event.h"
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 #include "cobalt/storage/savegame_fake.h"
 #endif
 #include "cobalt/system_window/application_event.h"
@@ -45,7 +45,7 @@
 #if defined(__LB_SHELL__)
 #if !defined(__LB_SHELL__FOR_RELEASE__)
 #include "lbshell/src/lb_memory_manager.h"
-#endif  // defined(ENABLE_DEBUG_CONSOLE)
+#endif  // defined(__LB_SHELL__FOR_RELEASE__)
 #include "lbshell/src/lb_memory_pages.h"
 #endif  // defined(__LB_SHELL__)
 
@@ -64,7 +64,7 @@
 int GetRemoteDebuggingPort() {
   const int kDefaultRemoteDebuggingPort = 9222;
   int remote_debugging_port = kDefaultRemoteDebuggingPort;
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kRemoteDebuggingPort)) {
     const std::string switchValue =
@@ -76,13 +76,13 @@
       remote_debugging_port = kDefaultRemoteDebuggingPort;
     }
   }
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
   return remote_debugging_port;
 }
 #endif  // ENABLE_REMOTE_DEBUGGING
 
 #if defined(ENABLE_WEBDRIVER)
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 int GetWebDriverPort() {
   // The default port on which the webdriver server should listen for incoming
   // connections.
@@ -101,11 +101,11 @@
   }
   return webdriver_port;
 }
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 #endif  // ENABLE_WEBDRIVER
 
 GURL GetInitialURL() {
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   // Allow the user to override the default URL via a command line parameter.
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kInitialURL)) {
@@ -116,13 +116,13 @@
       DLOG(INFO) << "URL from parameter is not valid, using default URL.";
     }
   }
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
   return GURL(kDefaultURL);
 }
 
 base::TimeDelta GetTimedTraceDuration() {
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   int duration_in_seconds = 0;
   if (command_line->HasSwitch(switches::kTimedTrace) &&
@@ -131,7 +131,7 @@
           &duration_in_seconds)) {
     return base::TimeDelta::FromSeconds(duration_in_seconds);
   }
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
   return base::TimeDelta();
 }
@@ -140,7 +140,7 @@
   // Default is empty, command line can override.
   FilePath result;
 
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kExtraWebFileDir)) {
     result =
@@ -153,18 +153,19 @@
     }
     DLOG(INFO) << "Extra web file dir: " << result.value();
   }
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
   return result;
 }
 
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 void EnableUsingStubImageDecoderIfRequired() {
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kStubImageDecoder)) {
     loader::image::ImageDecoder::UseStubImageDecoder();
   }
 }
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
 void SetIntegerIfSwitchIsSet(const char* switch_name, int* output) {
   if (CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
@@ -190,7 +191,13 @@
   SetIntegerIfSwitchIsSet(browser::switches::kSkiaCacheSizeInBytes,
                           &options->skia_cache_size_in_bytes);
 }
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+
+void ApplyCommandLineSettingsToWebModuleOptions(WebModule::Options* options) {
+  SetIntegerIfSwitchIsSet(browser::switches::kImageCacheSizeInBytes,
+                          &options->image_cache_capacity);
+  SetIntegerIfSwitchIsSet(browser::switches::kRemoteTypefaceCacheSizeInBytes,
+                          &options->remote_typeface_cache_capacity);
+}
 
 // Restrict navigation to a couple of whitelisted URLs by default.
 const char kYouTubeTvLocationPolicy[] =
@@ -288,11 +295,13 @@
   options.language = language;
   options.network_module_options.preferred_language = language;
 
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
   ApplyCommandLineSettingsToRendererOptions(&options.renderer_module_options);
+  ApplyCommandLineSettingsToWebModuleOptions(&options.web_module_options);
 
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          browser::switches::kNullSavegame)) {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
+  if (command_line->HasSwitch(browser::switches::kNullSavegame)) {
     options.storage_manager_options.savegame_options.factory =
         &storage::SavegameFake::Create;
   }
@@ -311,8 +320,7 @@
 
   math::Size viewport_size(kDefaultViewportWidth, kDefaultViewportHeight);
 
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   if (command_line->HasSwitch(browser::switches::kProxy)) {
     options.network_module_options.custom_proxy =
         command_line->GetSwitchValueASCII(browser::switches::kProxy);
@@ -344,6 +352,20 @@
 
   EnableUsingStubImageDecoderIfRequired();
 
+  if (command_line->HasSwitch(switches::kAudioDecoderStub)) {
+    DLOG(INFO) << "Use ShellRawAudioDecoderStub";
+    options.media_module_options.use_audio_decoder_stub = true;
+  }
+  if (command_line->HasSwitch(switches::kNullAudioStreamer)) {
+    DLOG(INFO) << "Use null audio";
+    options.media_module_options.use_null_audio_streamer = true;
+  }
+  if (command_line->HasSwitch(switches::kVideoDecoderStub)) {
+    DLOG(INFO) << "Use ShellRawVideoDecoderStub";
+    options.media_module_options.use_video_decoder_stub = true;
+  }
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+
   if (command_line->HasSwitch(browser::switches::kViewport)) {
     const std::string switchValue =
         command_line->GetSwitchValueASCII(browser::switches::kViewport);
@@ -381,19 +403,6 @@
       }
     }
   }
-  if (command_line->HasSwitch(switches::kAudioDecoderStub)) {
-    DLOG(INFO) << "Use ShellRawAudioDecoderStub";
-    options.media_module_options.use_audio_decoder_stub = true;
-  }
-  if (command_line->HasSwitch(switches::kNullAudioStreamer)) {
-    DLOG(INFO) << "Use null audio";
-    options.media_module_options.use_null_audio_streamer = true;
-  }
-  if (command_line->HasSwitch(switches::kVideoDecoderStub)) {
-    DLOG(INFO) << "Use ShellRawVideoDecoderStub";
-    options.media_module_options.use_video_decoder_stub = true;
-  }
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
 
   system_window_ =
       system_window::CreateSystemWindow(&event_dispatcher_, viewport_size);
@@ -419,7 +428,7 @@
                                      application_event_callback_);
 
 #if defined(ENABLE_WEBDRIVER)
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   if (command_line->HasSwitch(switches::kEnableWebDriver)) {
     int webdriver_port = GetWebDriverPort();
     web_driver_module_.reset(new webdriver::WebDriverModule(
@@ -431,7 +440,7 @@
                    base::Unretained(browser_module_.get())),
         base::Bind(&Application::Quit, base::Unretained(this))));
   }
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 #endif  // ENABLE_WEBDRIVER
 
 #if defined(ENABLE_REMOTE_DEBUGGING)
@@ -442,7 +451,7 @@
                  base::Unretained(browser_module_.get()))));
 #endif  // ENABLE_REMOTE_DEBUGGING
 
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   int duration_in_seconds = 0;
   if (command_line->HasSwitch(switches::kShutdownAfter) &&
       base::StringToInt(
@@ -455,7 +464,7 @@
         FROM_HERE, quit_closure_,
         base::TimeDelta::FromSeconds(duration_in_seconds));
   }
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 }
 
 Application::~Application() {
@@ -526,25 +535,15 @@
   if (app_event->type() == system_window::ApplicationEvent::kQuit) {
     DLOG(INFO) << "Got quit event.";
     app_status_ = kWillQuitAppStatus;
-#if !defined(OS_STARBOARD)
-    browser_module_->SetWillQuit();
-    browser_module_->SetPaused(false);
-#endif  // !defined(OS_STARBOARD)
     Quit();
   } else if (app_event->type() == system_window::ApplicationEvent::kSuspend) {
     DLOG(INFO) << "Got suspend event.";
     app_status_ = kPausedAppStatus;
     ++app_suspend_count_;
-#if !defined(OS_STARBOARD)
-    browser_module_->SetPaused(true);
-#endif  // !defined(OS_STARBOARD)
   } else if (app_event->type() == system_window::ApplicationEvent::kResume) {
     DLOG(INFO) << "Got resume event.";
     app_status_ = kRunningAppStatus;
     ++app_resume_count_;
-#if !defined(OS_STARBOARD)
-    browser_module_->SetPaused(false);
-#endif  // !defined(OS_STARBOARD)
   }
 }
 
@@ -629,7 +628,7 @@
         static_cast<size_t>(memory_info.application_memory);
     c_val_stats_.exe_memory = static_cast<size_t>(memory_info.executable_size);
   }
-#endif  // defined(ENABLE_DEBUG_CONSOLE)
+#endif  // defined(__LB_SHELL__FOR_RELEASE__)
   // If the memory stats have not been updated yet, then simply use the
   // unallocated memory as the available memory.
   if (!memory_stats_updated) {
diff --git a/src/cobalt/browser/browser.gyp b/src/cobalt/browser/browser.gyp
index 58aa11b..36effe7 100644
--- a/src/cobalt/browser/browser.gyp
+++ b/src/cobalt/browser/browser.gyp
@@ -46,6 +46,10 @@
         'web_module_stat_tracker.cc',
         'web_module_stat_tracker.h',
       ],
+      'defines': [
+        'COBALT_IMAGE_CACHE_SIZE_IN_BYTES=<(image_cache_size_in_bytes)',
+        'COBALT_REMOTE_TYPEFACE_CACHE_SIZE_IN_BYTES=<(remote_typeface_cache_size_in_bytes)',
+      ],
       'dependencies': [
         '<(DEPTH)/cobalt/account/account.gyp:account',
         '<(DEPTH)/cobalt/audio/audio.gyp:audio',
diff --git a/src/cobalt/browser/browser_bindings.gyp b/src/cobalt/browser/browser_bindings.gyp
index 45d7061..80049c1 100644
--- a/src/cobalt/browser/browser_bindings.gyp
+++ b/src/cobalt/browser/browser_bindings.gyp
@@ -23,6 +23,7 @@
 
     'bindings_dependencies': [
       '../h5vcc/h5vcc.gyp:h5vcc',
+      '../webdriver/webdriver.gyp:webdriver',
     ],
 
     # Bindings for the interfaces in this list will be generated, and there must
@@ -139,6 +140,7 @@
         '../dom/Uint32Array.idl',
         '../dom/Uint8Array.idl',
         '../dom/URL.idl',
+        '../dom/VideoPlaybackQuality.idl',
         '../dom/Window.idl',
         '../dom/XMLDocument.idl',
         '../dom/XMLSerializer.idl',
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index f5abd88..668f3c7 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -109,6 +109,9 @@
           weak_this_(weak_ptr_factory_.GetWeakPtr())),
       self_message_loop_(MessageLoop::current()),
       storage_manager_(options.storage_manager_options),
+#if defined(OS_STARBOARD)
+      is_rendered_(false),
+#endif  // OS_STARBOARD
       renderer_module_(system_window, options.renderer_module_options),
 #if defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
       array_buffer_allocator_(new ResourceProviderArrayBufferAllocator(
@@ -156,12 +159,12 @@
   web_module_options_.injected_window_attributes["h5vcc"] =
       base::Bind(&CreateH5VCC, h5vcc_settings);
 
-#if defined(ENABLE_DEBUG_CONSOLE) && defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_CONSOLE) && defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kInputFuzzer)) {
     OnFuzzerToggle(std::string());
   }
-#endif  // ENABLE_DEBUG_CONSOLE && ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_CONSOLE && ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
   input_device_manager_ = input::InputDeviceManager::CreateFromWindow(
       base::Bind(&BrowserModule::OnKeyEventProduced, base::Unretained(this)),
@@ -266,49 +269,6 @@
   return web_module_loaded_.TimedWait(timeout);
 }
 
-void BrowserModule::SetPaused(bool paused) {
-  // This method should not be called on the browser's own thread, as
-  // we will be unable to signal the |has_resumed_| event when the
-  // |Pause| method blocks the thread.
-  DCHECK_NE(MessageLoop::current(), self_message_loop_);
-
-  if (paused) {
-    has_resumed_.Reset();
-    self_message_loop_->PostTask(
-        FROM_HERE, base::Bind(&BrowserModule::Pause, base::Unretained(this)));
-  } else {
-    has_resumed_.Signal();
-  }
-}
-
-void BrowserModule::SetWillQuit() {
-  base::AutoLock lock(quit_lock_);
-  will_quit_ = true;
-}
-
-bool BrowserModule::WillQuit() {
-  base::AutoLock lock(quit_lock_);
-  return will_quit_;
-}
-
-void BrowserModule::Pause() {
-  // This method must be called on the browser's own thread.
-  DCHECK_EQ(MessageLoop::current(), self_message_loop_);
-
-  media_module_->PauseAllPlayers();
-
-  // Block the thread until the browser has been resumed.
-  DLOG(INFO) << "Pausing browser loop with " << self_message_loop_->Size()
-             << " items in queue.";
-  has_resumed_.Wait();
-  DLOG(INFO) << "Resuming browser loop with " << self_message_loop_->Size()
-             << " items in queue.";
-
-  if (!WillQuit()) {
-    media_module_->ResumeAllPlayers();
-  }
-}
-
 #if defined(ENABLE_SCREENSHOT)
 void BrowserModule::RequestScreenshotToFile(const FilePath& path,
                                             const base::Closure& done_cb) {
@@ -325,14 +285,17 @@
 void BrowserModule::OnRenderTreeProduced(
     const browser::WebModule::LayoutResults& layout_results) {
   TRACE_EVENT0("cobalt::browser", "BrowserModule::OnRenderTreeProduced()");
-  render_tree_combiner_.UpdateMainRenderTree(renderer::Submission(
-      layout_results.render_tree, layout_results.animations,
-      layout_results.layout_time));
+  renderer::Submission renderer_submission(layout_results.render_tree,
+                                           layout_results.layout_time);
+#if defined(OS_STARBOARD)
+  renderer_submission.on_rasterized_callback = base::Bind(
+      &BrowserModule::OnRendererSubmissionRasterized, base::Unretained(this));
+#endif  // OS_STARBOARD
+  render_tree_combiner_.UpdateMainRenderTree(renderer_submission);
 
 #if defined(ENABLE_SCREENSHOT)
   screen_shot_writer_->SetLastPipelineSubmission(renderer::Submission(
-      layout_results.render_tree, layout_results.animations,
-      layout_results.layout_time));
+      layout_results.render_tree, layout_results.layout_time));
 #endif
 }
 
@@ -361,8 +324,7 @@
   TRACE_EVENT0("cobalt::browser",
                "BrowserModule::OnDebugConsoleRenderTreeProduced()");
   render_tree_combiner_.UpdateDebugConsoleRenderTree(renderer::Submission(
-      layout_results.render_tree, layout_results.animations,
-      layout_results.layout_time));
+      layout_results.render_tree, layout_results.layout_time));
 }
 
 #endif  // defined(ENABLE_DEBUG_CONSOLE)
@@ -550,5 +512,15 @@
   network_module_.SetProxy(proxy_rules);
 }
 
+#if defined(OS_STARBOARD)
+void BrowserModule::OnRendererSubmissionRasterized() {
+  if (!is_rendered_) {
+    // Hide the system splash screen when the first render has completed.
+    is_rendered_ = true;
+    SbSystemHideSplashScreen();
+  }
+}
+#endif  // OS_STARBOARD
+
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index aadc0af..4ae4fb4 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -86,17 +86,6 @@
   void AddURLHandler(const URLHandler::URLHandlerCallback& callback);
   void RemoveURLHandler(const URLHandler::URLHandlerCallback& callback);
 
-  // Pauses/resumes all media players and blocks the browser thread. Should
-  // be called on a thread other than |self_message_loop_|.
-  void SetPaused(bool paused);
-
-  // Lets the web browser know that the application is about to quit. We use
-  // this not to start the web players when the thread is unpaused.
-  void SetWillQuit();
-
-  // Whether |SetWillQuit| has been called.
-  bool WillQuit();
-
 #if defined(ENABLE_SCREENSHOT)
   // Request a screenshot to be written to the specified path. Callback will
   // be fired after the screenshot has been written to disk.
@@ -172,10 +161,6 @@
   // Destroys the splash screen, if currently displayed.
   void DestroySplashScreen();
 
-  // Pauses all active web players and blocks the main thread until the
-  // |has_resumed_| event is signalled. Must be called on |self_message_loop_|.
-  void Pause();
-
 #if defined(ENABLE_DEBUG_CONSOLE)
   // Toggles the input fuzzer on/off.  Ignores the parameter.
   void OnFuzzerToggle(const std::string&);
@@ -195,6 +180,12 @@
       scoped_ptr<webdriver::WindowDriver>* out_window_driver);
 #endif
 
+#if defined(OS_STARBOARD)
+  // Called when a renderer submission has been rasterized. Used to hide the
+  // system splash screen after the first render has completed.
+  void OnRendererSubmissionRasterized();
+#endif  // OS_STARBOARD
+
   // 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
@@ -222,6 +213,12 @@
 
   storage::StorageManager storage_manager_;
 
+#if defined(OS_STARBOARD)
+  // Whether the browser module has yet rendered anything. On the very first
+  // render, we hide the system splash screen.
+  bool is_rendered_;
+#endif  // OS_STARBOARD
+
   // Sets up everything to do with graphics, from backend objects like the
   // display and graphics context to the rasterizer and rendering pipeline.
   renderer::RendererModule renderer_module_;
diff --git a/src/cobalt/browser/debug_console.cc b/src/cobalt/browser/debug_console.cc
index 0fce499..a293be3 100644
--- a/src/cobalt/browser/debug_console.cc
+++ b/src/cobalt/browser/debug_console.cc
@@ -77,14 +77,14 @@
 // Returns the debug console mode as specified by the command line.
 // If unspecified by the command line, base::nullopt is returned.
 base::optional<int> GetDebugConsoleModeFromCommandLine() {
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(switches::kDebugConsoleMode)) {
     const std::string debug_console_mode_string =
         command_line->GetSwitchValueASCII(switches::kDebugConsoleMode);
     return DebugConsoleModeStringToInt(debug_console_mode_string);
   }
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
   return base::nullopt;
 }
diff --git a/src/cobalt/browser/starboard/event_handler.cc b/src/cobalt/browser/starboard/event_handler.cc
index 4ef7069..00808d7 100644
--- a/src/cobalt/browser/starboard/event_handler.cc
+++ b/src/cobalt/browser/starboard/event_handler.cc
@@ -18,6 +18,7 @@
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "cobalt/network/network_event.h"
 #include "cobalt/system_window/application_event.h"
 #include "cobalt/system_window/starboard/system_window.h"
 
@@ -58,6 +59,12 @@
   } else if (starboard_event->type == kSbEventTypeSuspend) {
     cobalt_event.reset(new system_window::ApplicationEvent(
         system_window::ApplicationEvent::kSuspend));
+  } else if (starboard_event->type == kSbEventTypeNetworkConnect) {
+    cobalt_event.reset(
+        new network::NetworkEvent(network::NetworkEvent::kConnection));
+  } else if (starboard_event->type == kSbEventTypeNetworkDisconnect) {
+    cobalt_event.reset(
+        new network::NetworkEvent(network::NetworkEvent::kDisconnection));
   }
 
   // Dispatch the Cobalt event, if created.
diff --git a/src/cobalt/browser/switches.cc b/src/cobalt/browser/switches.cc
index 9258a4f..d9d0abf 100644
--- a/src/cobalt/browser/switches.cc
+++ b/src/cobalt/browser/switches.cc
@@ -20,7 +20,7 @@
 namespace browser {
 namespace switches {
 
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 // Allow insecure HTTP network connections.
 const char kAllowHttp[] = "allow_http";
 
@@ -71,32 +71,13 @@
 // Creates a remote debugging server and listens on the specified port.
 const char kRemoteDebuggingPort[] = "remote_debugging_port";
 
-// Determines the capacity of the scratch surface cache.  The scratch surface
-// cache facilitates the reuse of temporary offscreen surfaces within a single
-// frame.  This setting is only relevant when using the hardware-accelerated
-// Skia rasterizer.
-const char kScratchSurfaceCacheSizeInBytes[] =
-    "scratch_surface_cache_size_in_bytes";
-
 // If this flag is set, Cobalt will automatically shutdown after the specified
 // number of seconds have passed.
 const char kShutdownAfter[] = "shutdown_after";
 
-// Determines the capacity of the skia cache.  The Skia cache is maintained
-// within Skia and is used to cache the results of complicated effects such as
-// shadows, so that Skia draw calls that are used repeatedly across frames can
-// be cached into surfaces.  This setting is only relevant when using the
-// hardware-accelerated Skia rasterizer.
-const char kSkiaCacheSizeInBytes[] = "skia_cache_size_in_bytes";
-
 // Decode all images using StubImageDecoder.
 const char kStubImageDecoder[] = "stub_image_decoder";
 
-// Determines the capacity of the surface cache.  The surface cache tracks which
-// render tree nodes are being re-used across frames and stores the nodes that
-// are most CPU-expensive to render into surfaces.
-const char kSurfaceCacheSizeInBytes[] = "surface_cache_size_in_bytes";
-
 // If this is set, then a trace (see base/debug/trace_eventh.h) is started on
 // Cobalt startup.  A value must also be specified for this switch, which is
 // the duration in seconds of how long the trace will be done for before ending
@@ -104,16 +85,48 @@
 // "timed_trace.json" in the log output directory.
 const char kTimedTrace[] = "timed_trace";
 
-// Specifies the viewport size: width ['x' height]
-const char kViewport[] = "viewport";
-
 // Decode video data using ShellRawVideoDecoderStub.
 extern const char kVideoDecoderStub[] = "video_decoder_stub";
 
 // Port that the WebDriver server should be listening on.
 const char kWebDriverPort[] = "webdriver_port";
 
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+
+// Determines the capacity of the image cache which manages image surfaces
+// downloaded from a web page.  While it depends on the platform, often (and
+// ideally) these images are cached within GPU memory.
+const char kImageCacheSizeInBytes[] = "image_cache_size_in_bytes";
+
+// Determines the capacity of the remote typefaces cache which manages all
+// typefaces downloaded from a web page.
+const char kRemoteTypefaceCacheSizeInBytes[] =
+    "remote_typeface_cache_size_in_bytes";
+
+// Determines the capacity of the scratch surface cache.  The scratch surface
+// cache facilitates the reuse of temporary offscreen surfaces within a single
+// frame.  This setting is only relevant when using the hardware-accelerated
+// Skia rasterizer.  While it depends on the platform, this setting may affect
+// GPU memory usage.
+const char kScratchSurfaceCacheSizeInBytes[] =
+    "scratch_surface_cache_size_in_bytes";
+
+// Determines the capacity of the skia cache.  The Skia cache is maintained
+// within Skia and is used to cache the results of complicated effects such as
+// shadows, so that Skia draw calls that are used repeatedly across frames can
+// be cached into surfaces.  This setting is only relevant when using the
+// hardware-accelerated Skia rasterizer.  While it depends on the platform, this
+// setting may affect GPU memory usage.
+const char kSkiaCacheSizeInBytes[] = "skia_cache_size_in_bytes";
+
+// Determines the capacity of the surface cache.  The surface cache tracks which
+// render tree nodes are being re-used across frames and stores the nodes that
+// are most CPU-expensive to render into surfaces.  While it depends on the
+// platform, this setting may affect GPU memory usage.
+const char kSurfaceCacheSizeInBytes[] = "surface_cache_size_in_bytes";
+
+// Specifies the viewport size: width ['x' height]
+const char kViewport[] = "viewport";
 
 }  // namespace switches
 }  // namespace browser
diff --git a/src/cobalt/browser/switches.h b/src/cobalt/browser/switches.h
index 4c66e0c..75dc57d 100644
--- a/src/cobalt/browser/switches.h
+++ b/src/cobalt/browser/switches.h
@@ -21,7 +21,7 @@
 namespace browser {
 namespace switches {
 
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 extern const char kAllowHttp[];
 extern const char kAudioDecoderStub[];
 extern const char kCspMode[];
@@ -39,13 +39,16 @@
 extern const char kShutdownAfter[];
 extern const char kStubImageDecoder[];
 extern const char kTimedTrace[];
-extern const char kViewport[];
 extern const char kVideoDecoderStub[];
 extern const char kWebDriverPort[];
-extern const char kSurfaceCacheSizeInBytes[];
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
+
+extern const char kImageCacheSizeInBytes[];
+extern const char kRemoteTypefaceCacheSizeInBytes[];
 extern const char kScratchSurfaceCacheSizeInBytes[];
 extern const char kSkiaCacheSizeInBytes[];
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+extern const char kSurfaceCacheSizeInBytes[];
+extern const char kViewport[];
 
 }  // namespace switches
 }  // namespace browser
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 88b5286..828380d 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -246,16 +246,18 @@
       data.network_module, data.options.extra_web_file_dir));
   DCHECK(fetcher_factory_);
 
+  DCHECK_LE(0, data.options.image_cache_capacity);
   image_cache_ = loader::image::CreateImageCache(
       base::StringPrintf("Memory.%s.ImageCache", name_.c_str()),
-      data.options.image_cache_capacity, data.resource_provider,
-      fetcher_factory_.get());
+      static_cast<uint32>(data.options.image_cache_capacity),
+      data.resource_provider, fetcher_factory_.get());
   DCHECK(image_cache_);
 
+  DCHECK_LE(0, data.options.remote_typeface_cache_capacity);
   remote_typeface_cache_ = loader::font::CreateRemoteTypefaceCache(
       base::StringPrintf("Memory.%s.RemoteTypefaceCache", name_.c_str()),
-      kRemoteTypefaceCacheCapacity, data.resource_provider,
-      fetcher_factory_.get());
+      static_cast<uint32>(data.options.remote_typeface_cache_capacity),
+      data.resource_provider, fetcher_factory_.get());
   DCHECK(remote_typeface_cache_);
 
   local_storage_database_.reset(
@@ -512,6 +514,16 @@
   web_module_->impl_.reset();
 }
 
+WebModule::Options::Options()
+    : name("WebModule"),
+      layout_trigger(layout::LayoutManager::kOnDocumentMutation),
+      image_cache_capacity(COBALT_IMAGE_CACHE_SIZE_IN_BYTES),
+      remote_typeface_cache_capacity(
+          COBALT_REMOTE_TYPEFACE_CACHE_SIZE_IN_BYTES),
+      csp_enforcement_mode(dom::kCspEnforcementEnable),
+      csp_insecure_allowed_token(0),
+      track_event_stats(false) {}
+
 WebModule::WebModule(
     const GURL& initial_url,
     const OnRenderTreeProducedCallback& render_tree_produced_callback,
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index 83cfa49..826df99 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -74,11 +74,6 @@
 // accessed from only one thread.
 class WebModule {
  public:
-  // TODO: These numbers should be adjusted according to the size of
-  // client memory.
-  static const uint32 kImageCacheCapacity = 64U * 1024 * 1024;
-  static const uint32 kRemoteTypefaceCacheCapacity = 5U * 1024 * 1024;
-
   struct Options {
     typedef base::Callback<scoped_refptr<script::Wrappable>()>
         CreateObjectFunction;
@@ -86,15 +81,8 @@
         InjectedWindowAttributes;
 
     // All optional parameters defined in this structure should have their
-    // values
-    // initialized in the default constructor to useful defaults.
-    Options()
-        : name("WebModule"),
-          layout_trigger(layout::LayoutManager::kOnDocumentMutation),
-          image_cache_capacity(kImageCacheCapacity),
-          csp_enforcement_mode(dom::kCspEnforcementEnable),
-          csp_insecure_allowed_token(0),
-          track_event_stats(false) {}
+    // values initialized in the default constructor to useful defaults.
+    Options();
 
     // The name of the WebModule.  This is useful for debugging purposes as in
     // the case where multiple WebModule objects exist, it can be used to
@@ -133,7 +121,10 @@
     std::string location_policy;
 
     // Image cache capaticy in bytes.
-    uint32 image_cache_capacity;
+    int image_cache_capacity;
+
+    // Typeface cache capacity in bytes.
+    int remote_typeface_cache_capacity;
 
     // Content Security Policy enforcement mode for this web module.
     dom::CspEnforcementType csp_enforcement_mode;
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 4db8c83..29fb020 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-9617
\ No newline at end of file
+10060
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index ae3ac78..04a0d5e 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -106,11 +106,27 @@
     #   "cobalt/renderer/egl_and_gles/egl_and_gles_<gl_type>.gyp not found"
     'gl_type%': 'system_gles2',
 
+    # Cache parameters
+
+    # The following set of parameters define how much memory is reserved for
+    # different Cobalt caches.  These caches affect CPU *and* GPU memory usage.
+    #
+    # The sum of the following caches effectively describes the maximum GPU
+    # texture memory usage (though it doesn't consider video textures and
+    # display color buffers):
+    #   - skia_cache_size_in_bytes (GLES2 rasterizer only)
+    #   - scratch_surface_cache_size_in_bytes
+    #   - surface_cache_size_in_bytes
+    #   - image_cache_size_in_bytes
+    #
+    # The other caches affect CPU memory usage.
+
     # Determines the capacity of the skia cache.  The Skia cache is maintained
     # within Skia and is used to cache the results of complicated effects such
     # as shadows, so that Skia draw calls that are used repeatedly across
     # frames can be cached into surfaces.  This setting is only relevant when
-    # using the hardware-accelerated Skia rasterizer.
+    # using the hardware-accelerated Skia rasterizer (e.g. as opposed to the
+    # Blitter API).
     'skia_cache_size_in_bytes%': 4 * 1024 * 1024,
 
     # Determines the capacity of the scratch surface cache.  The scratch
@@ -124,6 +140,15 @@
     # nodes that are most CPU-expensive to render into surfaces.
     'surface_cache_size_in_bytes%': 0,
 
+    # Determines the capacity of the image cache which manages image surfaces
+    # downloaded from a web page.  While it depends on the platform, often (and
+    # ideally) these images are cached within GPU memory.
+    'image_cache_size_in_bytes%': 64 * 1024 * 1024,
+
+    # Determines the capacity of the remote typefaces cache which manages all
+    # typefaces downloaded from a web page.
+    'remote_typeface_cache_size_in_bytes%': 5 * 1024 * 1024,
+
     # Compiler configuration.
 
     # The following variables are used to specify compiler and linker
@@ -166,6 +191,11 @@
     # as expected, rather than requiring it to be set for each platform.
     #'javascript_engine%': 'javascriptcore',
 
+    # Enable jit by default. It can be set to 0 to run in interpreter-only mode.
+    # Setting this to 1 on a platform or engine for which there is no JIT
+    # implementation is a no-op.
+    'cobalt_enable_jit%': 1,
+
     # Customize variables used by Chromium's build/common.gypi.
 
     # Disable a check that looks for an official google api key.
@@ -287,7 +317,7 @@
           'COBALT_BOX_DUMP_ENABLED',
           'COBALT_BUILD_TYPE_DEBUG',
           '_DEBUG',
-          'ENABLE_COMMAND_LINE_SWITCHES',
+          'ENABLE_DEBUG_COMMAND_LINE_SWITCHES',
           'ENABLE_DEBUG_C_VAL',
           'ENABLE_DEBUG_CONSOLE',
           'ENABLE_DIR_SOURCE_ROOT_ACCESS',
@@ -310,7 +340,7 @@
           '_DEBUG',
           'ALLOCATOR_STATS_TRACKING',
           'COBALT_BUILD_TYPE_DEVEL',
-          'ENABLE_COMMAND_LINE_SWITCHES',
+          'ENABLE_DEBUG_COMMAND_LINE_SWITCHES',
           'ENABLE_DEBUG_C_VAL',
           'ENABLE_DEBUG_CONSOLE',
           'ENABLE_DIR_SOURCE_ROOT_ACCESS',
@@ -332,7 +362,7 @@
         'defines': [
           'ALLOCATOR_STATS_TRACKING',
           'COBALT_BUILD_TYPE_QA',
-          'ENABLE_COMMAND_LINE_SWITCHES',
+          'ENABLE_DEBUG_COMMAND_LINE_SWITCHES',
           'ENABLE_DEBUG_C_VAL',
           'ENABLE_DEBUG_CONSOLE',
           'ENABLE_DIR_SOURCE_ROOT_ACCESS',
diff --git a/src/cobalt/codereview.settings b/src/cobalt/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/cobalt/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/cobalt/cssom/animation_set.cc b/src/cobalt/cssom/animation_set.cc
index 37cea7d..a2459bb 100644
--- a/src/cobalt/cssom/animation_set.cc
+++ b/src/cobalt/cssom/animation_set.cc
@@ -99,7 +99,7 @@
 }
 }  // namespace
 
-void AnimationSet::Update(const base::TimeDelta& current_time,
+bool AnimationSet::Update(const base::TimeDelta& current_time,
                           const CSSComputedStyleData& style,
                           const CSSKeyframesRule::NameMap& keyframes_map) {
   const std::vector<scoped_refptr<PropertyValue> >& names =
@@ -115,9 +115,12 @@
       names[0] == KeywordValue::GetNone()) {
     // If we have no current animations playing and no animations were
     // specified, there is nothing to do so we can return immediately.
-    return;
+    return false;
   }
 
+  // Whether or not the animations have been modified by this update.
+  bool animations_modified = false;
+
   // Build a set of all animations in the new declared animation set, so that
   // we can later use this to decide which old animations are no longer active.
   std::set<std::string> declared_animation_set;
@@ -172,6 +175,8 @@
     if (event_handler_) {
       event_handler_->OnAnimationStarted(inserted->second);
     }
+
+    animations_modified = true;
   }
 
   // Finally check for any animations that are now ended.
@@ -189,10 +194,16 @@
       animations_to_end.push_back(iter->first);
     }
   }
-  for (std::vector<std::string>::iterator iter = animations_to_end.begin();
-       iter != animations_to_end.end(); ++iter) {
-    animations_.erase(*iter);
+  if (!animations_to_end.empty()) {
+    for (std::vector<std::string>::iterator iter = animations_to_end.begin();
+         iter != animations_to_end.end(); ++iter) {
+      animations_.erase(*iter);
+    }
+
+    animations_modified = true;
   }
+
+  return animations_modified;
 }
 
 }  // namespace cssom
diff --git a/src/cobalt/cssom/animation_set.h b/src/cobalt/cssom/animation_set.h
index 5ef8cf1..160377b 100644
--- a/src/cobalt/cssom/animation_set.h
+++ b/src/cobalt/cssom/animation_set.h
@@ -48,7 +48,8 @@
   // Update the internal state of animations based on our previous state and the
   // passed in computed style.  Animations may be started or ended when this
   // method is called.
-  void Update(const base::TimeDelta& current_time,
+  // Returns whether or not the update modified the animations.
+  bool Update(const base::TimeDelta& current_time,
               const CSSComputedStyleData& style,
               const CSSKeyframesRule::NameMap& keyframes_map);
 
diff --git a/src/cobalt/cssom/cascaded_style.cc b/src/cobalt/cssom/cascaded_style.cc
index 99511a2..7776979 100644
--- a/src/cobalt/cssom/cascaded_style.cc
+++ b/src/cobalt/cssom/cascaded_style.cc
@@ -69,7 +69,7 @@
   scoped_refptr<CSSComputedStyleData> cascaded_style(
       new CSSComputedStyleData());
 
-  // A sparce vector of CascadePrecedence values for all possible property
+  // A sparse vector of CascadePrecedence values for all possible property
   // values.
   base::optional<CascadePrecedence>
       cascade_precedences[static_cast<size_t>(kNumLonghandProperties)];
diff --git a/src/cobalt/cssom/computed_style.cc b/src/cobalt/cssom/computed_style.cc
index 30d4986..48d8223 100644
--- a/src/cobalt/cssom/computed_style.cc
+++ b/src/cobalt/cssom/computed_style.cc
@@ -23,6 +23,7 @@
 #include "cobalt/cssom/absolute_url_value.h"
 #include "cobalt/cssom/calc_value.h"
 #include "cobalt/cssom/css_computed_style_data.h"
+#include "cobalt/cssom/css_computed_style_declaration.h"
 #include "cobalt/cssom/font_weight_value.h"
 #include "cobalt/cssom/keyword_value.h"
 #include "cobalt/cssom/length_value.h"
@@ -2484,16 +2485,18 @@
  public:
   CalculateComputedStyleContext(
       CSSComputedStyleData* cascaded_style,
-      const scoped_refptr<const CSSComputedStyleData>& parent_computed_style,
+      const scoped_refptr<CSSComputedStyleDeclaration>&
+          parent_computed_style_declaration,
       const scoped_refptr<const CSSComputedStyleData>& root_computed_style,
       const math::Size& viewport_size,
       GURLMap* const property_key_to_base_url_map)
       : cascaded_style_(cascaded_style),
-        parent_computed_style_(*parent_computed_style),
+        parent_computed_style_(*parent_computed_style_declaration->data()),
         root_computed_style_(*root_computed_style),
         viewport_size_(viewport_size),
         property_key_to_base_url_map_(property_key_to_base_url_map) {
-    cascaded_style_->SetParentComputedStyle(parent_computed_style);
+    cascaded_style_->SetParentComputedStyleDeclaration(
+        parent_computed_style_declaration);
   }
 
   // Updates the property specified by the iterator to its computed value.
@@ -2689,6 +2692,11 @@
 bool CalculateComputedStyleContext::HandleInheritOrInitial(
     PropertyKey key, scoped_refptr<PropertyValue>* value) {
   if (*value == KeywordValue::GetInherit()) {
+    // Add this property to the list of those that inherited their declared
+    // value from the parent. This allows the computed style to later determine
+    // if a value that was explicitly inherited from the parent is no longer
+    // valid.
+    cascaded_style_->AddDeclaredPropertyInheritedFromParent(key);
     *value = parent_computed_style_.GetPropertyValue(key);
     return true;
   } else if (*value == KeywordValue::GetInitial()) {
@@ -3067,22 +3075,39 @@
 
 void PromoteToComputedStyle(
     const scoped_refptr<CSSComputedStyleData>& cascaded_style,
-    const scoped_refptr<const CSSComputedStyleData>& parent_computed_style,
+    const scoped_refptr<CSSComputedStyleDeclaration>&
+        parent_computed_style_declaration,
     const scoped_refptr<const CSSComputedStyleData>& root_computed_style,
     const math::Size& viewport_size,
     GURLMap* const property_key_to_base_url_map) {
   DCHECK(cascaded_style);
-  DCHECK(parent_computed_style);
+  DCHECK(parent_computed_style_declaration);
   DCHECK(root_computed_style);
 
   // Create a context for calculating the computed style.  This object is useful
   // because it can cache computed style values that are depended upon by other
   // properties' computed style calculations.
   CalculateComputedStyleContext calculate_computed_style_context(
-      cascaded_style.get(), parent_computed_style, root_computed_style,
-      viewport_size, property_key_to_base_url_map);
+      cascaded_style.get(), parent_computed_style_declaration,
+      root_computed_style, viewport_size, property_key_to_base_url_map);
 
-  // Go through all values declared values and calculate their computed values.
+  // For each inherited, animatable property, set the property value to
+  // inherited if it is not already declared. This causes the value to be
+  // explicitly set within the CSSComputedStyleData and ensures that the
+  // original value will be available for transitions (which need to know the
+  // before and after state of the property) even when the property is inherited
+  // from a parent that has changed.
+  const PropertyKeyVector& inherited_animatable_properties =
+      GetInheritedAnimatableProperties();
+  for (PropertyKeyVector::const_iterator iter =
+           inherited_animatable_properties.begin();
+       iter != inherited_animatable_properties.end(); ++iter) {
+    if (!cascaded_style->IsDeclared(*iter)) {
+      cascaded_style->SetPropertyValue(*iter, KeywordValue::GetInherit());
+    }
+  }
+
+  // Go through all declared values and calculate their computed values.
   CSSComputedStyleData::PropertyValues* declared_property_values =
       cascaded_style->declared_property_values();
   for (CSSComputedStyleData::PropertyValues::iterator property_value_iterator =
@@ -3095,11 +3120,13 @@
 }
 
 scoped_refptr<CSSComputedStyleData> GetComputedStyleOfAnonymousBox(
-    const scoped_refptr<const CSSComputedStyleData>& parent_computed_style) {
+    const scoped_refptr<CSSComputedStyleDeclaration>&
+        parent_computed_style_declaration) {
   scoped_refptr<CSSComputedStyleData> computed_style =
       new CSSComputedStyleData();
-  PromoteToComputedStyle(computed_style, parent_computed_style,
-                         parent_computed_style, math::Size(), NULL);
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+                         parent_computed_style_declaration->data(),
+                         math::Size(), NULL);
   return computed_style;
 }
 
diff --git a/src/cobalt/cssom/computed_style.h b/src/cobalt/cssom/computed_style.h
index 9d356df..da9c9da 100644
--- a/src/cobalt/cssom/computed_style.h
+++ b/src/cobalt/cssom/computed_style.h
@@ -25,6 +25,7 @@
 namespace cssom {
 
 class CSSComputedStyleData;
+class CSSComputedStyleDeclaration;
 
 // The computed value is the result of resolving the specified value,
 // generally absolutizing it. The computed value is the value that is
@@ -32,11 +33,12 @@
 //   https://www.w3.org/TR/css-cascade-3/#computed
 
 // Converts specified values into computed values in place.
-// parent_computed_style and root_computed_style cannot be NULL.
+// parent_computed_style_declaration and root_computed_style cannot be NULL.
 // property_key_to_base_url_map can be NULL.
 void PromoteToComputedStyle(
     const scoped_refptr<CSSComputedStyleData>& specified_style,
-    const scoped_refptr<const CSSComputedStyleData>& parent_computed_style,
+    const scoped_refptr<CSSComputedStyleDeclaration>&
+        parent_computed_style_declaration,
     const scoped_refptr<const CSSComputedStyleData>& root_computed_style,
     const math::Size& viewport_size,
     GURLMap* const property_key_to_base_url_map);
@@ -49,7 +51,8 @@
 //   https://www.w3.org/TR/CSS21/visuren.html#anonymous-block-level
 //   https://www.w3.org/TR/CSS21/visuren.html#anonymous
 scoped_refptr<CSSComputedStyleData> GetComputedStyleOfAnonymousBox(
-    const scoped_refptr<const CSSComputedStyleData>& parent_computed_style);
+    const scoped_refptr<CSSComputedStyleDeclaration>&
+        parent_computed_style_declaration);
 
 }  // namespace cssom
 }  // namespace cobalt
diff --git a/src/cobalt/cssom/computed_style_test.cc b/src/cobalt/cssom/computed_style_test.cc
index bd71ff9..d499787 100644
--- a/src/cobalt/cssom/computed_style_test.cc
+++ b/src/cobalt/cssom/computed_style_test.cc
@@ -23,6 +23,7 @@
 #include "cobalt/cssom/calc_value.h"
 #include "cobalt/cssom/css_computed_style_data.h"
 #include "cobalt/cssom/css_computed_style_declaration.h"
+#include "cobalt/cssom/font_style_value.h"
 #include "cobalt/cssom/font_weight_value.h"
 #include "cobalt/cssom/keyword_value.h"
 #include "cobalt/cssom/length_value.h"
@@ -39,15 +40,25 @@
 namespace cobalt {
 namespace cssom {
 
+scoped_refptr<CSSComputedStyleDeclaration> CreateComputedStyleDeclaration(
+    scoped_refptr<CSSComputedStyleData> computed_style) {
+  scoped_refptr<CSSComputedStyleDeclaration> computed_style_declaration(
+      new CSSComputedStyleDeclaration());
+  computed_style_declaration->SetData(computed_style);
+  return computed_style_declaration;
+}
+
 TEST(PromoteToComputedStyle, FontWeightShouldBeBoldAsSpecified) {
   scoped_refptr<CSSComputedStyleData> computed_style(
       new CSSComputedStyleData());
   computed_style->set_font_weight(FontWeightValue::GetBoldAka700());
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   EXPECT_EQ(FontWeightValue::GetBoldAka700(),
@@ -62,8 +73,10 @@
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   LengthValue* computed_font_size = base::polymorphic_downcast<LengthValue*>(
@@ -81,12 +94,14 @@
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
   scoped_refptr<CSSComputedStyleData> root_computed_style(
       new CSSComputedStyleData());
   root_computed_style->set_font_size(new LengthValue(200, kPixelsUnit));
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          root_computed_style, math::Size(), NULL);
 
   LengthValue* computed_font_size = base::polymorphic_downcast<LengthValue*>(
@@ -105,8 +120,10 @@
 
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(360, 240), NULL);
 
   LengthValue* computed_font_size = base::polymorphic_downcast<LengthValue*>(
@@ -125,10 +142,12 @@
       new CSSComputedStyleData());
   computed_style->set_font_size(new LengthValue(50, kPixelsUnit));
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   LengthValue* computed_font_size = base::polymorphic_downcast<LengthValue*>(
@@ -142,10 +161,12 @@
       new CSSComputedStyleData());
   computed_style->set_line_height(KeywordValue::GetNormal());
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   EXPECT_EQ(KeywordValue::GetNormal(), computed_style->line_height());
@@ -160,8 +181,10 @@
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   LengthValue* computed_line_height = base::polymorphic_downcast<LengthValue*>(
@@ -179,8 +202,10 @@
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   LengthValue* computed_text_indent = base::polymorphic_downcast<LengthValue*>(
@@ -202,12 +227,14 @@
 
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
   GURLMap property_key_to_base_url_map;
   property_key_to_base_url_map[kBackgroundImageProperty] =
       GURL("file:///computed_style_test/style_sheet.css");
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(),
                          &property_key_to_base_url_map);
 
@@ -237,12 +264,14 @@
 
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
   GURLMap property_key_to_base_url_map;
   property_key_to_base_url_map[kBackgroundImageProperty] =
       GURL("file:///computed_style_test/document.html");
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(),
                          &property_key_to_base_url_map);
 
@@ -263,9 +292,12 @@
       GetPropertyInitialValue(kBackgroundPositionProperty));
   computed_style->set_background_position(background_position);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_position_list =
@@ -302,9 +334,12 @@
       new PropertyListValue(background_position_builder.Pass()));
   computed_style->set_background_position(background_position);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_position_list =
@@ -340,9 +375,12 @@
       new PropertyListValue(background_position_builder.Pass()));
   computed_style->set_background_position(background_position);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_position_list =
@@ -380,9 +418,12 @@
       new PropertyListValue(background_position_builder.Pass()));
   computed_style->set_background_position(background_position);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_position_list =
@@ -419,9 +460,12 @@
       new PropertyListValue(background_position_builder.Pass()));
   computed_style->set_background_position(background_position);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_position_list =
@@ -458,9 +502,12 @@
       new PropertyListValue(background_position_builder.Pass()));
   computed_style->set_background_position(background_position);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_position_list =
@@ -497,9 +544,12 @@
       new PropertyListValue(background_position_builder.Pass()));
   computed_style->set_background_position(background_position);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_position_list =
@@ -537,9 +587,12 @@
       new PropertyListValue(background_position_builder.Pass()));
   computed_style->set_background_position(background_position);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_position_list =
@@ -577,9 +630,12 @@
       new PropertyListValue(background_position_builder.Pass()));
   computed_style->set_background_position(background_position);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_position_list =
@@ -618,9 +674,12 @@
       new PropertyListValue(background_position_builder.Pass()));
   computed_style->set_background_position(background_position);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_position_list =
@@ -656,9 +715,12 @@
       new PropertyListValue(background_size_builder.Pass()));
   computed_style->set_background_size(background_size);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> background_size_list =
@@ -682,9 +744,12 @@
       new CSSComputedStyleData());
   computed_style->set_background_size(KeywordValue::GetContain());
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   EXPECT_EQ(KeywordValue::GetContain(), computed_style->background_size());
@@ -695,9 +760,12 @@
       new CSSComputedStyleData());
   computed_style->set_border_radius(new LengthValue(3, kFontSizesAkaEmUnit));
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   LengthValue* border_radius = base::polymorphic_downcast<LengthValue*>(
@@ -712,9 +780,12 @@
   computed_style->set_border_left_color(KeywordValue::GetCurrentColor());
   computed_style->set_color(RGBAColorValue::GetAqua());
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<RGBAColorValue> border_color =
@@ -729,9 +800,12 @@
   computed_style->set_border_top_style(KeywordValue::GetNone());
   computed_style->set_border_top_width(new LengthValue(2, kFontSizesAkaEmUnit));
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<LengthValue> border_top_width =
@@ -752,7 +826,10 @@
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<LengthValue> border_left_width =
@@ -781,7 +858,10 @@
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_font_size(new LengthValue(50, kPixelsUnit));
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> box_shadow_list =
@@ -824,7 +904,10 @@
 
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> box_shadow_list =
@@ -867,7 +950,10 @@
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_color(new RGBAColorValue(0x0047abff));
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> box_shadow_list =
@@ -918,7 +1004,10 @@
       new CSSComputedStyleData());
   parent_computed_style->set_font_size(new LengthValue(50, kPixelsUnit));
   parent_computed_style->set_color(new RGBAColorValue(0x0047ABFF));
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> box_shadow_list =
@@ -970,7 +1059,10 @@
 
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   EXPECT_EQ(KeywordValue::GetNone(), computed_style->box_shadow());
@@ -982,9 +1074,12 @@
   computed_style->set_text_decoration_color(KeywordValue::GetCurrentColor());
   computed_style->set_color(RGBAColorValue::GetAqua());
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<RGBAColorValue> text_decoration_color =
@@ -1014,7 +1109,10 @@
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_font_size(new LengthValue(50, kPixelsUnit));
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> text_shadow_list =
@@ -1055,7 +1153,10 @@
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_color(new RGBAColorValue(0x0047abff));
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> text_shadow_list =
@@ -1105,7 +1206,10 @@
       new CSSComputedStyleData());
   parent_computed_style->set_font_size(new LengthValue(50, kPixelsUnit));
   parent_computed_style->set_color(new RGBAColorValue(0x0047ABFF));
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> text_shadow_list =
@@ -1156,7 +1260,10 @@
 
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   EXPECT_EQ(KeywordValue::GetNone(), computed_style->text_shadow());
@@ -1171,10 +1278,13 @@
       new CSSComputedStyleData());
   computed_style->set_height(new PercentageValue(0.50f));
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   EXPECT_EQ(KeywordValue::GetAuto(), parent_computed_style->height());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   EXPECT_EQ(KeywordValue::GetAuto(), computed_style->height());
@@ -1190,10 +1300,13 @@
       new CSSComputedStyleData());
   computed_style->set_max_height(new PercentageValue(0.50f));
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   EXPECT_EQ(KeywordValue::GetAuto(), parent_computed_style->height());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   EXPECT_EQ(KeywordValue::GetNone(), computed_style->max_height());
@@ -1209,10 +1322,13 @@
       new CSSComputedStyleData());
   computed_style->set_min_height(new PercentageValue(0.50f));
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   EXPECT_EQ(KeywordValue::GetAuto(), parent_computed_style->height());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   LengthValue* computed_min_height = base::polymorphic_downcast<LengthValue*>(
@@ -1229,15 +1345,22 @@
       new CSSComputedStyleData());
   computed_style->set_max_width(new PercentageValue(0.50f));
 
-  scoped_refptr<const CSSComputedStyleData> grandparent_computed_style(
+  scoped_refptr<CSSComputedStyleData> grandparent_computed_style(
       new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration>
+      grandparent_computed_style_declaration(
+          CreateComputedStyleDeclaration(grandparent_computed_style));
 
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_width(new LengthValue(-16, kPixelsUnit));
-  PromoteToComputedStyle(parent_computed_style, grandparent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(parent_computed_style,
+                         grandparent_computed_style_declaration,
                          grandparent_computed_style, math::Size(), NULL);
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          grandparent_computed_style, math::Size(), NULL);
 
   LengthValue* computed_max_width = base::polymorphic_downcast<LengthValue*>(
@@ -1254,15 +1377,22 @@
       new CSSComputedStyleData());
   computed_style->set_min_width(new PercentageValue(0.50f));
 
-  scoped_refptr<const CSSComputedStyleData> grandparent_computed_style(
+  scoped_refptr<CSSComputedStyleData> grandparent_computed_style(
       new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration>
+      grandparent_computed_style_declaration(
+          CreateComputedStyleDeclaration(grandparent_computed_style));
 
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_width(new LengthValue(-16, kPixelsUnit));
-  PromoteToComputedStyle(parent_computed_style, grandparent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(parent_computed_style,
+                         grandparent_computed_style_declaration,
                          grandparent_computed_style, math::Size(), NULL);
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          grandparent_computed_style, math::Size(), NULL);
 
   LengthValue* computed_min_width = base::polymorphic_downcast<LengthValue*>(
@@ -1280,10 +1410,12 @@
   computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
   computed_style->set_line_height(new PercentageValue(0.75f));
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
 
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   LengthValue* computed_line_height = base::polymorphic_downcast<LengthValue*>(
@@ -1304,9 +1436,12 @@
       new PropertyListValue(transform_origin_builder.Pass()));
   computed_style->set_transform_origin(transform_origin);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1347,9 +1482,12 @@
       new PropertyListValue(transform_origin_builder.Pass()));
   computed_style->set_transform_origin(transform_origin);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1391,9 +1529,12 @@
       new PropertyListValue(transform_origin_builder.Pass()));
   computed_style->set_transform_origin(transform_origin);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1435,9 +1576,12 @@
       new PropertyListValue(transform_origin_builder.Pass()));
   computed_style->set_transform_origin(transform_origin);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1479,9 +1623,12 @@
       new PropertyListValue(transform_origin_builder.Pass()));
   computed_style->set_transform_origin(transform_origin);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1523,9 +1670,12 @@
       new PropertyListValue(transform_origin_builder.Pass()));
   computed_style->set_transform_origin(transform_origin);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1568,9 +1718,12 @@
       new PropertyListValue(transform_origin_builder.Pass()));
   computed_style->set_transform_origin(transform_origin);
 
-  scoped_refptr<const CSSComputedStyleData> parent_computed_style(
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<PropertyListValue> transform_origin_list =
@@ -1614,7 +1767,10 @@
   scoped_refptr<CSSComputedStyleData> parent_computed_style(
       new CSSComputedStyleData());
   parent_computed_style->set_font_size(new LengthValue(100, kPixelsUnit));
-  PromoteToComputedStyle(computed_style, parent_computed_style,
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
                          parent_computed_style, math::Size(), NULL);
 
   scoped_refptr<TransformFunctionListValue> computed_transform =
@@ -1631,5 +1787,238 @@
   EXPECT_EQ(kPixelsUnit, computed_function->offset_as_length()->unit());
 }
 
+TEST(PromoteToComputedStyle,
+     InheritedAnimatablePropertyShouldAlwaysBeDeclared) {
+  scoped_refptr<CSSComputedStyleData> computed_style(
+      new CSSComputedStyleData());
+
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
+      new CSSComputedStyleData());
+  parent_computed_style->set_color(RGBAColorValue::GetAqua());
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  // Verify that we're testing an inherited and animatable property.
+  ASSERT_TRUE(GetPropertyInheritance(kColorProperty) &&
+              GetPropertyAnimatable(kColorProperty));
+
+  // For each inherited, animatable property, the property value should be set
+  // to inherited if it is not already declared in PromoteToComputedStyle().
+  // This causes the value to be  explicitly set within the CSSComputedStyleData
+  // and ensures that the original value will be available for transitions
+  // (which need to know the before and after state of the property) even when
+  // the property is inherited from a parent that has changed.
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+                         parent_computed_style, math::Size(), NULL);
+
+  // Verify that the color is declared in the child even though it was not
+  // explicitly declared.
+  ASSERT_TRUE(computed_style->IsDeclared(kColorProperty));
+}
+
+TEST(PromoteToComputedStyle,
+     DeclaredPropertiesInheritedFromParentShouldRemainValidWhenSetToSameValue) {
+  scoped_refptr<CSSComputedStyleData> computed_style(
+      new CSSComputedStyleData());
+
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
+      new CSSComputedStyleData());
+  parent_computed_style->set_color(
+      new RGBAColorValue(uint8(10), uint8(10), uint8(10), uint8(10)));
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  // Verify that we're testing an inherited and animatable property.
+  ASSERT_TRUE(GetPropertyInheritance(kColorProperty) &&
+              GetPropertyAnimatable(kColorProperty));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+                         parent_computed_style, math::Size(), NULL);
+
+  // Verify that the declared properties inherited from the parent are valid.
+  ASSERT_TRUE(computed_style->AreDeclaredPropertiesInheritedFromParentValid());
+
+  parent_computed_style = new CSSComputedStyleData();
+  parent_computed_style->set_color(
+      new RGBAColorValue(uint8(10), uint8(10), uint8(10), uint8(10)));
+  parent_computed_style_declaration->SetData(parent_computed_style);
+
+  // Verify that the declared properties inherited from the parent are still
+  // valid.
+  ASSERT_TRUE(computed_style->AreDeclaredPropertiesInheritedFromParentValid());
+}
+
+TEST(PromoteToComputedStyle,
+     InheritedAnimatablePropertyShouldRetainValueAfterParentValueChanges) {
+  scoped_refptr<CSSComputedStyleData> computed_style(
+      new CSSComputedStyleData());
+
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
+      new CSSComputedStyleData());
+  parent_computed_style->set_color(RGBAColorValue::GetAqua());
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+
+  // Verify that we're testing an inherited and animatable property.
+  ASSERT_TRUE(GetPropertyInheritance(kColorProperty) &&
+              GetPropertyAnimatable(kColorProperty));
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+                         parent_computed_style, math::Size(), NULL);
+
+  // Verify that the child's color is Aqua and matches the parent's color.
+  EXPECT_EQ(RGBAColorValue::GetAqua(), computed_style->color());
+  EXPECT_EQ(parent_computed_style->color(), computed_style->color());
+
+  // Verify that the declared properties inherited from the parent are valid.
+  ASSERT_TRUE(computed_style->AreDeclaredPropertiesInheritedFromParentValid());
+
+  parent_computed_style = new CSSComputedStyleData();
+  parent_computed_style->set_color(RGBAColorValue::GetNavy());
+  parent_computed_style_declaration->SetData(parent_computed_style);
+
+  // Verify that the color is still Aqua but that it no longer matches the
+  // parent's color.
+  EXPECT_EQ(RGBAColorValue::GetAqua(), computed_style->color());
+  EXPECT_NE(parent_computed_style->color(), computed_style->color());
+
+  // Verify that the declared properties inherited from the parent are no
+  // longer valid.
+  ASSERT_FALSE(computed_style->AreDeclaredPropertiesInheritedFromParentValid());
+}
+
+TEST(UpdateInheritedData,
+     UpdateInheritedDataShouldFixInheritedDataAfterItIsAdded) {
+  scoped_refptr<CSSComputedStyleData> grandparent_computed_style(
+      new CSSComputedStyleData());
+  scoped_refptr<CSSComputedStyleDeclaration>
+      grandparent_computed_style_declaration(
+          CreateComputedStyleDeclaration(grandparent_computed_style));
+
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
+      new CSSComputedStyleData());
+  // The parent should initially have the default value of normal.
+  EXPECT_EQ(FontStyleValue::GetNormal(), parent_computed_style->font_style());
+
+  PromoteToComputedStyle(parent_computed_style,
+                         grandparent_computed_style_declaration,
+                         grandparent_computed_style, math::Size(), NULL);
+  // The parent should still have the default value of normal.
+  EXPECT_EQ(FontStyleValue::GetNormal(), parent_computed_style->font_style());
+
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+  scoped_refptr<CSSComputedStyleData> computed_style(
+      new CSSComputedStyleData());
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+                         grandparent_computed_style, math::Size(), NULL);
+
+  // The child should have the default value of normal.
+  EXPECT_EQ(FontStyleValue::GetNormal(), computed_style->font_style());
+
+  grandparent_computed_style = new CSSComputedStyleData();
+  grandparent_computed_style->set_font_style(FontStyleValue::GetOblique());
+  grandparent_computed_style_declaration->SetData(grandparent_computed_style);
+
+  // Even though the grandparent has changed, the child should have the original
+  // default value of normal until UpdateInheritedData() is called.
+  EXPECT_EQ(FontStyleValue::GetNormal(), computed_style->font_style());
+  parent_computed_style_declaration->UpdateInheritedData();
+
+  // Now that UpdateInheritedData() has been called, the child should have the
+  // new inherited value of oblique.
+  EXPECT_EQ(FontStyleValue::GetOblique(), computed_style->font_style());
+}
+
+TEST(UpdateInheritedData,
+     UpdateInheritedDataShouldFixInheritedDataAfterItIsRemoved) {
+  scoped_refptr<CSSComputedStyleData> grandparent_computed_style(
+      new CSSComputedStyleData());
+  grandparent_computed_style->set_font_style(FontStyleValue::GetItalic());
+  scoped_refptr<CSSComputedStyleDeclaration>
+      grandparent_computed_style_declaration(
+          CreateComputedStyleDeclaration(grandparent_computed_style));
+
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
+      new CSSComputedStyleData());
+  // The parent should initially have the default value of normal.
+  EXPECT_EQ(FontStyleValue::GetNormal(), parent_computed_style->font_style());
+
+  PromoteToComputedStyle(parent_computed_style,
+                         grandparent_computed_style_declaration,
+                         grandparent_computed_style, math::Size(), NULL);
+  // The parent should now have the inherited value of italic.
+  EXPECT_EQ(FontStyleValue::GetItalic(), parent_computed_style->font_style());
+
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+  scoped_refptr<CSSComputedStyleData> computed_style(
+      new CSSComputedStyleData());
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+                         grandparent_computed_style, math::Size(), NULL);
+
+  // The child should have the inherited value of italic.
+  EXPECT_EQ(FontStyleValue::GetItalic(), computed_style->font_style());
+
+  grandparent_computed_style = new CSSComputedStyleData();
+  grandparent_computed_style_declaration->SetData(grandparent_computed_style);
+
+  // Even though the grandparent has changed, the child should have the original
+  // inherited value of italic until UpdateInheritedData() is called.
+  EXPECT_EQ(FontStyleValue::GetItalic(), computed_style->font_style());
+  parent_computed_style_declaration->UpdateInheritedData();
+
+  // Now that UpdateInheritedData() has been called, the child should have the
+  // default value of normal.
+  EXPECT_EQ(FontStyleValue::GetNormal(), computed_style->font_style());
+}
+
+TEST(UpdateInheritedData,
+     UpdateInheritedDataShouldFixInheritedDataAfterItChanges) {
+  scoped_refptr<CSSComputedStyleData> grandparent_computed_style(
+      new CSSComputedStyleData());
+  grandparent_computed_style->set_font_style(FontStyleValue::GetItalic());
+  scoped_refptr<CSSComputedStyleDeclaration>
+      grandparent_computed_style_declaration(
+          CreateComputedStyleDeclaration(grandparent_computed_style));
+
+  scoped_refptr<CSSComputedStyleData> parent_computed_style(
+      new CSSComputedStyleData());
+  // The parent should initially have the default value of normal.
+  EXPECT_EQ(FontStyleValue::GetNormal(), parent_computed_style->font_style());
+
+  PromoteToComputedStyle(parent_computed_style,
+                         grandparent_computed_style_declaration,
+                         grandparent_computed_style, math::Size(), NULL);
+  // The parent should now have the inherited value of italic.
+  EXPECT_EQ(FontStyleValue::GetItalic(), parent_computed_style->font_style());
+
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration(
+      CreateComputedStyleDeclaration(parent_computed_style));
+  scoped_refptr<CSSComputedStyleData> computed_style(
+      new CSSComputedStyleData());
+
+  PromoteToComputedStyle(computed_style, parent_computed_style_declaration,
+                         grandparent_computed_style, math::Size(), NULL);
+
+  // The child should have the inherited value of italic.
+  EXPECT_EQ(FontStyleValue::GetItalic(), computed_style->font_style());
+
+  grandparent_computed_style = new CSSComputedStyleData();
+  grandparent_computed_style->set_font_style(FontStyleValue::GetOblique());
+  grandparent_computed_style_declaration->SetData(grandparent_computed_style);
+
+  // Even though the grandparent has changed, the child should have the original
+  // inherited value of italic until UpdateInheritedData() is called.
+  EXPECT_EQ(FontStyleValue::GetItalic(), computed_style->font_style());
+  parent_computed_style_declaration->UpdateInheritedData();
+
+  // Now that UpdateInheritedData() has been called, the child should have the
+  // new inherited value of oblique.
+  EXPECT_EQ(FontStyleValue::GetOblique(), computed_style->font_style());
+}
+
 }  // namespace cssom
 }  // namespace cobalt
diff --git a/src/cobalt/cssom/css_computed_style_data.cc b/src/cobalt/cssom/css_computed_style_data.cc
index c2a4689..590ea05 100644
--- a/src/cobalt/cssom/css_computed_style_data.cc
+++ b/src/cobalt/cssom/css_computed_style_data.cc
@@ -20,6 +20,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/string_util.h"
+#include "cobalt/cssom/css_computed_style_declaration.h"
 #include "cobalt/cssom/keyword_value.h"
 #include "cobalt/cssom/length_value.h"
 
@@ -62,7 +63,9 @@
 }
 
 CSSComputedStyleData::CSSComputedStyleData()
-    : has_inherited_properties_(false) {}
+    : has_declared_inherited_properties_(false) {}
+
+CSSComputedStyleData::~CSSComputedStyleData() {}
 
 unsigned int CSSComputedStyleData::length() const {
   // Computed style declarations have all known longhand properties.
@@ -79,12 +82,18 @@
   DCHECK_GT(key, kNoneProperty);
   DCHECK_LE(key, kMaxLonghandPropertyKey);
 
+  // If the property's value is explicitly declared, then simply return it.
   if (declared_properties_[key]) {
     return declared_property_values_.find(key)->second;
   }
-  if (ancestor_computed_style_ &&
-      GetPropertyInheritance(key) == kInheritedYes) {
-    return ancestor_computed_style_->GetPropertyValueReference(key);
+
+  // Otherwise, if the property is inherited and the parent has inherited
+  // properties, then retrieve the parent's value for the property.
+  if (parent_computed_style_declaration_ &&
+      GetPropertyInheritance(key) == kInheritedYes &&
+      parent_computed_style_declaration_->HasInheritedProperties()) {
+    return parent_computed_style_declaration_
+        ->GetInheritedPropertyValueReference(key);
   }
 
   // For the root element, which has no parent element, the inherited value is
@@ -270,8 +279,18 @@
   if (value) {
     declared_properties_.set(key, true);
     declared_property_values_[key] = value;
-    has_inherited_properties_ = has_inherited_properties_ ||
-                                GetPropertyInheritance(key) == kInheritedYes;
+    // Only set |has_declared_inherited_properties_| if the property is
+    // inherited and the the value isn't explicitly set to "inherit". If it is
+    // set to "inherit", then the value is simply a copy of the parent's value,
+    // which doesn't necessitate the node being included in the inheritance
+    // tree, as it doesn't provide new information.
+    // NOTE: Declaring a value of "inherit" on an inherited property is used for
+    // transitions, which need to know the original value of the property (which
+    // would otherwise be lost when the parent changed).
+    has_declared_inherited_properties_ =
+        has_declared_inherited_properties_ ||
+        (GetPropertyInheritance(key) == kInheritedYes &&
+         value != KeywordValue::GetInherit());
   } else if (declared_properties_[key]) {
     declared_properties_.set(key, false);
     declared_property_values_.erase(key);
@@ -281,7 +300,10 @@
 void CSSComputedStyleData::AssignFrom(const CSSComputedStyleData& rhs) {
   declared_properties_ = rhs.declared_properties_;
   declared_property_values_ = rhs.declared_property_values_;
-  has_inherited_properties_ = rhs.has_inherited_properties_;
+  has_declared_inherited_properties_ = rhs.has_declared_inherited_properties_;
+  declared_properties_inherited_from_parent_ =
+      rhs.declared_properties_inherited_from_parent_;
+  parent_computed_style_declaration_ = rhs.parent_computed_style_declaration_;
 }
 
 std::string CSSComputedStyleData::SerializeCSSDeclarationBlock() const {
@@ -305,18 +327,84 @@
   return serialized_text;
 }
 
-void CSSComputedStyleData::SetParentComputedStyle(
-    const scoped_refptr<const CSSComputedStyleData>& parent_computed_style) {
-  if (parent_computed_style->has_inherited_properties_) {
-    ancestor_computed_style_ = parent_computed_style;
-  } else {
-    // If the parent style does not have any inherited properties, we will never
-    // need to refer to it for inherited properties, so we refer to the parent
-    // style's ancestor instead. This gives the number of ancestor dereferences
-    // needed to find the value of an inherited property an upper bound equal to
-    // the total number of inheritable properties.
-    ancestor_computed_style_ = parent_computed_style->ancestor_computed_style_;
+void CSSComputedStyleData::AddDeclaredPropertyInheritedFromParent(
+    PropertyKey key) {
+  declared_properties_inherited_from_parent_.push_back(key);
+}
+
+bool CSSComputedStyleData::AreDeclaredPropertiesInheritedFromParentValid()
+    const {
+  // If there are no declared properties inherited from the parent, then it's
+  // impossible for them to be invalid.
+  if (declared_properties_inherited_from_parent_.size() == 0) {
+    return true;
   }
+
+  if (!parent_computed_style_declaration_) {
+    return false;
+  }
+
+  const scoped_refptr<const CSSComputedStyleData>& parent_computed_style_data =
+      parent_computed_style_declaration_->data();
+  if (!parent_computed_style_data) {
+    return false;
+  }
+
+  // Verify that the parent's data is valid.
+  DCHECK(parent_computed_style_data
+             ->AreDeclaredPropertiesInheritedFromParentValid());
+
+  // Walk the declared properties inherited from the parent. They're invalid if
+  // any no longer match the parent's value.
+  for (PropertyKeyVector::const_iterator iter =
+           declared_properties_inherited_from_parent_.begin();
+       iter != declared_properties_inherited_from_parent_.end(); ++iter) {
+    if (!GetPropertyValueReference(*iter)->Equals(
+            *parent_computed_style_data->GetPropertyValueReference(*iter))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool CSSComputedStyleData::DoDeclaredPropertiesMatch(
+    const scoped_refptr<const CSSComputedStyleData>& other) const {
+  // If the bitsets don't match, then there's no need to check the values;
+  // the declared properties are guaranteed to not match.
+  if (declared_properties_ != other->declared_properties_) {
+    return false;
+  }
+
+  // Verify that the same number of declared property values exist within the
+  // two CSSComputedStyleData objects. This should be guaranteed by the
+  // bitsets matching.
+  DCHECK_EQ(declared_property_values_.size(),
+            other->declared_property_values_.size());
+
+  // Walk the two lists of declared property values looking for any keys or
+  // values that don't match.
+  PropertyValues::const_iterator iter1 = declared_property_values_.begin();
+  PropertyValues::const_iterator iter2 =
+      other->declared_property_values_.begin();
+  for (; iter1 != declared_property_values_.end(); ++iter1, ++iter2) {
+    if (iter1->first != iter2->first ||
+        !iter1->second->Equals(*iter2->second)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void CSSComputedStyleData::SetParentComputedStyleDeclaration(
+    const scoped_refptr<CSSComputedStyleDeclaration>&
+        parent_computed_style_declaration) {
+  parent_computed_style_declaration_ = parent_computed_style_declaration;
+}
+
+const scoped_refptr<CSSComputedStyleDeclaration>&
+CSSComputedStyleData::GetParentComputedStyleDeclaration() const {
+  return parent_computed_style_declaration_;
 }
 
 }  // namespace cssom
diff --git a/src/cobalt/cssom/css_computed_style_data.h b/src/cobalt/cssom/css_computed_style_data.h
index 80c93b7..e303868 100644
--- a/src/cobalt/cssom/css_computed_style_data.h
+++ b/src/cobalt/cssom/css_computed_style_data.h
@@ -31,12 +31,11 @@
 namespace cobalt {
 namespace cssom {
 
+class CSSComputedStyleDeclaration;
+
 // CSSComputedStyleData which has PropertyValue type properties only used
-// internally and it is not exposed to JavaScript.  It derives from
-// RefCountedThreadSafe instead of RefCounted so that it can be passed forward
-// to another thread for animating before rendering a scene.
-class CSSComputedStyleData
-    : public base::RefCountedThreadSafe<CSSComputedStyleData> {
+// internally and it is not exposed to JavaScript.
+class CSSComputedStyleData : public base::RefCounted<CSSComputedStyleData> {
  public:
   // This class provides the ability to determine whether the properties of two
   // CSSComputedStyleData objects match for a given set of property keys.
@@ -61,6 +60,7 @@
                          16, std::equal_to<PropertyKey> > PropertyValues;
 
   CSSComputedStyleData();
+  ~CSSComputedStyleData();
 
   // The length attribute must return the number of CSS declarations in the
   // declarations.
@@ -661,25 +661,54 @@
 
   void AssignFrom(const CSSComputedStyleData& rhs);
 
+  // This returns the result of serializing a CSS declaration block.
+  // The current implementation does not handle shorthands.
+  //   https://www.w3.org/TR/cssom/#serialize-a-css-declaration-block
+  std::string SerializeCSSDeclarationBlock() const;
+
   // Returns true if the property is explicitly declared in this style, as
   // opposed to implicitly inheriting from its parent or the initial value.
   bool IsDeclared(const PropertyKey key) const {
     return declared_properties_[key];
   }
 
-  // This returns the result of serializing a CSS declaration block.
-  // The current implementation does not handle shorthands.
-  //   https://www.w3.org/TR/cssom/#serialize-a-css-declaration-block
-  std::string SerializeCSSDeclarationBlock() const;
+  // Whether or not any inherited properties have been declared.
+  // NOTE: Inherited properties that are set to a value "inherit" do not impact
+  // this flag, as they will have the same value as the parent and can be
+  // skipped by descendants retrieving their inherited value without impacting
+  // the returned value.
+  bool has_declared_inherited_properties() const {
+    return has_declared_inherited_properties_;
+  }
 
-  // Set the parent computed style for tracking inherited properties.
-  void SetParentComputedStyle(
-      const scoped_refptr<const CSSComputedStyleData>& parent_computed_style);
+  // Adds a declared property that was inherited from the parent to an
+  // internal list. This facilitates tracking of whether or not a value that was
+  // initially set to a parent's value continues to match the parent's value.
+  void AddDeclaredPropertyInheritedFromParent(PropertyKey key);
+
+  // Returns true if all of the declared properties that were inherited from the
+  // parent are still valid. They become invalid when the parent's value
+  // changes.
+  bool AreDeclaredPropertiesInheritedFromParentValid() const;
 
   PropertyValues* declared_property_values() {
     return &declared_property_values_;
   }
 
+  // Returns whether or not the declared properties in the passed in
+  // CSSComputedStyleData matches those declared within this one.
+  bool DoDeclaredPropertiesMatch(
+      const scoped_refptr<const CSSComputedStyleData>& other) const;
+
+  // Set the parent computed style for tracking inherited properties.
+  void SetParentComputedStyleDeclaration(
+      const scoped_refptr<CSSComputedStyleDeclaration>&
+          parent_computed_style_declaration);
+
+  // Returns the parent computed style used for tracking inherited properties.
+  const scoped_refptr<CSSComputedStyleDeclaration>&
+  GetParentComputedStyleDeclaration() const;
+
  private:
   // Helper function that returns the computed value if the initial property
   // value is not computed or returns the initial value if it is computed.
@@ -691,10 +720,25 @@
   LonghandPropertiesBitset declared_properties_;
   PropertyValues declared_property_values_;
 
-  scoped_refptr<const CSSComputedStyleData> ancestor_computed_style_;
+  // True if this style has any inherited properties declared.
+  // NOTE: Inherited properties that are set to a value "inherit" do not impact
+  // this flag, as they will have the same value as the parent and can be
+  // skipped by descendants retrieving their inherited value without impacting
+  // the returned value.
+  bool has_declared_inherited_properties_;
 
-  // True if this style has any inheritable properties defined.
-  bool has_inherited_properties_;
+  // Properties that were initially set to a value of "inherit" before being
+  // updated with the parent's value. This is used to determine whether the
+  // declared properties inherited from the parent have subsequently changed.
+  PropertyKeyVector declared_properties_inherited_from_parent_;
+
+  // The parent used for inherited properties.
+  // NOTE: The parent is a CSSComputedStyleDeclaration, rather than a
+  // CSSComputedStyleData, in order to allow for the replacement of ancestor
+  // CSSComputedStyleData objects without requiring all of its descendants to
+  // also be replaced. The descendant's inherited property value will instead
+  // dynamically update.
+  scoped_refptr<CSSComputedStyleDeclaration> parent_computed_style_declaration_;
 };
 
 }  // namespace cssom
diff --git a/src/cobalt/cssom/css_computed_style_data_test.cc b/src/cobalt/cssom/css_computed_style_data_test.cc
index 3dd7f71..2fcb1ea 100644
--- a/src/cobalt/cssom/css_computed_style_data_test.cc
+++ b/src/cobalt/cssom/css_computed_style_data_test.cc
@@ -1128,5 +1128,68 @@
   EXPECT_EQ(KeywordValue::GetBlock(), style->display());
 }
 
+TEST(CSSComputedStyleDataTest,
+     DoDeclaredPropertiesMatchWorksWithUnequalNumberOfDeclaredProperties) {
+  scoped_refptr<CSSComputedStyleData> style1 = new CSSComputedStyleData();
+  style1->set_font_size(new LengthValue(50, kPixelsUnit));
+
+  scoped_refptr<CSSComputedStyleData> style2 = new CSSComputedStyleData();
+
+  ASSERT_FALSE(style1->DoDeclaredPropertiesMatch(style2));
+  ASSERT_FALSE(style2->DoDeclaredPropertiesMatch(style1));
+}
+
+TEST(CSSComputedStyleDataTest,
+     DoDeclaredPropertiesMatchWorksWithSingleUnequalProperty) {
+  scoped_refptr<CSSComputedStyleData> style1 = new CSSComputedStyleData();
+  style1->set_font_size(new LengthValue(50, kPixelsUnit));
+
+  scoped_refptr<CSSComputedStyleData> style2 = new CSSComputedStyleData();
+  style2->set_font_size(new LengthValue(30, kPixelsUnit));
+
+  ASSERT_FALSE(style1->DoDeclaredPropertiesMatch(style2));
+  ASSERT_FALSE(style2->DoDeclaredPropertiesMatch(style1));
+}
+
+TEST(CSSComputedStyleDataTest,
+     DoDeclaredPropertiesMatchWorksWithSingleEqualProperty) {
+  scoped_refptr<CSSComputedStyleData> style1 = new CSSComputedStyleData();
+  style1->set_font_size(new LengthValue(50, kPixelsUnit));
+
+  scoped_refptr<CSSComputedStyleData> style2 = new CSSComputedStyleData();
+  style2->set_font_size(new LengthValue(50, kPixelsUnit));
+
+  ASSERT_TRUE(style1->DoDeclaredPropertiesMatch(style2));
+  ASSERT_TRUE(style2->DoDeclaredPropertiesMatch(style1));
+}
+
+TEST(CSSComputedStyleDataTest,
+     DoDeclaredPropertiesMatchWorksWithMultipleUnequalProperties) {
+  scoped_refptr<CSSComputedStyleData> style1 = new CSSComputedStyleData();
+  style1->set_position(KeywordValue::GetAbsolute());
+  style1->set_font_size(new LengthValue(50, kPixelsUnit));
+
+  scoped_refptr<CSSComputedStyleData> style2 = new CSSComputedStyleData();
+  style2->set_position(KeywordValue::GetAbsolute());
+  style2->set_font_size(new LengthValue(30, kPixelsUnit));
+
+  ASSERT_FALSE(style1->DoDeclaredPropertiesMatch(style2));
+  ASSERT_FALSE(style2->DoDeclaredPropertiesMatch(style1));
+}
+
+TEST(CSSComputedStyleDataTest,
+     DoDeclaredPropertiesMatchWorksWithMultipleEqualProperty) {
+  scoped_refptr<CSSComputedStyleData> style1 = new CSSComputedStyleData();
+  style1->set_position(KeywordValue::GetAbsolute());
+  style1->set_font_size(new LengthValue(50, kPixelsUnit));
+
+  scoped_refptr<CSSComputedStyleData> style2 = new CSSComputedStyleData();
+  style2->set_position(KeywordValue::GetAbsolute());
+  style2->set_font_size(new LengthValue(50, kPixelsUnit));
+
+  ASSERT_TRUE(style1->DoDeclaredPropertiesMatch(style2));
+  ASSERT_TRUE(style2->DoDeclaredPropertiesMatch(style1));
+}
+
 }  // namespace cssom
 }  // namespace cobalt
diff --git a/src/cobalt/cssom/css_computed_style_declaration.cc b/src/cobalt/cssom/css_computed_style_declaration.cc
index 0d477a4..11c7dbb 100644
--- a/src/cobalt/cssom/css_computed_style_declaration.cc
+++ b/src/cobalt/cssom/css_computed_style_declaration.cc
@@ -72,5 +72,45 @@
                            exception_state);
 }
 
+void CSSComputedStyleDeclaration::SetData(
+    const scoped_refptr<const CSSComputedStyleData>& data) {
+  data_ = data;
+  // After setting |data_|, |data_with_inherited_properties_| needs to be
+  // updated. It may have changed.
+  UpdateInheritedData();
+}
+
+void CSSComputedStyleDeclaration::UpdateInheritedData() {
+  if (!data_) {
+    // If there's no data, then there can be no data with inherited properties.
+    data_with_inherited_properties_ = NULL;
+  } else if (data_->has_declared_inherited_properties()) {
+    // Otherwise, if the data has inherited properties, then it's also the first
+    // data with inherited properties.
+    data_with_inherited_properties_ = data_;
+  } else {
+    // Otherwise, |data_with_inherited_properties_| should be set to the parent
+    // computed style's |data_with_inherited_properties_|. This is because the
+    // updates always cascade down the tree and the parent is guaranteed to
+    // have already been updated when the child is updated.
+    const scoped_refptr<CSSComputedStyleDeclaration>&
+        parent_computed_style_declaration =
+            data_->GetParentComputedStyleDeclaration();
+    if (parent_computed_style_declaration) {
+      data_with_inherited_properties_ =
+          parent_computed_style_declaration->data_with_inherited_properties_;
+    } else {
+      data_with_inherited_properties_ = NULL;
+    }
+  }
+}
+
+const scoped_refptr<PropertyValue>&
+CSSComputedStyleDeclaration::GetInheritedPropertyValueReference(
+    PropertyKey key) const {
+  DCHECK(data_with_inherited_properties_);
+  return data_with_inherited_properties_->GetPropertyValueReference(key);
+}
+
 }  // namespace cssom
 }  // namespace cobalt
diff --git a/src/cobalt/cssom/css_computed_style_declaration.h b/src/cobalt/cssom/css_computed_style_declaration.h
index 36a4947..e166979 100644
--- a/src/cobalt/cssom/css_computed_style_declaration.h
+++ b/src/cobalt/cssom/css_computed_style_declaration.h
@@ -58,10 +58,23 @@
   const scoped_refptr<const CSSComputedStyleData>& data() const {
     return data_;
   }
-  void set_data(const scoped_refptr<const CSSComputedStyleData>& data) {
-    data_ = data;
+  void SetData(const scoped_refptr<const CSSComputedStyleData>& data);
+
+  // Updates the pointer to the nearest CSSComputedStyleData ancestor,
+  // inclusive, which has inherited properties declared.
+  void UpdateInheritedData();
+
+  // Returns whether or not this object or any ancestors have inherited
+  // properties declared.
+  bool HasInheritedProperties() const {
+    return data_with_inherited_properties_ != NULL;
   }
 
+  // Returns the reference to the property value for an inherited property.
+  // Should only be called if HasInheritedProperties() returns true.
+  const scoped_refptr<PropertyValue>& GetInheritedPropertyValueReference(
+      PropertyKey key) const;
+
   const scoped_refptr<const web_animations::AnimationSet>& animations() const {
     return animations_;
   }
@@ -74,9 +87,15 @@
   // From CSSStyleDeclaration.
   std::string GetDeclaredPropertyValueStringByKey(
       const PropertyKey key) const OVERRIDE;
+
+  // The CSSComputedStyleData owned by this object.
   scoped_refptr<const CSSComputedStyleData> data_;
 
-  // All animation that applies to  the above computed style.
+  // The nearest CSSComputedStyleData ancestor, inclusive, which has inherited
+  // properties declared.
+  scoped_refptr<const CSSComputedStyleData> data_with_inherited_properties_;
+
+  // All animation that applies to the above computed style.
   scoped_refptr<const web_animations::AnimationSet> animations_;
 
   DISALLOW_COPY_AND_ASSIGN(CSSComputedStyleDeclaration);
diff --git a/src/cobalt/cssom/css_transition_set.cc b/src/cobalt/cssom/css_transition_set.cc
index 4292a94..6edeae6 100644
--- a/src/cobalt/cssom/css_transition_set.cc
+++ b/src/cobalt/cssom/css_transition_set.cc
@@ -84,10 +84,8 @@
   // For each animatable property, check to see if there are any transitions
   // assigned to it.  If so, check to see if there are any existing transitions
   // that must be updated, otherwise introduce new transitions.
-  const AnimatablePropertyList& animatable_properties =
-      GetAnimatableProperties();
-  for (AnimatablePropertyList::const_iterator iter =
-           animatable_properties.begin();
+  const PropertyKeyVector& animatable_properties = GetAnimatableProperties();
+  for (PropertyKeyVector::const_iterator iter = animatable_properties.begin();
        iter != animatable_properties.end(); ++iter) {
     UpdateTransitionForProperty(
         *iter, current_time, source_computed_style.GetPropertyValue(*iter),
@@ -216,7 +214,7 @@
 
       if (existing_transition &&
           current_time < existing_transition->EndTime()) {
-        // A transition is already ocurring, so we handle this case a bit
+        // A transition is already occurring, so we handle this case a bit
         // differently depending on if we're reversing the previous transition
         // or starting a completely different one.
         transitions_.UpdateTransitionForProperty(
diff --git a/src/cobalt/cssom/cssom.gyp b/src/cobalt/cssom/cssom.gyp
index ab8852c..63be9ea 100644
--- a/src/cobalt/cssom/cssom.gyp
+++ b/src/cobalt/cssom/cssom.gyp
@@ -227,6 +227,7 @@
       ],
       'dependencies': [
         '<(DEPTH)/cobalt/base/base.gyp:base',
+        '<(DEPTH)/cobalt/dom/dom_exception.gyp:dom_exception',
         '<(DEPTH)/cobalt/math/math.gyp:math',
         '<(DEPTH)/googleurl/googleurl.gyp:googleurl',
         'embed_resources_as_header_files',
diff --git a/src/cobalt/cssom/property_definitions.cc b/src/cobalt/cssom/property_definitions.cc
index d589181..8133992 100644
--- a/src/cobalt/cssom/property_definitions.cc
+++ b/src/cobalt/cssom/property_definitions.cc
@@ -49,6 +49,7 @@
       : name(NULL),
         inherited(kInheritedNo),
         animatable(kAnimatableNo),
+        impacts_child_declared_style(kImpactsChildDeclaredStyleNo),
         impacts_box_generation(kImpactsBoxGenerationNo),
         impacts_box_sizes(kImpactsBoxSizesNo),
         impacts_box_cross_references(kImpactsBoxCrossReferencesNo) {}
@@ -56,6 +57,7 @@
   const char* name;
   Inherited inherited;
   Animatable animatable;
+  ImpactsChildDeclaredStyle impacts_child_declared_style;
   ImpactsBoxGeneration impacts_box_generation;
   ImpactsBoxSizes impacts_box_sizes;
   ImpactsBoxCrossReferences impacts_box_cross_references;
@@ -68,11 +70,14 @@
 
   std::vector<PropertyKey> lexicographical_longhand_keys;
   PropertyDefinition properties[kMaxEveryPropertyKey + 1];
-  AnimatablePropertyList animatable_properties;
+  PropertyKeyVector animatable_properties;
+  PropertyKeyVector inherited_animatable_properties;
 
   void SetPropertyDefinition(
       PropertyKey key, const char* name, Inherited inherited,
-      Animatable animatable, ImpactsBoxGeneration impacts_box_generation,
+      Animatable animatable,
+      ImpactsChildDeclaredStyle impacts_child_declared_style,
+      ImpactsBoxGeneration impacts_box_generation,
       ImpactsBoxSizes impacts_box_sizes,
       ImpactsBoxCrossReferences impacts_box_cross_references,
       const scoped_refptr<PropertyValue>& initial_value) {
@@ -82,6 +87,7 @@
     definition.name = name;
     definition.inherited = inherited;
     definition.animatable = animatable;
+    definition.impacts_child_declared_style = impacts_child_declared_style;
     definition.impacts_box_generation = impacts_box_generation;
     definition.impacts_box_sizes = impacts_box_sizes;
     definition.impacts_box_cross_references = impacts_box_cross_references;
@@ -151,61 +157,65 @@
 
 NonTrivialGlobalVariables::NonTrivialGlobalVariables() {
   // https://www.w3.org/TR/css3-animations/#animation-delay-property
-  SetPropertyDefinition(kAnimationDelayProperty, "animation-delay",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        CreateTimeListWithZeroSeconds());
+  SetPropertyDefinition(
+      kAnimationDelayProperty, "animation-delay", kInheritedNo, kAnimatableNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo, CreateTimeListWithZeroSeconds());
 
   // https://www.w3.org/TR/css3-animations/#animation-direction-property
   SetPropertyDefinition(
       kAnimationDirectionProperty, "animation-direction", kInheritedNo,
-      kAnimatableNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
-      kImpactsBoxCrossReferencesNo,
+      kAnimatableNo, kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+      kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
       CreateSinglePropertyListWithValue(KeywordValue::GetNormal()));
 
   // https://www.w3.org/TR/css3-animations/#animation-duration-property
   SetPropertyDefinition(kAnimationDurationProperty, "animation-duration",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         CreateTimeListWithZeroSeconds());
 
   // https://www.w3.org/TR/css3-animations/#animation-fill-mode-property
   SetPropertyDefinition(
       kAnimationFillModeProperty, "animation-fill-mode", kInheritedNo,
-      kAnimatableNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
-      kImpactsBoxCrossReferencesNo,
+      kAnimatableNo, kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+      kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
       CreateSinglePropertyListWithValue(KeywordValue::GetNone()));
 
   // https://www.w3.org/TR/css3-animations/#animation-iteration-count-property
   SetPropertyDefinition(
       kAnimationIterationCountProperty, "animation-iteration-count",
-      kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
-      kImpactsBoxCrossReferencesNo,
+      kInheritedNo, kAnimatableNo, kImpactsChildDeclaredStyleNo,
+      kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
       CreateSinglePropertyListWithValue(new NumberValue(1.0f)));
 
   // https://www.w3.org/TR/css3-animations/#animation-name-property
   SetPropertyDefinition(
       kAnimationNameProperty, "animation-name", kInheritedNo, kAnimatableNo,
-      kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo,
       CreateSinglePropertyListWithValue(KeywordValue::GetNone()));
 
   // https://www.w3.org/TR/css3-animations/#animation-timing-function-property
-  SetPropertyDefinition(kAnimationTimingFunctionProperty,
-                        "animation-timing-function", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        CreateTransitionTimingFunctionListWithEase());
+  SetPropertyDefinition(
+      kAnimationTimingFunctionProperty, "animation-timing-function",
+      kInheritedNo, kAnimatableNo, kImpactsChildDeclaredStyleNo,
+      kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+      CreateTransitionTimingFunctionListWithEase());
 
   // https://www.w3.org/TR/css3-background/#the-background-color
   SetPropertyDefinition(kBackgroundColorProperty, "background-color",
-                        kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableYes,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         new RGBAColorValue(0x00000000));
 
   // https://www.w3.org/TR/css3-background/#background-image
   SetPropertyDefinition(
       kBackgroundImageProperty, "background-image", kInheritedNo, kAnimatableNo,
-      kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo,
       CreateSinglePropertyListWithValue(KeywordValue::GetNone()));
 
   // https://www.w3.org/TR/css3-background/#the-background-position
@@ -219,7 +229,8 @@
   scoped_refptr<PropertyListValue> background_position_list(
       new PropertyListValue(background_position_builder.Pass()));
   SetPropertyDefinition(kBackgroundPositionProperty, "background-position",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         background_position_list);
 
@@ -234,10 +245,10 @@
   background_repeat_builder->push_back(KeywordValue::GetRepeat());
   scoped_refptr<PropertyListValue> background_repeat_list(
       new PropertyListValue(background_repeat_builder.Pass()));
-  SetPropertyDefinition(kBackgroundRepeatProperty, "background-repeat",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        background_repeat_list);
+  SetPropertyDefinition(
+      kBackgroundRepeatProperty, "background-repeat", kInheritedNo,
+      kAnimatableNo, kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+      kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo, background_repeat_list);
 
   // The first value gives the width of the corresponding image, and the second
   // value gives its height. If only one value is given, the second is assumed
@@ -250,52 +261,59 @@
   background_size_builder->push_back(KeywordValue::GetAuto());
   scoped_refptr<PropertyListValue> background_size_list(
       new PropertyListValue(background_size_builder.Pass()));
-  SetPropertyDefinition(kBackgroundSizeProperty, "background-size",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        background_size_list);
+  SetPropertyDefinition(
+      kBackgroundSizeProperty, "background-size", kInheritedNo, kAnimatableNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo, background_size_list);
 
   // This sets the foreground color of the border specified by the border-style
   // property.
   //   https://www.w3.org/TR/css3-background/#border-color
-  SetPropertyDefinition(kBorderTopColorProperty, "border-top-color",
-                        kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        KeywordValue::GetCurrentColor());
+  SetPropertyDefinition(
+      kBorderTopColorProperty, "border-top-color", kInheritedNo, kAnimatableYes,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo, KeywordValue::GetCurrentColor());
 
   SetPropertyDefinition(kBorderRightColorProperty, "border-right-color",
-                        kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableYes,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetCurrentColor());
 
   SetPropertyDefinition(kBorderBottomColorProperty, "border-bottom-color",
-                        kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableYes,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetCurrentColor());
 
   SetPropertyDefinition(kBorderLeftColorProperty, "border-left-color",
-                        kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableYes,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetCurrentColor());
 
   //   https://www.w3.org/TR/css3-background/#border-style
   SetPropertyDefinition(kBorderTopStyleProperty, "border-top-style",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetNone());
 
   SetPropertyDefinition(kBorderRightStyleProperty, "border-right-style",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetNone());
 
   SetPropertyDefinition(kBorderBottomStyleProperty, "border-bottom-style",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetNone());
 
   SetPropertyDefinition(kBorderLeftStyleProperty, "border-left-style",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetNone());
 
@@ -305,259 +323,290 @@
   // 'medium' font size is 17 px or less.
   //   https://www.w3.org/TR/css3-background/#border-width
   SetPropertyDefinition(kBorderTopWidthProperty, "border-top-width",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
                         new LengthValue(3, kPixelsUnit));
 
   SetPropertyDefinition(kBorderRightWidthProperty, "border-right-width",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
                         new LengthValue(3, kPixelsUnit));
 
   SetPropertyDefinition(kBorderBottomWidthProperty, "border-bottom-width",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
                         new LengthValue(3, kPixelsUnit));
 
   SetPropertyDefinition(kBorderLeftWidthProperty, "border-left-width",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
                         new LengthValue(3, kPixelsUnit));
 
   // Cobalt only support a single length value that applies to all borders.
   //   https://www.w3.org/TR/css3-background/#the-border-radius
-  SetPropertyDefinition(kBorderRadiusProperty, "border-radius", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        new LengthValue(0, kPixelsUnit));
+  SetPropertyDefinition(
+      kBorderRadiusProperty, "border-radius", kInheritedNo, kAnimatableNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo, new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/CSS2/visuren.html#propdef-bottom
   SetPropertyDefinition(kBottomProperty, "bottom", kInheritedNo, kAnimatableNo,
-                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
-                        kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        KeywordValue::GetAuto());
 
   // https://www.w3.org/TR/css3-background/#the-box-shadow
   SetPropertyDefinition(kBoxShadowProperty, "box-shadow", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        KeywordValue::GetNone());
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+                        kImpactsBoxCrossReferencesNo, KeywordValue::GetNone());
 
   // Opaque black in Chromium and Cobalt.
   //   https://www.w3.org/TR/css3-color/#foreground
   SetPropertyDefinition(kColorProperty, "color", kInheritedYes, kAnimatableYes,
-                        kImpactsBoxGenerationYes, kImpactsBoxSizesNo,
-                        kImpactsBoxCrossReferencesNo,
+                        kImpactsChildDeclaredStyleYes, kImpactsBoxGenerationYes,
+                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         new RGBAColorValue(0x000000ff));
 
   // https://www.w3.org/TR/CSS21/generate.html#content
   SetPropertyDefinition(kContentProperty, "content", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationYes,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationYes, kImpactsBoxSizesNo,
+                        kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetNormal());
 
   // https://www.w3.org/TR/CSS21/visuren.html#display-prop
   SetPropertyDefinition(kDisplayProperty, "display", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationYes,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationYes, kImpactsBoxSizesNo,
+                        kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetInline());
 
   // Varies by platform in Chromium, Roboto in Cobalt.
   //   https://www.w3.org/TR/css3-fonts/#font-family-prop
   SetPropertyDefinition(
       kFontFamilyProperty, "font-family", kInheritedYes, kAnimatableNo,
-      kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
-      kImpactsBoxCrossReferencesNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationYes,
+      kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
       CreateSinglePropertyListWithValue(new StringValue("Roboto")));
 
   // "medium" translates to 16px in Chromium.
   // Cobalt does not support keyword sizes, so we simply hardcode 16px.
   //   https://www.w3.org/TR/css3-fonts/#font-size-prop
   SetPropertyDefinition(kFontSizeProperty, "font-size", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationYes,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleYes,
+                        kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(16, kPixelsUnit));
 
   // https://www.w3.org/TR/css3-fonts/#font-style-prop
   SetPropertyDefinition(kFontStyleProperty, "font-style", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationYes,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         FontStyleValue::GetNormal());
 
   // https://www.w3.org/TR/css3-fonts/#font-weight-prop
   SetPropertyDefinition(kFontWeightProperty, "font-weight", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationYes,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         FontWeightValue::GetNormalAka400());
 
   // https://www.w3.org/TR/CSS21/visudet.html#the-height-property
   SetPropertyDefinition(kHeightProperty, "height", kInheritedNo, kAnimatableNo,
-                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
-                        kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+                        kImpactsChildDeclaredStyleYes, kImpactsBoxGenerationNo,
+                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        KeywordValue::GetAuto());
 
   // https://www.w3.org/TR/CSS2/visuren.html#propdef-left
   SetPropertyDefinition(kLeftProperty, "left", kInheritedNo, kAnimatableNo,
-                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
-                        kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        KeywordValue::GetAuto());
 
   // https://www.w3.org/TR/CSS21/visudet.html#line-height
   SetPropertyDefinition(kLineHeightProperty, "line-height", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetNormal());
 
   // https://www.w3.org/TR/CSS21/box.html#margin-properties
   SetPropertyDefinition(kMarginBottomProperty, "margin-bottom", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/CSS21/box.html#margin-properties
   SetPropertyDefinition(kMarginLeftProperty, "margin-left", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/CSS21/box.html#margin-properties
   SetPropertyDefinition(kMarginRightProperty, "margin-right", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/CSS21/box.html#margin-properties
   SetPropertyDefinition(kMarginTopProperty, "margin-top", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/CSS2/visudet.html#propdef-max-height
   SetPropertyDefinition(kMaxHeightProperty, "max-height", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
-                        KeywordValue::GetNone());
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo, KeywordValue::GetNone());
 
   // https://www.w3.org/TR/CSS2/visudet.html#propdef-max-width
   SetPropertyDefinition(kMaxWidthProperty, "max-width", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
-                        KeywordValue::GetNone());
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo, KeywordValue::GetNone());
 
   // https://www.w3.org/TR/CSS2/visudet.html#propdef-min-height
   SetPropertyDefinition(kMinHeightProperty, "min-height", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/CSS2/visudet.html#propdef-min-width
   SetPropertyDefinition(kMinWidthProperty, "min-width", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/css3-color/#opacity
   SetPropertyDefinition(kOpacityProperty, "opacity", kInheritedNo,
-                        kAnimatableYes, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesYes,
-                        new NumberValue(1.0f));
+                        kAnimatableYes, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+                        kImpactsBoxCrossReferencesYes, new NumberValue(1.0f));
 
   // https://www.w3.org/TR/css-overflow-3/#overflow-properties
   SetPropertyDefinition(kOverflowProperty, "overflow", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetVisible());
 
   // https://www.w3.org/TR/css-text-3/#overflow-wrap
   SetPropertyDefinition(kOverflowWrapProperty, "overflow-wrap", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetNormal());
 
   // https://www.w3.org/TR/CSS21/box.html#padding-properties
   SetPropertyDefinition(kPaddingBottomProperty, "padding-bottom", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/CSS21/box.html#padding-properties
   SetPropertyDefinition(kPaddingLeftProperty, "padding-left", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/CSS21/box.html#padding-properties
   SetPropertyDefinition(kPaddingRightProperty, "padding-right", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/CSS21/box.html#padding-properties
   SetPropertyDefinition(kPaddingTopProperty, "padding-top", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/css3-positioning/#position-property
   SetPropertyDefinition(kPositionProperty, "position", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationYes,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesYes,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesYes,
                         KeywordValue::GetStatic());
 
   // https://www.w3.org/TR/CSS2/visuren.html#propdef-right
   SetPropertyDefinition(kRightProperty, "right", kInheritedNo, kAnimatableNo,
-                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
-                        kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        KeywordValue::GetAuto());
 
   //   https://www.w3.org/TR/css-text-3/#text-align
   SetPropertyDefinition(kTextAlignProperty, "text-align", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
-                        KeywordValue::GetStart());
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo, KeywordValue::GetStart());
 
   //   https://www.w3.org/TR/css-text-decor-3/#text-decoration-color
   SetPropertyDefinition(kTextDecorationColorProperty, "text-decoration-color",
-                        kInheritedNo, kAnimatableYes, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableYes,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetCurrentColor());
 
   //   https://www.w3.org/TR/css-text-decor-3/#text-decoration-line
   SetPropertyDefinition(kTextDecorationLineProperty, "text-decoration-line",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetNone());
 
   // https://www.w3.org/TR/CSS21/text.html#propdef-text-indent
   SetPropertyDefinition(kTextIndentProperty, "text-indent", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         new LengthValue(0, kPixelsUnit));
 
   // https://www.w3.org/TR/css3-ui/#propdef-text-overflow
   SetPropertyDefinition(kTextOverflowProperty, "text-overflow", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        KeywordValue::GetClip());
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo, KeywordValue::GetClip());
 
   // https://www.w3.org/TR/css-text-decor-3/#text-shadow-property
   SetPropertyDefinition(kTextShadowProperty, "text-shadow", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        KeywordValue::GetNone());
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+                        kImpactsBoxCrossReferencesNo, KeywordValue::GetNone());
 
   // https://www.w3.org/TR/css3-text/#text-transform-property
   SetPropertyDefinition(kTextTransformProperty, "text-transform", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationYes,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        KeywordValue::GetNone());
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationYes, kImpactsBoxSizesNo,
+                        kImpactsBoxCrossReferencesNo, KeywordValue::GetNone());
 
   // https://www.w3.org/TR/CSS2/visuren.html#propdef-top
   SetPropertyDefinition(kTopProperty, "top", kInheritedNo, kAnimatableNo,
-                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
-                        kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        KeywordValue::GetAuto());
 
   // https://www.w3.org/TR/css3-transforms/#transform-property
   SetPropertyDefinition(kTransformProperty, "transform", kInheritedNo,
-                        kAnimatableYes, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesYes,
-                        KeywordValue::GetNone());
+                        kAnimatableYes, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesYes, KeywordValue::GetNone());
 
   // https://www.w3.org/TR/css3-transforms/#propdef-transform-origin
   scoped_ptr<PropertyListValue::Builder> transform_origin_builder(
@@ -568,88 +617,94 @@
   transform_origin_builder->push_back(new LengthValue(0.0f, kPixelsUnit));
   scoped_refptr<PropertyListValue> transform_origin_list(
       new PropertyListValue(transform_origin_builder.Pass()));
-  SetPropertyDefinition(kTransformOriginProperty, "transform-origin",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        transform_origin_list);
+  SetPropertyDefinition(
+      kTransformOriginProperty, "transform-origin", kInheritedNo, kAnimatableNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo, transform_origin_list);
 
   // https://www.w3.org/TR/css3-transitions/#transition-delay-property
-  SetPropertyDefinition(kTransitionDelayProperty, "transition-delay",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        CreateTimeListWithZeroSeconds());
+  SetPropertyDefinition(
+      kTransitionDelayProperty, "transition-delay", kInheritedNo, kAnimatableNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo, CreateTimeListWithZeroSeconds());
 
   // https://www.w3.org/TR/css3-transitions/#transition-duration-property
   SetPropertyDefinition(kTransitionDurationProperty, "transition-duration",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         CreateTimeListWithZeroSeconds());
 
   // https://www.w3.org/TR/css3-transitions/#transition-property-property
   SetPropertyDefinition(kTransitionPropertyProperty, "transition-property",
-                        kInheritedNo, kAnimatableNo, kImpactsBoxGenerationNo,
+                        kInheritedNo, kAnimatableNo,
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
                         kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
                         CreatePropertyKeyListWithAll());
 
   // https://www.w3.org/TR/css3-transitions/#transition-timing-function-property
-  SetPropertyDefinition(kTransitionTimingFunctionProperty,
-                        "transition-timing-function", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        CreateTransitionTimingFunctionListWithEase());
+  SetPropertyDefinition(
+      kTransitionTimingFunctionProperty, "transition-timing-function",
+      kInheritedNo, kAnimatableNo, kImpactsChildDeclaredStyleNo,
+      kImpactsBoxGenerationNo, kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
+      CreateTransitionTimingFunctionListWithEase());
 
   // https://www.w3.org/TR/CSS21/visudet.html#propdef-vertical-align
-  SetPropertyDefinition(kVerticalAlignProperty, "vertical-align", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        KeywordValue::GetBaseline());
+  SetPropertyDefinition(
+      kVerticalAlignProperty, "vertical-align", kInheritedNo, kAnimatableNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo, KeywordValue::GetBaseline());
 
   // https://www.w3.org/TR/CSS21/visufx.html#propdef-visibility
-  SetPropertyDefinition(kVisibilityProperty, "visibility", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        KeywordValue::GetVisible());
+  SetPropertyDefinition(
+      kVisibilityProperty, "visibility", kInheritedYes, kAnimatableNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo, KeywordValue::GetVisible());
 
   // https://www.w3.org/TR/css3-text/#white-space-property
   SetPropertyDefinition(kWhiteSpaceProperty, "white-space", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationYes,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationYes, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetNormal());
 
   // https://www.w3.org/TR/CSS21/visudet.html#the-width-property
   SetPropertyDefinition(kWidthProperty, "width", kInheritedNo, kAnimatableNo,
-                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
-                        kImpactsBoxCrossReferencesNo, KeywordValue::GetAuto());
+                        kImpactsChildDeclaredStyleYes, kImpactsBoxGenerationNo,
+                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        KeywordValue::GetAuto());
 
   // https://www.w3.org/TR/CSS21/visuren.html#z-index
   SetPropertyDefinition(kZIndexProperty, "z-index", kInheritedNo, kAnimatableNo,
-                        kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
-                        kImpactsBoxCrossReferencesYes, KeywordValue::GetAuto());
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesYes,
+                        KeywordValue::GetAuto());
 
   // This property name can appear as a keyword for the transition-property
   // property.
   //   https://www.w3.org/TR/2013/WD-css3-transitions-20131119/#transition-property-property
   SetPropertyDefinition(kAllProperty, "all", kInheritedNo, kAnimatableNo,
-                        kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
-                        kImpactsBoxCrossReferencesNo, NULL);
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo, NULL);
 
   // This is a descriptor for @font-face at-rules.
   //   https://www.w3.org/TR/css3-fonts/#descdef-src
   SetPropertyDefinition(kSrcProperty, "src", kInheritedNo, kAnimatableNo,
-                        kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
-                        kImpactsBoxCrossReferencesNo, NULL);
+                        kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo,
+                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo, NULL);
 
   //   https://www.w3.org/TR/css3-fonts/#unicode-range-desc
-  SetPropertyDefinition(kUnicodeRangeProperty, "unicode-range", kInheritedNo,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesNo, kImpactsBoxCrossReferencesNo,
-                        new UnicodeRangeValue(0, 0x10FFFF));
+  SetPropertyDefinition(
+      kUnicodeRangeProperty, "unicode-range", kInheritedNo, kAnimatableNo,
+      kImpactsChildDeclaredStyleNo, kImpactsBoxGenerationNo, kImpactsBoxSizesNo,
+      kImpactsBoxCrossReferencesNo, new UnicodeRangeValue(0, 0x10FFFF));
 
   // This is an alias for kOverflowWrap
   //   https://www.w3.org/TR/css-text-3/#overflow-wrap
   SetPropertyDefinition(kWordWrapProperty, "word-wrap", kInheritedYes,
-                        kAnimatableNo, kImpactsBoxGenerationNo,
-                        kImpactsBoxSizesYes, kImpactsBoxCrossReferencesNo,
+                        kAnimatableNo, kImpactsChildDeclaredStyleNo,
+                        kImpactsBoxGenerationNo, kImpactsBoxSizesYes,
+                        kImpactsBoxCrossReferencesNo,
                         KeywordValue::GetNormal());
 
   // Shorthand properties.
@@ -790,6 +845,9 @@
   for (int i = 0; i < kMaxEveryPropertyKey + 1; ++i) {
     if (properties[i].animatable == kAnimatableYes) {
       animatable_properties.push_back(static_cast<PropertyKey>(i));
+      if (properties[i].inherited == kInheritedYes) {
+        inherited_animatable_properties.push_back(static_cast<PropertyKey>(i));
+      }
     }
   }
 }
@@ -842,6 +900,16 @@
   return non_trivial_global_variables.Get().properties[key].animatable;
 }
 
+ImpactsChildDeclaredStyle GetPropertyImpactsChildDeclaredStyle(
+    PropertyKey key) {
+  DCHECK(!IsShorthandProperty(key));
+  DCHECK_GT(key, kNoneProperty);
+  DCHECK_LE(key, kMaxEveryPropertyKey);
+  return non_trivial_global_variables.Get()
+      .properties[key]
+      .impacts_child_declared_style;
+}
+
 ImpactsBoxGeneration GetPropertyImpactsBoxGeneration(PropertyKey key) {
   DCHECK(!IsShorthandProperty(key));
   DCHECK_GT(key, kNoneProperty);
@@ -877,10 +945,14 @@
   return non_trivial_global_variables.Get().properties[key].longhand_properties;
 }
 
-const AnimatablePropertyList& GetAnimatableProperties() {
+const PropertyKeyVector& GetAnimatableProperties() {
   return non_trivial_global_variables.Get().animatable_properties;
 }
 
+const PropertyKeyVector& GetInheritedAnimatableProperties() {
+  return non_trivial_global_variables.Get().inherited_animatable_properties;
+}
+
 PropertyKey GetLexicographicalLonghandPropertyKey(const size_t index) {
   DCHECK_LE(
       index,
diff --git a/src/cobalt/cssom/property_definitions.h b/src/cobalt/cssom/property_definitions.h
index bbaf9a3..14a1c39 100644
--- a/src/cobalt/cssom/property_definitions.h
+++ b/src/cobalt/cssom/property_definitions.h
@@ -157,16 +157,33 @@
   kAnimatableYes,
 };
 
+// Any property that is referenced when calculating the declared property values
+// of children should have this set to true.
+// NOTE: This currently occurs within CalculateComputedStyleContext.
+enum ImpactsChildDeclaredStyle {
+  kImpactsChildDeclaredStyleNo,
+  kImpactsChildDeclaredStyleYes,
+};
+
+// Any property that is referenced during box generation should have this set to
+// true.
+// NOTE: This currently occurs within BoxGenerator.
 enum ImpactsBoxGeneration {
   kImpactsBoxGenerationNo,
   kImpactsBoxGenerationYes,
 };
 
+// Any property that is referenced when updating the size of boxes should have
+// this set to true.
+// NOTE: This currently occurs within Box::UpdateSize().
 enum ImpactsBoxSizes {
   kImpactsBoxSizesNo,
   kImpactsBoxSizesYes,
 };
 
+// Any property that is referenced when generating cross references should have
+// this set to true.
+// NOTE: This currently occurs within ContainerBox::UpdateCrossReferences().
 enum ImpactsBoxCrossReferences {
   kImpactsBoxCrossReferencesNo,
   kImpactsBoxCrossReferencesYes,
@@ -183,12 +200,14 @@
 
 Inherited GetPropertyInheritance(PropertyKey key);
 Animatable GetPropertyAnimatable(PropertyKey key);
+ImpactsChildDeclaredStyle GetPropertyImpactsChildDeclaredStyle(PropertyKey key);
 ImpactsBoxGeneration GetPropertyImpactsBoxGeneration(PropertyKey key);
 ImpactsBoxSizes GetPropertyImpactsBoxSizes(PropertyKey key);
 ImpactsBoxCrossReferences GetPropertyImpactsBoxCrossReferences(PropertyKey key);
 
-typedef std::vector<PropertyKey> AnimatablePropertyList;
-const AnimatablePropertyList& GetAnimatableProperties();
+typedef std::vector<PropertyKey> PropertyKeyVector;
+const PropertyKeyVector& GetAnimatableProperties();
+const PropertyKeyVector& GetInheritedAnimatableProperties();
 
 PropertyKey GetLexicographicalLonghandPropertyKey(const size_t index);
 
@@ -203,7 +222,6 @@
 const LonghandPropertySet& ExpandShorthandProperty(PropertyKey key);
 
 typedef std::bitset<kNumLonghandProperties> LonghandPropertiesBitset;
-typedef std::vector<PropertyKey> PropertyKeyVector;
 
 }  // namespace cssom
 }  // namespace cobalt
diff --git a/src/cobalt/debug/render_overlay.cc b/src/cobalt/debug/render_overlay.cc
index 85d03b0..5a60043 100644
--- a/src/cobalt/debug/render_overlay.cc
+++ b/src/cobalt/debug/render_overlay.cc
@@ -25,7 +25,7 @@
 RenderOverlay::RenderOverlay(
     const OnRenderTreeProducedCallback& render_tree_produced_callback)
     : render_tree_produced_callback_(render_tree_produced_callback),
-      input_layout_(NULL, NULL, base::TimeDelta()) {}
+      input_layout_(NULL, base::TimeDelta()) {}
 
 void RenderOverlay::OnRenderTreeProduced(const LayoutResults& layout_results) {
   input_layout_ = layout_results;
@@ -56,10 +56,10 @@
           new render_tree::CompositionNode(builder);
 
       render_tree_produced_callback_.Run(
-          LayoutResults(combined_tree, input_layout_.animations, layout_time));
+          LayoutResults(combined_tree, layout_time));
     } else {
-      render_tree_produced_callback_.Run(LayoutResults(
-          input_layout_.render_tree, input_layout_.animations, layout_time));
+      render_tree_produced_callback_.Run(
+          LayoutResults(input_layout_.render_tree, layout_time));
     }
   }
 }
diff --git a/src/cobalt/dom/Document.idl b/src/cobalt/dom/Document.idl
index 73fa7e6..d33334d 100644
--- a/src/cobalt/dom/Document.idl
+++ b/src/cobalt/dom/Document.idl
@@ -22,6 +22,10 @@
   readonly attribute DOMString documentURI;
   readonly attribute Element? documentElement;
 
+  // Non-standard return type, should be WindowProxy.
+  // https://www.w3.org/TR/html5/single-page.html#dom-document-defaultview
+  readonly attribute Window? defaultView;
+
   HTMLCollection getElementsByTagName(DOMString localName);
   HTMLCollection getElementsByClassName(DOMString classNames);
   [NewObject] Element createElement(DOMString localName);
diff --git a/src/cobalt/dom/HTMLVideoElement.idl b/src/cobalt/dom/HTMLVideoElement.idl
index 3793eab..7f44060 100644
--- a/src/cobalt/dom/HTMLVideoElement.idl
+++ b/src/cobalt/dom/HTMLVideoElement.idl
@@ -21,4 +21,7 @@
   attribute unsigned long height;
   readonly attribute unsigned long videoWidth;
   readonly attribute unsigned long videoHeight;
+
+  // https://www.w3.org/TR/media-source/#widl-HTMLVideoElement-getVideoPlaybackQuality-VideoPlaybackQuality
+  VideoPlaybackQuality getVideoPlaybackQuality();
 };
diff --git a/src/cobalt/dom/VideoPlaybackQuality.idl b/src/cobalt/dom/VideoPlaybackQuality.idl
new file mode 100644
index 0000000..8263a07
--- /dev/null
+++ b/src/cobalt/dom/VideoPlaybackQuality.idl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+// https://www.w3.org/TR/media-source/#idl-def-VideoPlaybackQuality
+
+interface VideoPlaybackQuality {
+  readonly attribute DOMHighResTimeStamp creationTime;
+  readonly attribute unsigned long totalVideoFrames;
+  readonly attribute unsigned long droppedVideoFrames;
+  readonly attribute unsigned long corruptedVideoFrames;
+  readonly attribute double totalFrameDelay;
+};
+
+typedef double DOMHighResTimeStamp;
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index cc586b7..0d2b543 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -53,6 +53,7 @@
 #include "cobalt/dom/node_descendants_iterator.h"
 #include "cobalt/dom/text.h"
 #include "cobalt/dom/ui_event.h"
+#include "cobalt/dom/window.h"
 
 namespace cobalt {
 namespace dom {
@@ -61,6 +62,7 @@
                    const Options& options)
     : ALLOW_THIS_IN_INITIALIZER_LIST(Node(this)),
       html_element_context_(html_element_context),
+      window_(options.window),
       implementation_(new DOMImplementation()),
       ALLOW_THIS_IN_INITIALIZER_LIST(
           style_sheets_(new cssom::StyleSheetList(this))),
@@ -81,7 +83,9 @@
       navigation_start_clock_(options.navigation_start_clock),
       ALLOW_THIS_IN_INITIALIZER_LIST(
           default_timeline_(new DocumentTimeline(this, 0))),
-      user_agent_style_sheet_(options.user_agent_style_sheet) {
+      user_agent_style_sheet_(options.user_agent_style_sheet),
+      initial_computed_style_declaration_(
+          new cssom::CSSComputedStyleDeclaration()) {
   DCHECK(options.url.is_empty() || options.url.is_valid());
 
   if (options.viewport_size) {
@@ -141,6 +145,8 @@
   return first_element_child();
 }
 
+scoped_refptr<Window> Document::default_view() const { return window_; }
+
 std::string Document::title() const {
   const char kTitleTag[] = "title";
   if (head()) {
@@ -543,14 +549,14 @@
     scoped_refptr<HTMLElement> root = html();
     if (root) {
       // First update the computed style for root element.
-      root->UpdateComputedStyle(initial_computed_style_,
-                                initial_computed_style_,
+      root->UpdateComputedStyle(initial_computed_style_declaration_,
+                                initial_computed_style_data_,
                                 style_change_event_time);
 
       // Then update the computed styles for the other elements.
-      root->UpdateComputedStyleRecursively(root->computed_style(),
-                                           root->computed_style(),
-                                           style_change_event_time, true);
+      root->UpdateComputedStyleRecursively(
+          root->css_computed_style_declaration(), root->computed_style(),
+          style_change_event_time, true);
     }
 
     is_computed_style_dirty_ = false;
@@ -589,9 +595,16 @@
 
 void Document::SetViewport(const math::Size& viewport_size) {
   viewport_size_ = viewport_size;
-  initial_computed_style_ = CreateInitialComputedStyle(*viewport_size_);
+  initial_computed_style_data_ = CreateInitialComputedStyle(*viewport_size_);
+  initial_computed_style_declaration_->SetData(initial_computed_style_data_);
+
   is_computed_style_dirty_ = true;
   is_selector_tree_dirty_ = true;
+
+  scoped_refptr<HTMLHtmlElement> current_html = html();
+  if (current_html) {
+    current_html->InvalidateComputedStylesRecursively();
+  }
 }
 
 Document::~Document() {
@@ -682,6 +695,13 @@
     keyframes_map_updater.ProcessCSSStyleSheet(user_agent_style_sheet_);
     keyframes_map_updater.ProcessStyleSheetList(style_sheets());
     are_keyframes_dirty_ = false;
+
+    // This should eventually be altered to only invalidate the tree when the
+    // the keyframes map changed.
+    scoped_refptr<HTMLHtmlElement> current_html = html();
+    if (current_html) {
+      current_html->InvalidateComputedStylesRecursively();
+    }
   }
 }
 
diff --git a/src/cobalt/dom/document.h b/src/cobalt/dom/document.h
index a312b1a..4d45315 100644
--- a/src/cobalt/dom/document.h
+++ b/src/cobalt/dom/document.h
@@ -27,7 +27,7 @@
 #include "base/optional.h"
 #include "base/string_piece.h"
 #include "cobalt/base/clock.h"
-#include "cobalt/cssom/css_computed_style_data.h"
+#include "cobalt/cssom/css_computed_style_declaration.h"
 #include "cobalt/cssom/css_keyframes_rule.h"
 #include "cobalt/cssom/css_style_sheet.h"
 #include "cobalt/cssom/mutation_observer.h"
@@ -61,6 +61,7 @@
 class HTMLScriptElement;
 class Location;
 class Text;
+class Window;
 
 class DocumentObserver {
  public:
@@ -88,9 +89,11 @@
     Options() : cookie_jar(NULL), csp_enforcement_mode(kCspEnforcementEnable) {}
     explicit Options(const GURL& url_value)
         : url(url_value),
+          window(NULL),
           cookie_jar(NULL),
           csp_enforcement_mode(kCspEnforcementEnable) {}
-    Options(const GURL& url_value, const base::Closure& hashchange_callback,
+    Options(const GURL& url_value, Window* window,
+            const base::Closure& hashchange_callback,
             const scoped_refptr<base::Clock>& navigation_start_clock_value,
             const base::Callback<void(const GURL&)>& navigation_callback,
             const scoped_refptr<cssom::CSSStyleSheet> user_agent_style_sheet,
@@ -102,6 +105,7 @@
             const base::Closure& csp_policy_changed_callback,
             int csp_insecure_allowed_token = 0)
         : url(url_value),
+          window(window),
           hashchange_callback(hashchange_callback),
           navigation_start_clock(navigation_start_clock_value),
           navigation_callback(navigation_callback),
@@ -115,6 +119,7 @@
           csp_insecure_allowed_token(csp_insecure_allowed_token) {}
 
     GURL url;
+    Window* window;
     base::Closure hashchange_callback;
     scoped_refptr<base::Clock> navigation_start_clock;
     base::Callback<void(const GURL&)> navigation_callback;
@@ -145,6 +150,8 @@
   scoped_refptr<Element> document_element() const;
   std::string title() const;
 
+  scoped_refptr<Window> default_view() const;
+
   scoped_refptr<HTMLCollection> GetElementsByTagName(
       const std::string& local_name) const;
   scoped_refptr<HTMLCollection> GetElementsByClassName(
@@ -298,9 +305,13 @@
   math::Size viewport_size() { return viewport_size_.value_or(math::Size()); }
   void SetViewport(const math::Size& viewport_size);
 
-  const scoped_refptr<cssom::CSSComputedStyleData>& initial_computed_style()
-      const {
-    return initial_computed_style_;
+  const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+  initial_computed_style_declaration() const {
+    return initial_computed_style_declaration_;
+  }
+  const scoped_refptr<cssom::CSSComputedStyleData>&
+  initial_computed_style_data() const {
+    return initial_computed_style_data_;
   }
 
   void NotifyUrlChanged(const GURL& url);
@@ -334,6 +345,9 @@
 
   // Reference to HTML element context.
   HTMLElementContext* const html_element_context_;
+  // Reference to the Window object. We cannot hold a strong reference,
+  // otherwise we create a reference loop.
+  Window* window_;
   // Associated DOM implementation object.
   scoped_refptr<DOMImplementation> implementation_;
   // Associated location object.
@@ -387,7 +401,9 @@
 
   // Computed style of the initial containing block, width and height come from
   // the viewport size.
-  scoped_refptr<cssom::CSSComputedStyleData> initial_computed_style_;
+  scoped_refptr<cssom::CSSComputedStyleDeclaration>
+      initial_computed_style_declaration_;
+  scoped_refptr<cssom::CSSComputedStyleData> initial_computed_style_data_;
 };
 
 }  // namespace dom
diff --git a/src/cobalt/dom/dom.gyp b/src/cobalt/dom/dom.gyp
index d171fd3..5438684 100644
--- a/src/cobalt/dom/dom.gyp
+++ b/src/cobalt/dom/dom.gyp
@@ -64,8 +64,6 @@
         'document_type.h',
         'dom_animatable.cc',
         'dom_animatable.h',
-        'dom_exception.cc',
-        'dom_exception.h',
         'dom_implementation.cc',
         'dom_implementation.h',
         'dom_parser.cc',
@@ -248,6 +246,7 @@
         '<(DEPTH)/cobalt/base/base.gyp:base',
         '<(DEPTH)/cobalt/csp/csp.gyp:csp',
         '<(DEPTH)/cobalt/cssom/cssom.gyp:cssom',
+        '<(DEPTH)/cobalt/dom/dom_exception.gyp:dom_exception',
         '<(DEPTH)/cobalt/loader/loader.gyp:loader',
         '<(DEPTH)/cobalt/media/media.gyp:media',
         # Interface layer to avoid directly depending on network.
diff --git a/src/cobalt/dom/dom_exception.gyp b/src/cobalt/dom/dom_exception.gyp
new file mode 100644
index 0000000..ba6dcf6
--- /dev/null
+++ b/src/cobalt/dom/dom_exception.gyp
@@ -0,0 +1,32 @@
+# 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': {
+    'cobalt_code': 1,
+  },
+  'targets': [
+    {
+      'target_name': 'dom_exception',
+      'type': 'static_library',
+      'sources': [
+        'dom_exception.cc',
+        'dom_exception.h',
+      ],
+      'dependencies': [
+        '<(DEPTH)/cobalt/script/script.gyp:script',
+      ],
+    },
+  ],
+}
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc
index 29cbf3e..f63dbbf 100644
--- a/src/cobalt/dom/html_element.cc
+++ b/src/cobalt/dom/html_element.cc
@@ -77,18 +77,22 @@
 
 struct NonTrivialStaticFields {
   NonTrivialStaticFields() {
+    cssom::PropertyKeyVector computed_style_invalidation_properties;
     cssom::PropertyKeyVector layout_box_invalidation_properties;
     cssom::PropertyKeyVector size_invalidation_properties;
     cssom::PropertyKeyVector cross_references_invalidation_properties;
 
     for (int i = 0; i <= cssom::kMaxLonghandPropertyKey; ++i) {
       cssom::PropertyKey property_key = static_cast<cssom::PropertyKey>(i);
-      // TODO: Only invalidate layout boxes when a property that is used
-      // for box generation is modified. We currently have to also invalidate
-      // when any inheritable property is modified, because AnonymousBlockBox
-      // and TextBox use GetComputedStyleOfAnonymousBox() to store a copy of
-      // them that won't automatically get updated when the style() in a
-      // CSSComputedStyleDeclaration gets updated.
+
+      if (cssom::GetPropertyImpactsChildDeclaredStyle(property_key) ==
+          cssom::kImpactsChildDeclaredStyleYes) {
+        computed_style_invalidation_properties.push_back(property_key);
+      }
+
+      // TODO: Revisit inherited property handling. Currently, all boxes are
+      // invalidated if an inherited property changes, but now that inherited
+      // properties dynamically update, this is likely no longer necessary.
       if (cssom::GetPropertyInheritance(property_key) == cssom::kInheritedYes ||
           cssom::GetPropertyImpactsBoxGeneration(property_key) ==
               cssom::kImpactsBoxGenerationYes) {
@@ -105,6 +109,9 @@
       }
     }
 
+    computed_style_invalidation_property_checker =
+        cssom::CSSComputedStyleData::PropertySetMatcher(
+            computed_style_invalidation_properties);
     layout_box_invalidation_property_checker =
         cssom::CSSComputedStyleData::PropertySetMatcher(
             layout_box_invalidation_properties);
@@ -117,6 +124,8 @@
   }
 
   cssom::CSSComputedStyleData::PropertySetMatcher
+      computed_style_invalidation_property_checker;
+  cssom::CSSComputedStyleData::PropertySetMatcher
       layout_box_invalidation_property_checker;
   cssom::CSSComputedStyleData::PropertySetMatcher
       size_invalidation_property_checker;
@@ -570,9 +579,13 @@
   }
 
   matching_rules_valid_ = false;
-  computed_style_valid_ = false;
 
-  matching_rules_.clear();
+  // Move |matching_rules_| into |old_matching_rules_|. This is used for
+  // determining whether or not the matching rules actually changed when they
+  // are updated.
+  old_matching_rules_.swap(matching_rules_);
+
+  matching_rules_->clear();
   rule_matching_state_.matching_nodes.clear();
   rule_matching_state_.descendant_potential_nodes.clear();
   rule_matching_state_.following_sibling_potential_nodes.clear();
@@ -603,17 +616,28 @@
   }
 }
 
+void HTMLElement::InvalidateComputedStylesRecursively() {
+  computed_style_valid_ = false;
+
+  for (Element* element = first_element_child(); element;
+       element = element->next_element_sibling()) {
+    HTMLElement* html_element = element->AsHTMLElement();
+    DCHECK(html_element);
+    html_element->InvalidateComputedStylesRecursively();
+  }
+}
+
 void HTMLElement::UpdateComputedStyleRecursively(
-    const scoped_refptr<const cssom::CSSComputedStyleData>&
-        parent_computed_style,
+    const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+        parent_computed_style_declaration,
     const scoped_refptr<const cssom::CSSComputedStyleData>& root_computed_style,
     const base::TimeDelta& style_change_event_time, bool ancestors_were_valid) {
   // Update computed style for this element.
-  bool is_valid = ancestors_were_valid && computed_style_valid_;
+  bool is_valid =
+      ancestors_were_valid && matching_rules_valid_ && computed_style_valid_;
   if (!is_valid) {
-    UpdateComputedStyle(parent_computed_style, root_computed_style,
+    UpdateComputedStyle(parent_computed_style_declaration, root_computed_style,
                         style_change_event_time);
-    computed_style_valid_ = true;
   }
 
   // Do not update computed style for descendants of "display: none" elements,
@@ -630,8 +654,8 @@
     HTMLElement* html_element = element->AsHTMLElement();
     DCHECK(html_element);
     html_element->UpdateComputedStyleRecursively(
-        computed_style(), root_computed_style, style_change_event_time,
-        is_valid);
+        css_computed_style_declaration(), root_computed_style,
+        style_change_event_time, is_valid);
   }
 }
 
@@ -657,6 +681,12 @@
   }
 }
 
+void HTMLElement::InvalidateRenderTreeNodesFromNode() {
+  if (layout_boxes_) {
+    layout_boxes_->InvalidateRenderTreeNodes();
+  }
+}
+
 HTMLElement::HTMLElement(Document* document, base::Token tag_name)
     : Element(document, tag_name),
       directionality_(kNoExplicitDirectionality),
@@ -670,6 +700,8 @@
       ALLOW_THIS_IN_INITIALIZER_LIST(
           animations_adapter_(new DOMAnimatable(this))),
       css_animations_(&animations_adapter_),
+      old_matching_rules_(new cssom::RulesWithCascadePrecedence()),
+      matching_rules_(new cssom::RulesWithCascadePrecedence()),
       matching_rules_valid_(false),
       dom_stat_tracker_(document->html_element_context()->dom_stat_tracker()) {
   css_computed_style_declaration_->set_animations(animations());
@@ -729,16 +761,16 @@
     cssom::RulesWithCascadePrecedence* matching_rules,
     cssom::GURLMap* property_key_to_base_url_map,
     const scoped_refptr<const cssom::CSSDeclaredStyleData>& inline_style,
-    const scoped_refptr<const cssom::CSSComputedStyleData>&
-        parent_computed_style,
+    const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+        parent_computed_style_declaration,
     const scoped_refptr<const cssom::CSSComputedStyleData>& root_computed_style,
     const math::Size& viewport_size,
     const base::TimeDelta& style_change_event_time,
-    cssom::TransitionSet* css_transitions,
     const scoped_refptr<const cssom::CSSComputedStyleData>&
         previous_computed_style,
-    cssom::AnimationSet* css_animations,
-    const cssom::CSSKeyframesRule::NameMap& keyframes_map) {
+    cssom::TransitionSet* css_transitions, cssom::AnimationSet* css_animations,
+    const cssom::CSSKeyframesRule::NameMap& keyframes_map,
+    bool* animations_modified) {
   // Select the winning value for each property by performing the cascade,
   // that is, apply values from matching rules on top of inline style, taking
   // into account rule specificity and location in the source file, as well as
@@ -754,9 +786,9 @@
   // properties, like "font-family", computed value is the same as specified
   // value. Declarations that cannot be absolutized easily, like "width: auto;",
   // will be resolved during layout.
-  cssom::PromoteToComputedStyle(computed_style, parent_computed_style,
-                                root_computed_style, viewport_size,
-                                property_key_to_base_url_map);
+  cssom::PromoteToComputedStyle(
+      computed_style, parent_computed_style_declaration, root_computed_style,
+      viewport_size, property_key_to_base_url_map);
 
   if (previous_computed_style) {
     // Now that we have updated our computed style, compare it to the previous
@@ -764,13 +796,39 @@
     css_transitions->UpdateTransitions(
         style_change_event_time, *previous_computed_style, *computed_style);
   }
-  // Update the set of currently running animations.
-  css_animations->Update(style_change_event_time, *computed_style,
-                         keyframes_map);
+  // Update the set of currently running animations and track whether or not the
+  // animations changed.
+  *animations_modified = css_animations->Update(style_change_event_time,
+                                                *computed_style, keyframes_map);
 
   return computed_style;
 }
 
+// Flags tracking which cached values must be invalidated.
+struct UpdateComputedStyleInvalidationFlags {
+  UpdateComputedStyleInvalidationFlags()
+      : invalidate_descendant_computed_styles(false),
+        invalidate_layout_boxes(false),
+        invalidate_sizes(false),
+        invalidate_cross_references(false),
+        invalidate_render_tree_nodes(false) {}
+
+  bool invalidate_descendant_computed_styles;
+  bool invalidate_layout_boxes;
+  bool invalidate_sizes;
+  bool invalidate_cross_references;
+  bool invalidate_render_tree_nodes;
+};
+
+bool NewComputedStyleInvalidatesDescendantComputedStyles(
+    const scoped_refptr<const cssom::CSSComputedStyleData>& old_computed_style,
+    const scoped_refptr<cssom::CSSComputedStyleData>& new_computed_style) {
+  return !non_trivial_static_fields.Get()
+              .computed_style_invalidation_property_checker
+              .DoDeclaredPropertiesMatch(old_computed_style,
+                                         new_computed_style);
+}
+
 bool NewComputedStyleInvalidatesLayoutBoxes(
     const scoped_refptr<const cssom::CSSComputedStyleData>& old_computed_style,
     const scoped_refptr<cssom::CSSComputedStyleData>& new_computed_style) {
@@ -797,24 +855,82 @@
                                          new_computed_style);
 }
 
+void UpdateInvalidationFlagsForNewComputedStyle(
+    const scoped_refptr<const cssom::CSSComputedStyleData>& old_computed_style,
+    const scoped_refptr<cssom::CSSComputedStyleData>& new_computed_style,
+    bool animations_modified, UpdateComputedStyleInvalidationFlags* flags) {
+  if (old_computed_style) {
+    if (!flags->invalidate_descendant_computed_styles &&
+        NewComputedStyleInvalidatesDescendantComputedStyles(
+            old_computed_style, new_computed_style)) {
+      flags->invalidate_descendant_computed_styles = true;
+      flags->invalidate_layout_boxes = true;
+    } else if (!flags->invalidate_layout_boxes) {
+      if (NewComputedStyleInvalidatesLayoutBoxes(old_computed_style,
+                                                 new_computed_style)) {
+        flags->invalidate_layout_boxes = true;
+      } else {
+        if (!flags->invalidate_sizes &&
+            NewComputedStyleInvalidatesSizes(old_computed_style,
+                                             new_computed_style)) {
+          flags->invalidate_sizes = true;
+          flags->invalidate_render_tree_nodes = true;
+        }
+        if (!flags->invalidate_cross_references &&
+            NewComputedStyleInvalidatesCrossReferences(old_computed_style,
+                                                       new_computed_style)) {
+          flags->invalidate_cross_references = true;
+          flags->invalidate_render_tree_nodes = true;
+        }
+
+        flags->invalidate_render_tree_nodes =
+            flags->invalidate_render_tree_nodes || animations_modified ||
+            !new_computed_style->DoDeclaredPropertiesMatch(old_computed_style);
+      }
+    }
+  }
+}
+
 }  // namespace
 
 void HTMLElement::UpdateComputedStyle(
-    const scoped_refptr<const cssom::CSSComputedStyleData>&
-        parent_computed_style,
+    const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+        parent_computed_style_declaration,
     const scoped_refptr<const cssom::CSSComputedStyleData>& root_computed_style,
     const base::TimeDelta& style_change_event_time) {
   Document* document = node_document();
   DCHECK(document) << "Element should be attached to document in order to "
                       "participate in layout.";
 
+  // If there is no previous computed style, there should also be no layout
+  // boxes.
+  DCHECK(computed_style() || NULL == layout_boxes());
+
   dom_stat_tracker_->OnUpdateComputedStyle();
 
+  // The computed style must be generated if either the computed style is
+  // invalid or no computed style has been created yet.
+  bool generate_computed_style = !computed_style_valid_ || !computed_style();
+
   // Update matching rules if necessary.
   if (!matching_rules_valid_) {
     dom_stat_tracker_->OnUpdateMatchingRules();
     UpdateMatchingRules(this);
     matching_rules_valid_ = true;
+
+    // Check for whether the matching rules have changed. If they have, then a
+    // new computed style must be generated from them.
+    if (!generate_computed_style && *old_matching_rules_ != *matching_rules_) {
+      generate_computed_style = true;
+    }
+  }
+
+  // If any declared properties inherited from the parent are no longer valid,
+  // then a new computed style must be generated with the updated inherited
+  // values.
+  if (!generate_computed_style &&
+      !computed_style()->AreDeclaredPropertiesInheritedFromParentValid()) {
+    generate_computed_style = true;
   }
 
   // TODO: It maybe helpful to generalize this mapping framework in the
@@ -824,95 +940,88 @@
   property_key_to_base_url_map[cssom::kBackgroundImageProperty] =
       document->url_as_gurl();
 
-  scoped_refptr<cssom::CSSComputedStyleData> new_computed_style =
-      PromoteMatchingRulesToComputedStyle(
-          matching_rules(), &property_key_to_base_url_map, style_->data(),
-          parent_computed_style, root_computed_style, document->viewport_size(),
-          style_change_event_time, &css_transitions_, computed_style(),
-          &css_animations_, document->keyframes_map());
+  // Flags tracking which cached values must be invalidated.
+  UpdateComputedStyleInvalidationFlags invalidation_flags;
 
-  // If there is no previous computed style, there should also be no layout
-  // boxes, and nothing has to be invalidated.
-  bool invalidate_layout_boxes = false;
-  bool invalidate_sizes = false;
-  bool invalidate_cross_references = false;
+  if (generate_computed_style) {
+    bool animations_modified = false;
 
-  DCHECK(computed_style() || NULL == layout_boxes());
-  if (computed_style()) {
-    if (NewComputedStyleInvalidatesLayoutBoxes(computed_style(),
-                                               new_computed_style)) {
-      invalidate_layout_boxes = true;
-    } else {
-      if (NewComputedStyleInvalidatesSizes(computed_style(),
-                                           new_computed_style)) {
-        invalidate_sizes = true;
-      }
-      if (NewComputedStyleInvalidatesCrossReferences(computed_style(),
-                                                     new_computed_style)) {
-        invalidate_cross_references = true;
-      }
-    }
+    scoped_refptr<cssom::CSSComputedStyleData> new_computed_style =
+        PromoteMatchingRulesToComputedStyle(
+            matching_rules(), &property_key_to_base_url_map, style_->data(),
+            parent_computed_style_declaration, root_computed_style,
+            document->viewport_size(), style_change_event_time,
+            computed_style(), &css_transitions_, &css_animations_,
+            document->keyframes_map(), &animations_modified);
+
+    UpdateInvalidationFlagsForNewComputedStyle(
+        computed_style(), new_computed_style, animations_modified,
+        &invalidation_flags);
+
+    css_computed_style_declaration_->SetData(new_computed_style);
+
+    // Update cached background images after resolving the urls in
+    // background_image CSS property of the computed style, so we have all the
+    // information to get the cached background images.
+    UpdateCachedBackgroundImagesFromComputedStyle();
+  } else {
+    // Update the inherited data if a new style was not generated. The ancestor
+    // data with inherited properties may have changed.
+    css_computed_style_declaration_->UpdateInheritedData();
   }
 
-  set_computed_style(new_computed_style);
-
-  // Update cached background images after resolving the urls in
-  // background_image CSS property of the computed style, so we have all the
-  // information to get the cached background images.
-  UpdateCachedBackgroundImagesFromComputedStyle();
+  // NOTE: Currently, pseudo elements computed styles are always generated. If
+  // this becomes a performance bottleneck, change the logic so that it only
+  // occurs when needed.
 
   // Promote the matching rules for all known pseudo elements.
   for (int pseudo_element_type = 0; pseudo_element_type < kMaxPseudoElementType;
        ++pseudo_element_type) {
     if (pseudo_elements_[pseudo_element_type]) {
+      bool animations_modified = false;
+
       scoped_refptr<cssom::CSSComputedStyleData> pseudo_element_computed_style =
           PromoteMatchingRulesToComputedStyle(
               pseudo_elements_[pseudo_element_type]->matching_rules(),
-              &property_key_to_base_url_map, style_->data(), computed_style(),
-              root_computed_style, document->viewport_size(),
-              style_change_event_time,
-              pseudo_elements_[pseudo_element_type]->css_transitions(),
+              &property_key_to_base_url_map, style_->data(),
+              css_computed_style_declaration(), root_computed_style,
+              document->viewport_size(), style_change_event_time,
               pseudo_elements_[pseudo_element_type]->computed_style(),
+              pseudo_elements_[pseudo_element_type]->css_transitions(),
               pseudo_elements_[pseudo_element_type]->css_animations(),
-              document->keyframes_map());
+              document->keyframes_map(), &animations_modified);
 
-      if (!invalidate_layout_boxes &&
-          pseudo_elements_[pseudo_element_type]->computed_style()) {
-        if (NewComputedStyleInvalidatesLayoutBoxes(
-                pseudo_elements_[pseudo_element_type]->computed_style(),
-                pseudo_element_computed_style)) {
-          invalidate_layout_boxes = true;
-        } else {
-          if (!invalidate_sizes &&
-              NewComputedStyleInvalidatesSizes(
-                  pseudo_elements_[pseudo_element_type]->computed_style(),
-                  pseudo_element_computed_style)) {
-            invalidate_sizes = true;
-          }
-          if (!invalidate_cross_references &&
-              NewComputedStyleInvalidatesCrossReferences(
-                  pseudo_elements_[pseudo_element_type]->computed_style(),
-                  pseudo_element_computed_style)) {
-            invalidate_cross_references = true;
-          }
-        }
-      }
-      pseudo_elements_[pseudo_element_type]->set_computed_style(
-          pseudo_element_computed_style);
+      UpdateInvalidationFlagsForNewComputedStyle(
+          pseudo_elements_[pseudo_element_type]->computed_style(),
+          pseudo_element_computed_style, animations_modified,
+          &invalidation_flags);
+
+      pseudo_elements_[pseudo_element_type]
+          ->css_computed_style_declaration()
+          ->SetData(pseudo_element_computed_style);
     }
   }
 
-  if (invalidate_layout_boxes) {
+  if (invalidation_flags.invalidate_descendant_computed_styles) {
+    InvalidateComputedStylesRecursively();
+  }
+
+  if (invalidation_flags.invalidate_layout_boxes) {
     InvalidateLayoutBoxesFromNodeAndAncestors();
     InvalidateLayoutBoxesFromNodeAndDescendants();
   } else {
-    if (invalidate_sizes) {
+    if (invalidation_flags.invalidate_sizes) {
       InvalidateLayoutBoxSizesFromNode();
     }
-    if (invalidate_cross_references) {
+    if (invalidation_flags.invalidate_cross_references) {
       InvalidateLayoutBoxCrossReferencesFromNode();
     }
+    if (invalidation_flags.invalidate_render_tree_nodes) {
+      InvalidateRenderTreeNodesFromNode();
+    }
   }
+
+  computed_style_valid_ = true;
 }
 
 void HTMLElement::UpdateCachedBackgroundImagesFromComputedStyle() {
diff --git a/src/cobalt/dom/html_element.h b/src/cobalt/dom/html_element.h
index eb6995f..11837a8 100644
--- a/src/cobalt/dom/html_element.h
+++ b/src/cobalt/dom/html_element.h
@@ -178,7 +178,7 @@
   //
   // Returns the cached matching rules of this element.
   cssom::RulesWithCascadePrecedence* matching_rules() {
-    return &matching_rules_;
+    return matching_rules_.get();
   }
   // Returns the rule matching state of this element.
   RuleMatchingState* rule_matching_state() { return &rule_matching_state_; }
@@ -199,13 +199,12 @@
       const {
     return css_computed_style_declaration_->data();
   }
-  void set_computed_style(
-      const scoped_refptr<cssom::CSSComputedStyleData>& computed_style) {
-    css_computed_style_declaration_->set_data(computed_style);
-  }
+
+  // Invalidates the cached computed style of this element and its descendants.
+  void InvalidateComputedStylesRecursively();
   // Updates the cached computed style of this element and its descendants.
   void UpdateComputedStyleRecursively(
-      const scoped_refptr<const cssom::CSSComputedStyleData>&
+      const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
           parent_computed_style,
       const scoped_refptr<const cssom::CSSComputedStyleData>&
           root_computed_style,
@@ -213,8 +212,8 @@
       bool ancestors_were_valid);
   // Updates the cached computed style of this element.
   void UpdateComputedStyle(
-      const scoped_refptr<const cssom::CSSComputedStyleData>&
-          parent_computed_style,
+      const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
+          parent_computed_style_declaration,
       const scoped_refptr<const cssom::CSSComputedStyleData>&
           root_computed_style,
       const base::TimeDelta& style_change_event_time);
@@ -233,6 +232,7 @@
   void InvalidateLayoutBoxesFromNodeAndDescendants() OVERRIDE;
   void InvalidateLayoutBoxSizesFromNode() OVERRIDE;
   void InvalidateLayoutBoxCrossReferencesFromNode() OVERRIDE;
+  void InvalidateRenderTreeNodesFromNode() OVERRIDE;
 
   // Determines whether this element is focusable.
   bool IsFocusable() const { return HasAttribute("tabindex"); }
@@ -313,7 +313,8 @@
   cssom::AnimationSet css_animations_;
 
   // The following fields are used in rule matching.
-  cssom::RulesWithCascadePrecedence matching_rules_;
+  scoped_ptr<cssom::RulesWithCascadePrecedence> old_matching_rules_;
+  scoped_ptr<cssom::RulesWithCascadePrecedence> matching_rules_;
   RuleMatchingState rule_matching_state_;
 
   // This contains information about the boxes generated from the element.
diff --git a/src/cobalt/dom/html_element_test.cc b/src/cobalt/dom/html_element_test.cc
index ce2a589..1e8bceb 100644
--- a/src/cobalt/dom/html_element_test.cc
+++ b/src/cobalt/dom/html_element_test.cc
@@ -86,6 +86,7 @@
 
   MOCK_METHOD0(InvalidateSizes, void());
   MOCK_METHOD0(InvalidateCrossReferences, void());
+  MOCK_METHOD0(InvalidateRenderTreeNodes, void());
 };
 
 // Takes the fist child of the given element repeatedly to the given depth.
@@ -136,7 +137,7 @@
         document_->CreateElement(*null_terminated_element_names)
             ->AsHTMLElement());
     DCHECK(child_html_element);
-    child_html_element->set_computed_style(
+    child_html_element->css_computed_style_declaration()->SetData(
         make_scoped_refptr(new cssom::CSSComputedStyleData()));
 
     if (parent_html_element) {
@@ -442,7 +443,8 @@
       make_scoped_refptr(new cssom::CSSComputedStyleData());
   computed_style_relative->set_position(cssom::KeywordValue::GetRelative());
   GetFirstChildAtDepth(root_html_element, 2)
-      ->set_computed_style(computed_style_relative);
+      ->css_computed_style_declaration()
+      ->SetData(computed_style_relative);
 
   // Return ancestor if it is the HTML body element.
   EXPECT_EQ(GetFirstChildAtDepth(root_html_element, 2)->offset_parent(),
@@ -454,7 +456,8 @@
       make_scoped_refptr(new cssom::CSSComputedStyleData());
   computed_style_fixed->set_position(cssom::KeywordValue::GetFixed());
   GetFirstChildAtDepth(root_html_element, 3)
-      ->set_computed_style(computed_style_fixed);
+      ->css_computed_style_declaration()
+      ->SetData(computed_style_fixed);
   EXPECT_FALSE(GetFirstChildAtDepth(root_html_element, 3)->offset_parent());
 
   // Return ancestor if its computed value of the 'position' property is not
diff --git a/src/cobalt/dom/html_video_element.cc b/src/cobalt/dom/html_video_element.cc
index b7e4751..89d0f1e 100644
--- a/src/cobalt/dom/html_video_element.cc
+++ b/src/cobalt/dom/html_video_element.cc
@@ -71,6 +71,17 @@
   return static_cast<uint32>(player()->GetNaturalSize().height());
 }
 
+scoped_refptr<VideoPlaybackQuality> HTMLVideoElement::GetVideoPlaybackQuality()
+    const {
+  // TODO: Provide all attributes with valid values.
+  return new VideoPlaybackQuality(
+      0.,   // creation_time
+      player() ? static_cast<uint32>(player()->GetDecodedFrameCount()) : 0,
+      player() ? static_cast<uint32>(player()->GetDroppedFrameCount()) : 0,
+      0,    // corrupted_video_frames
+      0.);  // total_frame_delay
+}
+
 scoped_refptr<ShellVideoFrameProvider>
 HTMLVideoElement::GetVideoFrameProvider() {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/src/cobalt/dom/html_video_element.h b/src/cobalt/dom/html_video_element.h
index 0f83f04..2ac5c3f 100644
--- a/src/cobalt/dom/html_video_element.h
+++ b/src/cobalt/dom/html_video_element.h
@@ -20,6 +20,7 @@
 #include <string>
 
 #include "cobalt/dom/html_media_element.h"
+#include "cobalt/dom/video_playback_quality.h"
 #include "media/base/shell_video_frame_provider.h"
 
 namespace cobalt {
@@ -43,6 +44,7 @@
   void set_height(uint32 height);
   uint32 video_width() const;
   uint32 video_height() const;
+  scoped_refptr<VideoPlaybackQuality> GetVideoPlaybackQuality() const;
 
   // Custom, not in any spec
   //
diff --git a/src/cobalt/dom/layout_boxes.h b/src/cobalt/dom/layout_boxes.h
index 350a7cc..98eccce 100644
--- a/src/cobalt/dom/layout_boxes.h
+++ b/src/cobalt/dom/layout_boxes.h
@@ -81,6 +81,8 @@
   // Invalidate the cross references, which relates to both positioned children
   // of containing blocks and z-index children of stacking contexts.
   virtual void InvalidateCrossReferences() = 0;
+  // Invalidate the layout box's render tree nodes.
+  virtual void InvalidateRenderTreeNodes() = 0;
 
  protected:
   LayoutBoxes() {}
diff --git a/src/cobalt/dom/node.h b/src/cobalt/dom/node.h
index ceee672..0b2ca54 100644
--- a/src/cobalt/dom/node.h
+++ b/src/cobalt/dom/node.h
@@ -239,6 +239,8 @@
   virtual void InvalidateLayoutBoxSizesFromNode() {}
   // Invalidate the cross references within the layout boxes of this node.
   virtual void InvalidateLayoutBoxCrossReferencesFromNode() {}
+  // Invalidate the render tree nodes within the layout boxes of this node.
+  virtual void InvalidateRenderTreeNodesFromNode() {}
 
   // Triggers a generation update in this node and all its ancestor nodes.
   void UpdateGenerationForNodeAndAncestors();
diff --git a/src/cobalt/dom/pseudo_element.h b/src/cobalt/dom/pseudo_element.h
index 0531421..18e94d7 100644
--- a/src/cobalt/dom/pseudo_element.h
+++ b/src/cobalt/dom/pseudo_element.h
@@ -58,10 +58,6 @@
   scoped_refptr<const cssom::CSSComputedStyleData> computed_style() const {
     return css_computed_style_declaration_->data();
   }
-  void set_computed_style(
-      const scoped_refptr<const cssom::CSSComputedStyleData>& computed_style) {
-    css_computed_style_declaration_->set_data(computed_style);
-  }
 
   cssom::RulesWithCascadePrecedence* matching_rules() {
     return &matching_rules_;
diff --git a/src/cobalt/dom/video_playback_quality.h b/src/cobalt/dom/video_playback_quality.h
new file mode 100644
index 0000000..e5e88e3
--- /dev/null
+++ b/src/cobalt/dom/video_playback_quality.h
@@ -0,0 +1,61 @@
+/*
+ * 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_DOM_VIDEO_PLAYBACK_QUALITY_H_
+#define COBALT_DOM_VIDEO_PLAYBACK_QUALITY_H_
+
+#include "base/basictypes.h"
+#include "cobalt/script/wrappable.h"
+
+namespace cobalt {
+namespace dom {
+
+// The VideoPlaybackQuality interface exposes data to describe the video
+// playback quality.
+//   https://www.w3.org/TR/media-source/#idl-def-VideoPlaybackQuality
+class VideoPlaybackQuality : public script::Wrappable {
+ public:
+  VideoPlaybackQuality(double creation_time, uint32 total_video_frames,
+                       uint32 dropped_video_frames,
+                       uint32 corrupted_video_frames, double total_frame_delay)
+      : creation_time_(creation_time),
+        total_video_frames_(total_video_frames),
+        dropped_video_frames_(dropped_video_frames),
+        corrupted_video_frames_(corrupted_video_frames),
+        total_frame_delay_(total_frame_delay) {}
+
+  // Web API: VideoPlaybackQuality
+  //
+  double creation_time() const { return creation_time_; }
+  uint32 total_video_frames() const { return total_video_frames_; }
+  uint32 dropped_video_frames() const { return dropped_video_frames_; }
+  uint32 corrupted_video_frames() const { return corrupted_video_frames_; }
+  double total_frame_delay() const { return total_frame_delay_; }
+
+  DEFINE_WRAPPABLE_TYPE(VideoPlaybackQuality);
+
+ private:
+  double creation_time_;
+  uint32 total_video_frames_;
+  uint32 dropped_video_frames_;
+  uint32 corrupted_video_frames_;
+  double total_frame_delay_;
+};
+
+}  // namespace dom
+}  // namespace cobalt
+
+#endif  // COBALT_DOM_VIDEO_PLAYBACK_QUALITY_H_
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index e1f7bce..cdab450 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -90,7 +90,7 @@
       ALLOW_THIS_IN_INITIALIZER_LIST(document_(new Document(
           html_element_context_.get(),
           Document::Options(
-              url,
+              url, this,
               base::Bind(&Window::FireHashChangeEvent, base::Unretained(this)),
               performance_->timing()->GetNavigationStartClock(),
               navigation_callback, ParseUserAgentStyleSheet(css_parser),
diff --git a/src/cobalt/dom/window_timers.cc b/src/cobalt/dom/window_timers.cc
index 04e58b8..df784cd 100644
--- a/src/cobalt/dom/window_timers.cc
+++ b/src/cobalt/dom/window_timers.cc
@@ -73,7 +73,10 @@
 void WindowTimers::RunTimerCallback(int handle) {
   Timers::iterator timer = timers_.find(handle);
   DCHECK(timer != timers_.end());
-  timer->second->callback_reference().value().Run();
+  // Keep a |TimerInfo| reference, so it won't be released when running the
+  // callback.
+  scoped_refptr<TimerInfo> timer_info = timer->second;
+  timer_info->callback_reference().value().Run();
   // After running the callback, double check whether the timer is still there
   // since it might be deleted inside the callback.
   timer = timers_.find(handle);
diff --git a/src/cobalt/layout/anonymous_block_box.cc b/src/cobalt/layout/anonymous_block_box.cc
index b20e597..281cc70 100644
--- a/src/cobalt/layout/anonymous_block_box.cc
+++ b/src/cobalt/layout/anonymous_block_box.cc
@@ -62,11 +62,8 @@
 }
 
 void AnonymousBlockBox::RenderAndAnimateContent(
-    render_tree::CompositionNode::Builder* border_node_builder,
-    render_tree::animations::NodeAnimationsMap::Builder*
-        node_animations_map_builder) const {
-  ContainerBox::RenderAndAnimateContent(border_node_builder,
-                                        node_animations_map_builder);
+    render_tree::CompositionNode::Builder* border_node_builder) const {
+  ContainerBox::RenderAndAnimateContent(border_node_builder);
 
   if (computed_style()->visibility() != cssom::KeywordValue::GetVisible()) {
     return;
@@ -125,24 +122,20 @@
 
 scoped_ptr<FormattingContext> AnonymousBlockBox::UpdateRectOfInFlowChildBoxes(
     const LayoutParams& child_layout_params) {
-  // Check to see if ellipses are enabled:
-  // If they are, then retrieve the ellipsis width for the font and reset the
-  // ellipsis boxes on all child boxes because they are no longer valid.
-  // Otherwise, set the width to 0, which indicates that ellipses are not being
-  // used. In this case, child boxes do not need to have ellipses reset, as they
-  // could not have previously been set.
-  float ellipsis_width;
-  if (AreEllipsesEnabled()) {
-    ellipsis_width = used_font_->GetEllipsisWidth();
-
-    for (Boxes::const_iterator child_box_iterator = child_boxes().begin();
-         child_box_iterator != child_boxes().end(); ++child_box_iterator) {
-      (*child_box_iterator)->ResetEllipses();
-    }
-  } else {
-    ellipsis_width = 0;
+  // Do any processing needed prior to ellipsis placement on all of the
+  // children.
+  for (Boxes::const_iterator child_ellipsis_iterator = child_boxes().begin();
+       child_ellipsis_iterator != child_boxes().end();
+       ++child_ellipsis_iterator) {
+    (*child_ellipsis_iterator)->DoPreEllipsisPlacementProcessing();
   }
 
+  // If ellipses are enabled then retrieve the ellipsis width for the font;
+  // otherwise, set the width to 0, which indicates that ellipses are not being
+  // used.
+  float ellipsis_width =
+      AreEllipsesEnabled() ? used_font_->GetEllipsisWidth() : 0;
+
   // Lay out child boxes in the normal flow.
   //   https://www.w3.org/TR/CSS21/visuren.html#normal-flow
   scoped_ptr<InlineFormattingContext> inline_formatting_context(
@@ -204,6 +197,15 @@
   }
   inline_formatting_context->EndUpdates();
   ellipses_coordinates_ = inline_formatting_context->GetEllipsesCoordinates();
+
+  // Do any processing needed following ellipsis placement on all of the
+  // children.
+  for (Boxes::const_iterator child_ellipsis_iterator = child_boxes().begin();
+       child_ellipsis_iterator != child_boxes().end();
+       ++child_ellipsis_iterator) {
+    (*child_ellipsis_iterator)->DoPostEllipsisPlacementProcessing();
+  }
+
   return inline_formatting_context.PassAs<FormattingContext>();
 }
 
diff --git a/src/cobalt/layout/anonymous_block_box.h b/src/cobalt/layout/anonymous_block_box.h
index 54c1673..bda736f 100644
--- a/src/cobalt/layout/anonymous_block_box.h
+++ b/src/cobalt/layout/anonymous_block_box.h
@@ -47,10 +47,8 @@
 
   bool HasTrailingLineBreak() const OVERRIDE;
 
-  void RenderAndAnimateContent(
-      render_tree::CompositionNode::Builder* border_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder) const OVERRIDE;
+  void RenderAndAnimateContent(render_tree::CompositionNode::Builder*
+                                   border_node_builder) const OVERRIDE;
 
   // From |ContainerBox|.
 
diff --git a/src/cobalt/layout/block_formatting_block_container_box.cc b/src/cobalt/layout/block_formatting_block_container_box.cc
index b4023d8..1c85502 100644
--- a/src/cobalt/layout/block_formatting_block_container_box.cc
+++ b/src/cobalt/layout/block_formatting_block_container_box.cc
@@ -96,14 +96,14 @@
     // TODO: Determine which animations to propagate to the anonymous block box,
     //       instead of none at all.
     scoped_refptr<cssom::CSSComputedStyleDeclaration>
-        css_computed_style_declaration =
+        new_computed_style_declaration =
             new cssom::CSSComputedStyleDeclaration();
-    css_computed_style_declaration->set_data(
-        GetComputedStyleOfAnonymousBox(computed_style()));
-    css_computed_style_declaration->set_animations(
+    new_computed_style_declaration->SetData(
+        GetComputedStyleOfAnonymousBox(css_computed_style_declaration()));
+    new_computed_style_declaration->set_animations(
         new web_animations::AnimationSet());
     scoped_refptr<AnonymousBlockBox> new_anonymous_block_box(
-        new AnonymousBlockBox(css_computed_style_declaration,
+        new AnonymousBlockBox(new_computed_style_declaration,
                               GetBaseDirection(), used_style_provider(),
                               layout_stat_tracker()));
     anonymous_block_box = new_anonymous_block_box.get();
@@ -144,7 +144,8 @@
                                        layout_stat_tracker),
       paragraph_(paragraph),
       text_position_(text_position),
-      is_hidden_by_ellipsis_(false) {}
+      is_hidden_by_ellipsis_(false),
+      was_hidden_by_ellipsis_(false) {}
 
 InlineLevelBlockContainerBox::~InlineLevelBlockContainerBox() {}
 
@@ -216,10 +217,17 @@
   return true;
 }
 
-void InlineLevelBlockContainerBox::ResetEllipses() {
+void InlineLevelBlockContainerBox::DoPreEllipsisPlacementProcessing() {
+  was_hidden_by_ellipsis_ = is_hidden_by_ellipsis_;
   is_hidden_by_ellipsis_ = false;
 }
 
+void InlineLevelBlockContainerBox::DoPostEllipsisPlacementProcessing() {
+  if (was_hidden_by_ellipsis_ != is_hidden_by_ellipsis_) {
+    InvalidateRenderTreeNodesOfBoxAndAncestors();
+  }
+}
+
 bool InlineLevelBlockContainerBox::IsHiddenByEllipsis() const {
   return is_hidden_by_ellipsis_;
 }
diff --git a/src/cobalt/layout/block_formatting_block_container_box.h b/src/cobalt/layout/block_formatting_block_container_box.h
index 197960b..a4a5bd9 100644
--- a/src/cobalt/layout/block_formatting_block_container_box.h
+++ b/src/cobalt/layout/block_formatting_block_container_box.h
@@ -117,7 +117,8 @@
   base::optional<int> GetBidiLevel() const OVERRIDE;
 
   bool DoesFulfillEllipsisPlacementRequirement() const OVERRIDE;
-  void ResetEllipses() OVERRIDE;
+  void DoPreEllipsisPlacementProcessing() OVERRIDE;
+  void DoPostEllipsisPlacementProcessing() OVERRIDE;
   bool IsHiddenByEllipsis() const OVERRIDE;
 
  protected:
@@ -143,6 +144,11 @@
   // the applicable edge(s) of the line as necessary to fit the ellipsis."
   //   https://www.w3.org/TR/css3-ui/#propdef-text-overflow
   bool is_hidden_by_ellipsis_;
+  // Tracking of the previous value of |is_hidden_by_ellipsis_|, which allows
+  // for determination of whether or not the value changed during ellipsis
+  // placement. When this occurs, the cached render tree nodes of this box and
+  // its ancestors are invalidated.
+  bool was_hidden_by_ellipsis_;
 };
 
 }  // namespace layout
diff --git a/src/cobalt/layout/box.cc b/src/cobalt/layout/box.cc
index 82cbeb3..c8739ee 100644
--- a/src/cobalt/layout/box.cc
+++ b/src/cobalt/layout/box.cc
@@ -53,7 +53,7 @@
 using cobalt::render_tree::RoundedCorners;
 using cobalt::render_tree::ViewportFilter;
 using cobalt::render_tree::animations::Animation;
-using cobalt::render_tree::animations::NodeAnimationsMap;
+using cobalt::render_tree::animations::AnimateNode;
 
 namespace cobalt {
 namespace layout {
@@ -110,6 +110,10 @@
   UpdateBorders();
   UpdatePaddings(layout_params);
   UpdateContentSizeAndMargins(layout_params);
+
+  // After a size update, this portion of the render tree must be updated, so
+  // invalidate any cached render tree nodes.
+  InvalidateRenderTreeNodesOfBoxAndAncestors();
 }
 
 bool Box::ValidateUpdateSizeInputs(const LayoutParams& params) {
@@ -190,6 +194,13 @@
   }
 }
 
+void Box::InvalidateRenderTreeNodesOfBoxAndAncestors() {
+  cached_render_tree_node_info_ = base::nullopt;
+  if (parent_) {
+    parent_->InvalidateRenderTreeNodesOfBoxAndAncestors();
+  }
+}
+
 LayoutUnit Box::GetMarginBoxWidth() const {
   return margin_left() + GetBorderBoxWidth() + margin_right();
 }
@@ -385,8 +396,25 @@
 
 void Box::RenderAndAnimate(
     CompositionNode::Builder* parent_content_node_builder,
-    NodeAnimationsMap::Builder* node_animations_map_builder,
-    const math::Vector2dF& offset_from_parent_node) const {
+    const math::Vector2dF& offset_from_parent_node) {
+  math::Vector2dF border_box_offset(left().toFloat() + margin_left().toFloat(),
+                                    top().toFloat() + margin_top().toFloat());
+  border_box_offset += offset_from_parent_node;
+
+  // If there's a pre-existing cached render tree node that is located at the
+  // border box offset, then simply use it. There's no more work to do.
+  if (cached_render_tree_node_info_ &&
+      cached_render_tree_node_info_->offset_ == border_box_offset) {
+    if (cached_render_tree_node_info_->node_) {
+      parent_content_node_builder->AddChild(
+          cached_render_tree_node_info_->node_);
+    }
+    return;
+  }
+
+  // Initialize the cached render tree node with the border box offset.
+  cached_render_tree_node_info_ = CachedRenderTreeNodeInfo(border_box_offset);
+
   float opacity = base::polymorphic_downcast<const cssom::NumberValue*>(
                       computed_style()->opacity().get())
                       ->value();
@@ -406,10 +434,8 @@
     return;
   }
 
-  math::Vector2dF border_box_offset(left().toFloat() + margin_left().toFloat(),
-                                    top().toFloat() + margin_top().toFloat());
-  border_box_offset += offset_from_parent_node;
   render_tree::CompositionNode::Builder border_node_builder(border_box_offset);
+  AnimateNode::Builder animate_node_builder;
 
   UsedBorderRadiusProvider border_radius_provider(GetBorderBoxSize());
   computed_style()->border_radius()->Accept(&border_radius_provider);
@@ -446,17 +472,14 @@
   // 'visibility: visible'.
   //   https://www.w3.org/TR/CSS21/visufx.html#propdef-visibility
   if (computed_style()->visibility() == cssom::KeywordValue::GetVisible()) {
-    RenderAndAnimateBackgroundColor(padding_rounded_corners,
-                                    &border_node_builder,
-                                    node_animations_map_builder);
-    RenderAndAnimateBackgroundImage(padding_rounded_corners,
-                                    &border_node_builder,
-                                    node_animations_map_builder);
+    RenderAndAnimateBackgroundColor(
+        padding_rounded_corners, &border_node_builder, &animate_node_builder);
+    RenderAndAnimateBackgroundImage(
+        padding_rounded_corners, &border_node_builder, &animate_node_builder);
     RenderAndAnimateBorder(border_radius_provider.rounded_corners(),
-                           &border_node_builder, node_animations_map_builder);
+                           &border_node_builder, &animate_node_builder);
     RenderAndAnimateBoxShadow(border_radius_provider.rounded_corners(),
-                              &border_node_builder,
-                              node_animations_map_builder);
+                              &border_node_builder, &animate_node_builder);
   }
 
   const bool overflow_hidden =
@@ -472,17 +495,17 @@
        border_insets_.zero())) {
     // If there's no reason to distinguish between content and background,
     // just add them all to the same composition node.
-    RenderAndAnimateContent(&border_node_builder, node_animations_map_builder);
+    RenderAndAnimateContent(&border_node_builder);
   } else {
     CompositionNode::Builder content_node_builder;
     // Otherwise, deal with content specifically so that we can apply overflow:
     // hidden to the content but not the background.
-    RenderAndAnimateContent(&content_node_builder, node_animations_map_builder);
+    RenderAndAnimateContent(&content_node_builder);
     if (!content_node_builder.children().empty()) {
       border_node_builder.AddChild(RenderAndAnimateOverflow(
           padding_rounded_corners,
           new CompositionNode(content_node_builder.Pass()),
-          node_animations_map_builder, math::Vector2dF(0, 0)));
+          &animate_node_builder, math::Vector2dF(0, 0)));
     }
     // We've already applied overflow hidden, no need to apply it again later.
     overflow_hidden_needs_to_be_applied = false;
@@ -492,16 +515,22 @@
     scoped_refptr<render_tree::Node> border_node =
         new CompositionNode(border_node_builder.Pass());
     if (overflow_hidden_needs_to_be_applied) {
-      border_node = RenderAndAnimateOverflow(
-          padding_rounded_corners, border_node, node_animations_map_builder,
-          border_box_offset);
+      border_node =
+          RenderAndAnimateOverflow(padding_rounded_corners, border_node,
+                                   &animate_node_builder, border_box_offset);
     }
-    border_node = RenderAndAnimateOpacity(
-        border_node, node_animations_map_builder, opacity, opacity_animated);
-    border_node = RenderAndAnimateTransform(
-        border_node, node_animations_map_builder, border_box_offset);
+    border_node = RenderAndAnimateOpacity(border_node, &animate_node_builder,
+                                          opacity, opacity_animated);
+    border_node = RenderAndAnimateTransform(border_node, &animate_node_builder,
+                                            border_box_offset);
 
-    parent_content_node_builder->AddChild(border_node);
+    cached_render_tree_node_info_->node_ =
+        animate_node_builder.empty()
+            ? border_node
+            : scoped_refptr<render_tree::Node>(
+                  new AnimateNode(animate_node_builder, border_node));
+
+    parent_content_node_builder->AddChild(cached_render_tree_node_info_->node_);
   }
 }
 
@@ -536,6 +565,14 @@
 #endif  // COBALT_BOX_DUMP_ENABLED
 
 namespace {
+void PopulateBaseStyleForBackgroundNode(
+    const scoped_refptr<const cssom::CSSComputedStyleData>& source_style,
+    const scoped_refptr<cssom::CSSComputedStyleData>& destination_style) {
+  // NOTE: Properties set by PopulateBaseStyleForBackgroundNode() should match
+  // the properties used by SetupBackgroundNodeFromStyle().
+  destination_style->set_background_color(source_style->background_color());
+}
+
 void SetupBackgroundNodeFromStyle(
     const base::optional<RoundedCorners>& rounded_corners,
     const scoped_refptr<const cssom::CSSComputedStyleData>& style,
@@ -596,6 +633,36 @@
   return Border(left, right, top, bottom);
 }
 
+void PopulateBaseStyleForBorderNode(
+    const scoped_refptr<const cssom::CSSComputedStyleData>& source_style,
+    const scoped_refptr<cssom::CSSComputedStyleData>& destination_style) {
+  // NOTE: Properties set by PopulateBaseStyleForBorderNode() should match the
+  // properties used by SetupBorderNodeFromStyle().
+
+  // Left
+  destination_style->set_border_left_width(source_style->border_left_width());
+  destination_style->set_border_left_style(source_style->border_left_style());
+  destination_style->set_border_left_color(source_style->border_left_color());
+
+  // Right
+  destination_style->set_border_right_width(source_style->border_right_width());
+  destination_style->set_border_right_style(source_style->border_right_style());
+  destination_style->set_border_right_color(source_style->border_right_color());
+
+  // Top
+  destination_style->set_border_top_width(source_style->border_top_width());
+  destination_style->set_border_top_style(source_style->border_top_style());
+  destination_style->set_border_top_color(source_style->border_top_color());
+
+  // Bottom
+  destination_style->set_border_bottom_width(
+      source_style->border_bottom_width());
+  destination_style->set_border_bottom_style(
+      source_style->border_bottom_style());
+  destination_style->set_border_bottom_color(
+      source_style->border_bottom_color());
+}
+
 void SetupBorderNodeFromStyle(
     const base::optional<RoundedCorners>& rounded_corners,
     const scoped_refptr<const cssom::CSSComputedStyleData>& style,
@@ -774,7 +841,7 @@
 // CSS transform style property.  If the object does not have a transform
 // style property set, this will be the identity matrix.  Otherwise, it is
 // calculated from the property value and returned.  The transform-origin
-// style property will also be taken into account, and therefore the layed
+// style property will also be taken into account, and therefore the laid
 // out size of the object is also required in order to resolve a
 // percentage-based transform-origin.
 math::Matrix3F GetCSSTransform(
@@ -797,10 +864,20 @@
          math::TranslateMatrix(-origin.x(), -origin.y());
 }
 
-// Used within the animation callback for CSS transforms.  This will
-// set the transform of a single-child composition node to that specified by
-// the CSS transform of the provided CSS Style Declaration.
-void SetupCompositionNodeFromCSSSStyleTransform(
+void PopulateBaseStyleForMatrixTransformNode(
+    const scoped_refptr<const cssom::CSSComputedStyleData>& source_style,
+    const scoped_refptr<cssom::CSSComputedStyleData>& destination_style) {
+  // NOTE: Properties set by PopulateBaseStyleForMatrixTransformNode() should
+  // match the properties used by
+  // SetupMatrixTransformNodeFromCSSSStyleTransform().
+  destination_style->set_transform(source_style->transform());
+  destination_style->set_transform_origin(source_style->transform_origin());
+}
+
+// Used within the animation callback for CSS transforms.  This will set the
+// transform of a single-child matrix transform node to that specified by the
+// CSS transform of the provided CSS Style Declaration.
+void SetupMatrixTransformNodeFromCSSSStyleTransform(
     const math::RectF& used_rect,
     const scoped_refptr<const cssom::CSSComputedStyleData>& style,
     MatrixTransformNode::Builder* transform_node_builder) {
@@ -808,6 +885,14 @@
       GetCSSTransform(style->transform(), style->transform_origin(), used_rect);
 }
 
+void PopulateBaseStyleForFilterNode(
+    const scoped_refptr<const cssom::CSSComputedStyleData>& source_style,
+    const scoped_refptr<cssom::CSSComputedStyleData>& destination_style) {
+  // NOTE: Properties set by PopulateBaseStyleForFilterNode() should match the
+  // properties used by SetupFilterNodeFromStyle().
+  destination_style->set_opacity(source_style->opacity());
+}
+
 void SetupFilterNodeFromStyle(
     const scoped_refptr<const cssom::CSSComputedStyleData>& style,
     FilterNode::Builder* filter_node_builder) {
@@ -843,8 +928,8 @@
 void Box::RenderAndAnimateBoxShadow(
     const base::optional<RoundedCorners>& rounded_corners,
     CompositionNode::Builder* border_node_builder,
-    NodeAnimationsMap::Builder* node_animations_map_builder) const {
-  UNREFERENCED_PARAMETER(node_animations_map_builder);
+    AnimateNode::Builder* animate_node_builder) {
+  UNREFERENCED_PARAMETER(animate_node_builder);
 
   if (computed_style()->box_shadow() != cssom::KeywordValue::GetNone()) {
     const cssom::PropertyListValue* box_shadow_list =
@@ -907,7 +992,7 @@
 void Box::RenderAndAnimateBorder(
     const base::optional<RoundedCorners>& rounded_corners,
     CompositionNode::Builder* border_node_builder,
-    NodeAnimationsMap::Builder* node_animations_map_builder) const {
+    AnimateNode::Builder* animate_node_builder) {
   // If the border is absent or all borders are transparent, there is no need
   // to render border.
   if (border_insets_.zero() || AreAllBordersTransparent(computed_style())) {
@@ -924,16 +1009,16 @@
 
   if (HasAnimatedBorder(animations())) {
     AddAnimations<RectNode>(
+        base::Bind(&PopulateBaseStyleForBorderNode),
         base::Bind(&SetupBorderNodeFromStyle, rounded_corners),
-        *css_computed_style_declaration(), border_node,
-        node_animations_map_builder);
+        *css_computed_style_declaration(), border_node, animate_node_builder);
   }
 }
 
 void Box::RenderAndAnimateBackgroundColor(
     const base::optional<RoundedCorners>& rounded_corners,
     render_tree::CompositionNode::Builder* border_node_builder,
-    NodeAnimationsMap::Builder* node_animations_map_builder) const {
+    AnimateNode::Builder* animate_node_builder) {
   // Only create the RectNode if the background color is not the initial value
   // (which we know is transparent) and not transparent.  If it's animated,
   // add it no matter what since its value may change over time to be
@@ -958,9 +1043,9 @@
       // instead here.
       if (background_color_animated) {
         AddAnimations<RectNode>(
+            base::Bind(&PopulateBaseStyleForBackgroundNode),
             base::Bind(&SetupBackgroundNodeFromStyle, rounded_corners),
-            *css_computed_style_declaration(), rect_node,
-            node_animations_map_builder);
+            *css_computed_style_declaration(), rect_node, animate_node_builder);
       }
     }
   }
@@ -969,8 +1054,8 @@
 void Box::RenderAndAnimateBackgroundImage(
     const base::optional<RoundedCorners>& rounded_corners,
     CompositionNode::Builder* border_node_builder,
-    NodeAnimationsMap::Builder* node_animations_map_builder) const {
-  UNREFERENCED_PARAMETER(node_animations_map_builder);
+    AnimateNode::Builder* animate_node_builder) {
+  UNREFERENCED_PARAMETER(animate_node_builder);
 
   math::RectF image_frame(
       math::PointF(border_left_width().toFloat(), border_top_width().toFloat()),
@@ -1012,9 +1097,8 @@
 
 scoped_refptr<render_tree::Node> Box::RenderAndAnimateOpacity(
     const scoped_refptr<render_tree::Node>& border_node,
-    render_tree::animations::NodeAnimationsMap::Builder*
-        node_animations_map_builder,
-    float opacity, bool opacity_animated) const {
+    AnimateNode::Builder* animate_node_builder, float opacity,
+    bool opacity_animated) {
   if (opacity < 1.0f || opacity_animated) {
     FilterNode::Builder filter_node_builder(border_node);
 
@@ -1026,9 +1110,10 @@
 
     if (opacity_animated) {
       // Possibly setup an animation for opacity.
-      AddAnimations<FilterNode>(base::Bind(&SetupFilterNodeFromStyle),
+      AddAnimations<FilterNode>(base::Bind(&PopulateBaseStyleForFilterNode),
+                                base::Bind(&SetupFilterNodeFromStyle),
                                 *css_computed_style_declaration(), filter_node,
-                                node_animations_map_builder);
+                                animate_node_builder);
     }
     return filter_node;
   }
@@ -1038,10 +1123,9 @@
 
 scoped_refptr<render_tree::Node> Box::RenderAndAnimateOverflow(
     const base::optional<render_tree::RoundedCorners>& rounded_corners,
-    const scoped_refptr<render_tree::Node>& content_node,
-    render_tree::animations::NodeAnimationsMap::Builder*
-    /* node_animations_map_builder */,
-    const math::Vector2dF& border_node_offset) const {
+    const scoped_refptr<render_tree::Node>& content_node, AnimateNode::Builder*
+    /* animate_node_builder */,
+    const math::Vector2dF& border_node_offset) {
   bool overflow_hidden =
       computed_style()->overflow().get() == cssom::KeywordValue::GetHidden();
 
@@ -1069,24 +1153,25 @@
 
 scoped_refptr<render_tree::Node> Box::RenderAndAnimateTransform(
     const scoped_refptr<render_tree::Node>& border_node,
-    render_tree::animations::NodeAnimationsMap::Builder*
-        node_animations_map_builder,
-    const math::Vector2dF& border_node_offset) const {
+    AnimateNode::Builder* animate_node_builder,
+    const math::Vector2dF& border_node_offset) {
   if (IsTransformable() &&
       animations()->IsPropertyAnimated(cssom::kTransformProperty)) {
     // If the CSS transform is animated, we cannot flatten it into the layout
-    // transform, thus we create a new composition node to separate it and
+    // transform, thus we create a new matrix transform node to separate it and
     // animate that node only.
     scoped_refptr<MatrixTransformNode> css_transform_node =
         new MatrixTransformNode(border_node, math::Matrix3F::Identity());
 
-    // Specifically animate only the composition node with the CSS transform.
+    // Specifically animate only the matrix transform node with the CSS
+    // transform.
     AddAnimations<MatrixTransformNode>(
-        base::Bind(&SetupCompositionNodeFromCSSSStyleTransform,
+        base::Bind(&PopulateBaseStyleForMatrixTransformNode),
+        base::Bind(&SetupMatrixTransformNodeFromCSSSStyleTransform,
                    math::RectF(PointAtOffsetFromOrigin(border_node_offset),
                                GetBorderBoxSize())),
         *css_computed_style_declaration(), css_transform_node,
-        node_animations_map_builder);
+        animate_node_builder);
 
     return css_transform_node;
   }
diff --git a/src/cobalt/layout/box.h b/src/cobalt/layout/box.h
index a85dfc5..676b04d 100644
--- a/src/cobalt/layout/box.h
+++ b/src/cobalt/layout/box.h
@@ -37,7 +37,7 @@
 #include "cobalt/layout/vector2d_layout_unit.h"
 #include "cobalt/math/point_f.h"
 #include "cobalt/math/rect_f.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 #include "cobalt/render_tree/composition_node.h"
 #include "cobalt/web_animations/animation_set.h"
 
@@ -314,8 +314,15 @@
   // element on a line."
   //   https://www.w3.org/TR/css3-ui/#propdef-text-overflow
   virtual bool DoesFulfillEllipsisPlacementRequirement() const { return false; }
-  // Reset all ellipses-related state within the box.
-  virtual void ResetEllipses() {}
+  // Do any processing needed prior to ellipsis placement. This involves caching
+  // the old value and resetting the current value so it can be determined
+  // whether or not the ellipsis state within a box changed as a a result of
+  // ellipsis placement.
+  virtual void DoPreEllipsisPlacementProcessing() {}
+  // Do any processing needed following ellipsis placement. This involves
+  // checking the old value against the new value and resetting the cached
+  // render tree node if the ellipsis state changed.
+  virtual void DoPostEllipsisPlacementProcessing() {}
   // Whether or not the box is fully hidden by an ellipsis. This applies to
   // atomic inline-level elements that have had an ellipsis placed before them
   // on a line. https://www.w3.org/TR/css3-ui/#propdef-text-overflow
@@ -401,14 +408,16 @@
   // time they are needed.
   virtual void InvalidateCrossReferencesOfBoxAndAncestors();
 
+  // Invalidating the render tree nodes causes them to be re-generated the next
+  // time they are needed.
+  void InvalidateRenderTreeNodesOfBoxAndAncestors();
+
   // Converts a layout subtree into a render subtree.
   // This method defines the overall strategy of the conversion and relies
   // on the subclasses to provide the actual content.
   void RenderAndAnimate(
       render_tree::CompositionNode::Builder* parent_content_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder,
-      const math::Vector2dF& offset_from_parent_node) const;
+      const math::Vector2dF& offset_from_parent_node);
 
   // Poor man's reflection.
   virtual AnonymousBlockBox* AsAnonymousBlockBox();
@@ -528,9 +537,7 @@
 
   // Renders the content of the box.
   virtual void RenderAndAnimateContent(
-      render_tree::CompositionNode::Builder* border_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder) const = 0;
+      render_tree::CompositionNode::Builder* border_node_builder) const = 0;
 
   // A transformable element is an element whose layout is governed by the CSS
   // box model which is either a block-level or atomic inline-level element.
@@ -564,6 +571,14 @@
       const base::optional<LayoutUnit>& possibly_overconstrained_margin_right);
 
  private:
+  struct CachedRenderTreeNodeInfo {
+    explicit CachedRenderTreeNodeInfo(const math::Vector2dF& offset)
+        : offset_(offset) {}
+
+    math::Vector2dF offset_;
+    scoped_refptr<render_tree::Node> node_;
+  };
+
   // Updates used values of "border" properties.
   void UpdateBorders();
   // Updates used values of "padding" properties.
@@ -583,47 +598,40 @@
   void RenderAndAnimateBorder(
       const base::optional<render_tree::RoundedCorners>& rounded_corners,
       render_tree::CompositionNode::Builder* border_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder) const;
+      render_tree::animations::AnimateNode::Builder* animate_node_builder);
   void RenderAndAnimateBackgroundColor(
       const base::optional<render_tree::RoundedCorners>& rounded_corners,
       render_tree::CompositionNode::Builder* border_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder) const;
+      render_tree::animations::AnimateNode::Builder* animate_node_builder);
   void RenderAndAnimateBackgroundImage(
       const base::optional<render_tree::RoundedCorners>& rounded_corners,
       render_tree::CompositionNode::Builder* border_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder) const;
+      render_tree::animations::AnimateNode::Builder* animate_node_builder);
   void RenderAndAnimateBoxShadow(
       const base::optional<render_tree::RoundedCorners>& rounded_corners,
       render_tree::CompositionNode::Builder* border_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder) const;
+      render_tree::animations::AnimateNode::Builder* animate_node_builder);
 
   // If opacity is animated or other than 1, wraps a border node into a filter
   // node. Otherwise returns the original border node.
   scoped_refptr<render_tree::Node> RenderAndAnimateOpacity(
       const scoped_refptr<render_tree::Node>& border_node,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder,
-      float opacity, bool opacity_animated) const;
+      render_tree::animations::AnimateNode::Builder* animate_node_builder,
+      float opacity, bool opacity_animated);
 
   scoped_refptr<render_tree::Node> RenderAndAnimateOverflow(
       const base::optional<render_tree::RoundedCorners>& rounded_corners,
       const scoped_refptr<render_tree::Node>& border_node,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder,
-      const math::Vector2dF& border_node_offset) const;
+      render_tree::animations::AnimateNode::Builder* animate_node_builder,
+      const math::Vector2dF& border_node_offset);
 
   // If transform is not "none", wraps a border node in a MatrixTransformNode.
   // If transform is "none", returns the original border node and leaves
   // |border_node_transform| intact.
   scoped_refptr<render_tree::Node> RenderAndAnimateTransform(
       const scoped_refptr<render_tree::Node>& border_node,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder,
-      const math::Vector2dF& border_node_offset) const;
+      render_tree::animations::AnimateNode::Builder* animate_node_builder,
+      const math::Vector2dF& border_node_offset);
 
   // The css_computed_style_declaration_ member references the
   // cssom::CSSComputedStyleDeclaration object owned by the HTML Element from
@@ -681,6 +689,10 @@
   // parameters we were passed during in last call to UpdateSizes().
   base::optional<LayoutParams> last_update_size_params_;
 
+  // Render tree node caching is used to prevent the node from needing to be
+  // recalculated during each call to RenderAndAnimateContent.
+  base::optional<CachedRenderTreeNodeInfo> cached_render_tree_node_info_;
+
   // For write access to parent/containing_block members.
   friend class ContainerBox;
   friend class LayoutBoxes;
diff --git a/src/cobalt/layout/box_generator.cc b/src/cobalt/layout/box_generator.cc
index a2affb9..1f2d803 100644
--- a/src/cobalt/layout/box_generator.cc
+++ b/src/cobalt/layout/box_generator.cc
@@ -317,8 +317,8 @@
 
   scoped_refptr<cssom::CSSComputedStyleDeclaration>
       css_computed_style_declaration = new cssom::CSSComputedStyleDeclaration();
-  css_computed_style_declaration->set_data(
-      GetComputedStyleOfAnonymousBox(br_element->computed_style()));
+  css_computed_style_declaration->SetData(GetComputedStyleOfAnonymousBox(
+      br_element->css_computed_style_declaration()));
 
   css_computed_style_declaration->set_animations(br_element->animations());
 
@@ -802,7 +802,7 @@
   new_data->AssignFrom(*style->data());
   new_data->SetPropertyValue(cssom::kBackgroundColorProperty, NULL);
   new_data->SetPropertyValue(cssom::kBackgroundImageProperty, NULL);
-  new_style->set_data(new_data);
+  new_style->SetData(new_data);
 
   return new_style;
 }
@@ -880,8 +880,8 @@
 void BoxGenerator::Visit(dom::Text* text) {
   scoped_refptr<cssom::CSSComputedStyleDeclaration>
       css_computed_style_declaration = new cssom::CSSComputedStyleDeclaration();
-  css_computed_style_declaration->set_data(GetComputedStyleOfAnonymousBox(
-      parent_css_computed_style_declaration_->data()));
+  css_computed_style_declaration->SetData(
+      GetComputedStyleOfAnonymousBox(parent_css_computed_style_declaration_));
 
   // Copy the animations from the parent.
   css_computed_style_declaration->set_animations(parent_animations_);
diff --git a/src/cobalt/layout/container_box.cc b/src/cobalt/layout/container_box.cc
index 24f72b1..4ee4b0b 100644
--- a/src/cobalt/layout/container_box.cc
+++ b/src/cobalt/layout/container_box.cc
@@ -93,6 +93,9 @@
     split_sibling->GetStackingContext()->are_cross_references_valid_ = false;
   }
 
+  // Invalidate the render tree nodes now that the children have changed.
+  InvalidateRenderTreeNodesOfBoxAndAncestors();
+
   return split_sibling_position;
 }
 
@@ -138,6 +141,9 @@
       !non_negative_z_index_child_.empty()) {
     are_cross_references_valid_ = false;
   }
+
+  // Invalidate the render tree nodes now that the children have changed.
+  InvalidateRenderTreeNodesOfBoxAndAncestors();
 }
 
 // Returns true if the given style allows a container box to act as a containing
@@ -471,8 +477,6 @@
 void ContainerBox::RenderAndAnimateStackingContextChildren(
     const ZIndexSortedList& z_index_child_list,
     render_tree::CompositionNode::Builder* content_node_builder,
-    render_tree::animations::NodeAnimationsMap::Builder*
-        node_animations_map_builder,
     const Vector2dLayoutUnit& offset_from_parent_node) const {
   // Render all children of the passed in list in sorted order.
   for (ZIndexSortedList::const_iterator iter = z_index_child_list.begin();
@@ -484,8 +488,7 @@
         GetOffsetFromStackingContextToContainingBlock(child_box) +
         offset_from_parent_node;
 
-    child_box->RenderAndAnimate(content_node_builder,
-                                node_animations_map_builder, position_offset);
+    child_box->RenderAndAnimate(content_node_builder, position_offset);
   }
 }
 
@@ -552,9 +555,7 @@
 }
 
 void ContainerBox::RenderAndAnimateContent(
-    render_tree::CompositionNode::Builder* border_node_builder,
-    render_tree::animations::NodeAnimationsMap::Builder*
-        node_animations_map_builder) const {
+    render_tree::CompositionNode::Builder* border_node_builder) const {
   // Ensure that the cross references are up to date.
   const_cast<ContainerBox*>(this)->UpdateCrossReferences();
 
@@ -564,22 +565,19 @@
   // z-index values.
   //   https://www.w3.org/TR/CSS21/visuren.html#z-index
   RenderAndAnimateStackingContextChildren(
-      negative_z_index_child_, border_node_builder, node_animations_map_builder,
-      content_box_offset);
+      negative_z_index_child_, border_node_builder, content_box_offset);
   // Render laid out child boxes.
   for (Boxes::const_iterator child_box_iterator = child_boxes_.begin();
        child_box_iterator != child_boxes_.end(); ++child_box_iterator) {
     Box* child_box = *child_box_iterator;
     if (!child_box->IsPositioned() && !child_box->IsTransformed()) {
-      child_box->RenderAndAnimate(
-          border_node_builder, node_animations_map_builder, content_box_offset);
+      child_box->RenderAndAnimate(border_node_builder, content_box_offset);
     }
   }
   // Render all positioned children with non-negative z-index values.
   //   https://www.w3.org/TR/CSS21/visuren.html#z-index
   RenderAndAnimateStackingContextChildren(
-      non_negative_z_index_child_, border_node_builder,
-      node_animations_map_builder, content_box_offset);
+      non_negative_z_index_child_, border_node_builder, content_box_offset);
 }
 
 #ifdef COBALT_BOX_DUMP_ENABLED
diff --git a/src/cobalt/layout/container_box.h b/src/cobalt/layout/container_box.h
index 31aba2b..2a13c91 100644
--- a/src/cobalt/layout/container_box.h
+++ b/src/cobalt/layout/container_box.h
@@ -62,10 +62,8 @@
   ContainerBox* AsContainerBox() OVERRIDE;
   const ContainerBox* AsContainerBox() const OVERRIDE;
 
-  void RenderAndAnimateContent(
-      render_tree::CompositionNode::Builder* border_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder) const OVERRIDE;
+  void RenderAndAnimateContent(render_tree::CompositionNode::Builder*
+                                   border_node_builder) const OVERRIDE;
 
 #ifdef COBALT_BOX_DUMP_ENABLED
   void DumpChildrenWithIndent(std::ostream* stream, int indent) const OVERRIDE;
@@ -167,8 +165,6 @@
   void RenderAndAnimateStackingContextChildren(
       const ZIndexSortedList& z_index_child_list,
       render_tree::CompositionNode::Builder* border_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder,
       const Vector2dLayoutUnit& offset_from_parent_node) const;
 
   // A list of our direct children.  If a box is one of our child boxes, we
diff --git a/src/cobalt/layout/initial_containing_block.cc b/src/cobalt/layout/initial_containing_block.cc
index 7c22f89..6bf5891 100644
--- a/src/cobalt/layout/initial_containing_block.cc
+++ b/src/cobalt/layout/initial_containing_block.cc
@@ -98,7 +98,7 @@
 
   scoped_refptr<cssom::CSSComputedStyleDeclaration> initial_style_state =
       new cssom::CSSComputedStyleDeclaration();
-  initial_style_state->set_data(initial_containing_block_style);
+  initial_style_state->SetData(initial_containing_block_style);
   initial_style_state->set_animations(new web_animations::AnimationSet());
 
   results.box = make_scoped_refptr(new BlockLevelBlockContainerBox(
diff --git a/src/cobalt/layout/inline_container_box.cc b/src/cobalt/layout/inline_container_box.cc
index 062bc6e..4ce8255 100644
--- a/src/cobalt/layout/inline_container_box.cc
+++ b/src/cobalt/layout/inline_container_box.cc
@@ -222,10 +222,17 @@
   return false;
 }
 
-void InlineContainerBox::ResetEllipses() {
+void InlineContainerBox::DoPreEllipsisPlacementProcessing() {
   for (Boxes::const_iterator child_box_iterator = child_boxes().begin();
        child_box_iterator != child_boxes().end(); ++child_box_iterator) {
-    (*child_box_iterator)->ResetEllipses();
+    (*child_box_iterator)->DoPreEllipsisPlacementProcessing();
+  }
+}
+
+void InlineContainerBox::DoPostEllipsisPlacementProcessing() {
+  for (Boxes::const_iterator child_box_iterator = child_boxes().begin();
+       child_box_iterator != child_boxes().end(); ++child_box_iterator) {
+    (*child_box_iterator)->DoPostEllipsisPlacementProcessing();
   }
 }
 
diff --git a/src/cobalt/layout/inline_container_box.h b/src/cobalt/layout/inline_container_box.h
index 8c873a0..6444c0e 100644
--- a/src/cobalt/layout/inline_container_box.h
+++ b/src/cobalt/layout/inline_container_box.h
@@ -58,7 +58,8 @@
   Box* GetSplitSibling() const OVERRIDE;
 
   bool DoesFulfillEllipsisPlacementRequirement() const OVERRIDE;
-  void ResetEllipses() OVERRIDE;
+  void DoPreEllipsisPlacementProcessing() OVERRIDE;
+  void DoPostEllipsisPlacementProcessing() OVERRIDE;
 
   bool TrySplitAtSecondBidiLevelRun() OVERRIDE;
   base::optional<int> GetBidiLevel() const OVERRIDE;
diff --git a/src/cobalt/layout/inline_level_replaced_box.cc b/src/cobalt/layout/inline_level_replaced_box.cc
index 8603e7d..9d6072c 100644
--- a/src/cobalt/layout/inline_level_replaced_box.cc
+++ b/src/cobalt/layout/inline_level_replaced_box.cc
@@ -35,7 +35,8 @@
                   text_position, maybe_intrinsic_width, maybe_intrinsic_height,
                   maybe_intrinsic_ratio, used_style_provider,
                   layout_stat_tracker),
-      is_hidden_by_ellipsis_(false) {}
+      is_hidden_by_ellipsis_(false),
+      was_hidden_by_ellipsis_(false) {}
 
 Box::Level InlineLevelReplacedBox::GetLevel() const { return kInlineLevel; }
 
@@ -46,7 +47,16 @@
   return true;
 }
 
-void InlineLevelReplacedBox::ResetEllipses() { is_hidden_by_ellipsis_ = false; }
+void InlineLevelReplacedBox::DoPreEllipsisPlacementProcessing() {
+  was_hidden_by_ellipsis_ = is_hidden_by_ellipsis_;
+  is_hidden_by_ellipsis_ = false;
+}
+
+void InlineLevelReplacedBox::DoPostEllipsisPlacementProcessing() {
+  if (was_hidden_by_ellipsis_ != is_hidden_by_ellipsis_) {
+    InvalidateRenderTreeNodesOfBoxAndAncestors();
+  }
+}
 
 bool InlineLevelReplacedBox::IsHiddenByEllipsis() const {
   return is_hidden_by_ellipsis_;
diff --git a/src/cobalt/layout/inline_level_replaced_box.h b/src/cobalt/layout/inline_level_replaced_box.h
index a53c1f6..b0f1a25 100644
--- a/src/cobalt/layout/inline_level_replaced_box.h
+++ b/src/cobalt/layout/inline_level_replaced_box.h
@@ -48,7 +48,8 @@
   Level GetLevel() const OVERRIDE;
 
   bool DoesFulfillEllipsisPlacementRequirement() const OVERRIDE;
-  void ResetEllipses() OVERRIDE;
+  void DoPreEllipsisPlacementProcessing() OVERRIDE;
+  void DoPostEllipsisPlacementProcessing() OVERRIDE;
   bool IsHiddenByEllipsis() const OVERRIDE;
 
  protected:
@@ -76,6 +77,11 @@
   // the applicable edge(s) of the line as necessary to fit the ellipsis."
   //   https://www.w3.org/TR/css3-ui/#propdef-text-overflow
   bool is_hidden_by_ellipsis_;
+  // Tracking of the previous value of |is_hidden_by_ellipsis_|, which allows
+  // for determination of whether or not the value changed during ellipsis
+  // placement. When this occurs, the cached render tree nodes of this box and
+  // its ancestors are invalidated.
+  bool was_hidden_by_ellipsis_;
 };
 
 }  // namespace layout
diff --git a/src/cobalt/layout/layout.cc b/src/cobalt/layout/layout.cc
index 9acfffb..d517a4f 100644
--- a/src/cobalt/layout/layout.cc
+++ b/src/cobalt/layout/layout.cc
@@ -28,7 +28,7 @@
 #include "cobalt/layout/box_generator.h"
 #include "cobalt/layout/initial_containing_block.h"
 #include "cobalt/layout/used_style.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 
 namespace cobalt {
 namespace layout {
@@ -73,8 +73,8 @@
   // Create initial containing block.
   InitialContainingBlockCreationResults
       initial_containing_block_creation_results = CreateInitialContainingBlock(
-          document->initial_computed_style(), document, used_style_provider,
-          layout_stat_tracker);
+          document->initial_computed_style_data(), document,
+          used_style_provider, layout_stat_tracker);
   *initial_containing_block = initial_containing_block_creation_results.box;
 
   // Generate boxes.
@@ -128,7 +128,7 @@
   }
 }
 
-RenderTreeWithAnimations Layout(
+scoped_refptr<render_tree::Node> Layout(
     const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
     UsedStyleProvider* used_style_provider,
     LayoutStatTracker* layout_stat_tracker,
@@ -141,8 +141,6 @@
       line_break_iterator, character_break_iterator, initial_containing_block);
 
   // Add to render tree.
-  render_tree::animations::NodeAnimationsMap::Builder
-      node_animations_map_builder;
   render_tree::CompositionNode::Builder render_tree_root_builder;
   {
     TRACE_EVENT0("cobalt::layout", kBenchmarkStatRenderAndAnimate);
@@ -151,14 +149,18 @@
         base::StopWatch::kAutoStartOn, layout_stat_tracker);
 
     (*initial_containing_block)
-        ->RenderAndAnimate(&render_tree_root_builder,
-                           &node_animations_map_builder, math::Vector2dF(0, 0));
+        ->RenderAndAnimate(&render_tree_root_builder, math::Vector2dF(0, 0));
   }
 
-  return RenderTreeWithAnimations(
-      new render_tree::CompositionNode(render_tree_root_builder.Pass()),
-      new render_tree::animations::NodeAnimationsMap(
-          node_animations_map_builder.Pass()));
+  render_tree::CompositionNode* static_root_node =
+      new render_tree::CompositionNode(render_tree_root_builder.Pass());
+
+  // Make it easy to animate the entire tree by placing an AnimateNode at the
+  // root to merge any sub-AnimateNodes.
+  render_tree::animations::AnimateNode* animate_node =
+      new render_tree::animations::AnimateNode(static_root_node);
+
+  return animate_node;
 }
 
 }  // namespace layout
diff --git a/src/cobalt/layout/layout.h b/src/cobalt/layout/layout.h
index 9b8bf8e..d9cdf7a 100644
--- a/src/cobalt/layout/layout.h
+++ b/src/cobalt/layout/layout.h
@@ -21,7 +21,7 @@
 #include "cobalt/layout/block_formatting_block_container_box.h"
 #include "cobalt/loader/image/image_cache.h"
 #include "cobalt/math/size_f.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 #include "cobalt/render_tree/node.h"
 #include "cobalt/render_tree/resource_provider.h"
 #include "third_party/icu/public/common/unicode/brkiter.h"
@@ -40,17 +40,6 @@
 // (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.
 
-struct RenderTreeWithAnimations {
-  RenderTreeWithAnimations(
-      const scoped_refptr<render_tree::Node>& render_tree,
-      const scoped_refptr<render_tree::animations::NodeAnimationsMap>&
-          animations)
-      : render_tree(render_tree), animations(animations) {}
-
-  scoped_refptr<render_tree::Node> render_tree;
-  scoped_refptr<render_tree::animations::NodeAnimationsMap> animations;
-};
-
 // Update the computed styles, then generate and layout the box tree.
 void UpdateComputedStylesAndLayoutBoxTree(
     const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
@@ -63,7 +52,7 @@
 // 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.
-RenderTreeWithAnimations Layout(
+scoped_refptr<render_tree::Node> Layout(
     const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
     UsedStyleProvider* used_style_provider,
     LayoutStatTracker* layout_stat_tracker,
diff --git a/src/cobalt/layout/layout_boxes.cc b/src/cobalt/layout/layout_boxes.cc
index 2c65d99..8a95115 100644
--- a/src/cobalt/layout/layout_boxes.cc
+++ b/src/cobalt/layout/layout_boxes.cc
@@ -159,6 +159,17 @@
   }
 }
 
+void LayoutBoxes::InvalidateRenderTreeNodes() {
+  for (Boxes::const_iterator box_iterator = boxes_.begin();
+       box_iterator != boxes_.end(); ++box_iterator) {
+    Box* box = *box_iterator;
+    do {
+      box->InvalidateRenderTreeNodesOfBoxAndAncestors();
+      box = box->GetSplitSibling();
+    } while (box != NULL);
+  }
+}
+
 math::RectF LayoutBoxes::GetBoundingBorderRectangle() const {
   // In the CSSOM View extensions to the HTMLElement interface, at
   // https://www.w3.org/TR/2013/WD-cssom-view-20131217/#extensions-to-the-htmlelement-interface,
diff --git a/src/cobalt/layout/layout_boxes.h b/src/cobalt/layout/layout_boxes.h
index 28708a8..055d1e0 100644
--- a/src/cobalt/layout/layout_boxes.h
+++ b/src/cobalt/layout/layout_boxes.h
@@ -58,6 +58,7 @@
 
   void InvalidateSizes() OVERRIDE;
   void InvalidateCrossReferences() OVERRIDE;
+  void InvalidateRenderTreeNodes() OVERRIDE;
 
   // Other
   //
diff --git a/src/cobalt/layout/layout_manager.cc b/src/cobalt/layout/layout_manager.cc
index b92c47b..c0fb5c6 100644
--- a/src/cobalt/layout/layout_manager.cc
+++ b/src/cobalt/layout/layout_manager.cc
@@ -239,7 +239,7 @@
       TRACE_EVENT_BEGIN0("cobalt::layout", kBenchmarkStatLayout);
     }
 
-    RenderTreeWithAnimations render_tree_with_animations = layout::Layout(
+    scoped_refptr<render_tree::Node> render_tree_root = layout::Layout(
         locale_, window_->document(), used_style_provider_.get(),
         layout_stat_tracker_, line_break_iterator_.get(),
         character_break_iterator_.get(), &initial_containing_block_);
@@ -251,11 +251,9 @@
     }
 #endif  // ENABLE_TEST_RUNNER
     if (run_on_render_tree_produced_callback) {
-      on_render_tree_produced_callback_.Run(
-          LayoutResults(render_tree_with_animations.render_tree,
-                        render_tree_with_animations.animations,
-                        base::TimeDelta::FromMillisecondsD(
-                            *document->timeline()->current_time())));
+      on_render_tree_produced_callback_.Run(LayoutResults(
+          render_tree_root, base::TimeDelta::FromMillisecondsD(
+                                *document->timeline()->current_time())));
     }
 
     layout_dirty_ = false;
diff --git a/src/cobalt/layout/layout_manager.h b/src/cobalt/layout/layout_manager.h
index 4a9b405..39e4eb7 100644
--- a/src/cobalt/layout/layout_manager.h
+++ b/src/cobalt/layout/layout_manager.h
@@ -25,7 +25,6 @@
 #include "cobalt/dom/window.h"
 #include "cobalt/layout/layout_stat_tracker.h"
 #include "cobalt/loader/image/image_cache.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
 #include "cobalt/render_tree/node.h"
 #include "cobalt/render_tree/resource_provider.h"
 
@@ -37,19 +36,15 @@
  public:
   struct LayoutResults {
     LayoutResults(const scoped_refptr<render_tree::Node>& render_tree,
-                  const scoped_refptr<
-                      render_tree::animations::NodeAnimationsMap>& animations,
                   const base::TimeDelta& layout_time)
         : render_tree(render_tree),
-          animations(animations),
           layout_time(layout_time) {}
 
     // The render tree produced by a layout.
     scoped_refptr<render_tree::Node> render_tree;
-    // Animations that are to be applied to the layout's render tree.
-    scoped_refptr<render_tree::animations::NodeAnimationsMap> animations;
+
     // The time that the render tree was created, which will be used as a
-    // reference point for updating the animations specified above.
+    // reference point for updating the animations in the above render tree.
     base::TimeDelta layout_time;
   };
 
diff --git a/src/cobalt/layout/render_tree_animations.h b/src/cobalt/layout/render_tree_animations.h
index 07121eb..0c8a862 100644
--- a/src/cobalt/layout/render_tree_animations.h
+++ b/src/cobalt/layout/render_tree_animations.h
@@ -33,6 +33,15 @@
 // a convenience function that can be used by code that creates render tree
 // nodes (e.g. layout box tree processing).
 
+// This callback function defines a function that is expected to populate a
+// given CSS style object for a render tree node type.
+class PopulateBaseStyleForRenderTreeNode {
+ public:
+  typedef base::Callback<void(
+      const scoped_refptr<const cssom::CSSComputedStyleData>&,
+      const scoped_refptr<cssom::CSSComputedStyleData>&)> Function;
+};
+
 // This callback function defines a function that is expected to apply a given
 // CSS style to a render tree node builder object.  A function meeting this
 // specification can be passed into AddAnimations() in order to
@@ -47,16 +56,16 @@
       typename T::Builder*)> Function;
 };
 
-// Helper function that applies a animation set to a base style to produce
+// Helper function that applies an animation set to a base style to produce
 // an animated style that is then passed into the provided
 // ApplyStyleToRenderTreeNode<T>::Function callback function.
 template <typename T>
-void AnimateNode(const typename ApplyStyleToRenderTreeNode<T>::Function&
-                     apply_style_function,
-                 const web_animations::BakedAnimationSet& animations,
-                 const scoped_refptr<cssom::CSSComputedStyleData>& base_style,
-                 typename T::Builder* node_builder,
-                 base::TimeDelta time_elapsed) {
+void ApplyAnimation(
+    const typename ApplyStyleToRenderTreeNode<T>::Function&
+        apply_style_function,
+    const web_animations::BakedAnimationSet& animations,
+    const scoped_refptr<cssom::CSSComputedStyleData>& base_style,
+    typename T::Builder* node_builder, base::TimeDelta time_elapsed) {
   scoped_refptr<cssom::CSSComputedStyleData> animated_style =
       new cssom::CSSComputedStyleData();
   animated_style->AssignFrom(*base_style);
@@ -65,26 +74,30 @@
 }
 
 // If animations exist, this function will add an animation which represents
-// the animations to the passed in NodeAnimationsMap.  The animation will
+// the animations to the passed in ApplyAnimation.  The animation will
 // target the passed in render tree node.
 template <typename T>
 void AddAnimations(
+    const typename PopulateBaseStyleForRenderTreeNode::Function&
+        populate_base_style_function,
     const typename ApplyStyleToRenderTreeNode<T>::Function&
         apply_style_function,
     const cssom::CSSComputedStyleDeclaration& css_computed_style_declaration,
     const scoped_refptr<T>& target_node,
-    render_tree::animations::NodeAnimationsMap::Builder*
-        node_animation_map_builder) {
+    render_tree::animations::AnimateNode::Builder* node_animation_map_builder) {
   DCHECK(!css_computed_style_declaration.animations()->IsEmpty());
-  scoped_refptr<cssom::CSSComputedStyleData> base_style_copy =
+
+  // Populate the base style.
+  scoped_refptr<cssom::CSSComputedStyleData> base_style =
       new cssom::CSSComputedStyleData();
-  base_style_copy->AssignFrom(*css_computed_style_declaration.data());
+  populate_base_style_function.Run(css_computed_style_declaration.data(),
+                                   base_style);
 
   node_animation_map_builder->Add(
-      target_node, base::Bind(&AnimateNode<T>, apply_style_function,
+      target_node, base::Bind(&ApplyAnimation<T>, apply_style_function,
                               web_animations::BakedAnimationSet(
                                   *css_computed_style_declaration.animations()),
-                              base_style_copy));
+                              base_style));
 }
 
 }  // namespace layout
diff --git a/src/cobalt/layout/replaced_box.cc b/src/cobalt/layout/replaced_box.cc
index 62b771f..15f0d6a 100644
--- a/src/cobalt/layout/replaced_box.cc
+++ b/src/cobalt/layout/replaced_box.cc
@@ -46,7 +46,7 @@
 namespace cobalt {
 namespace layout {
 
-using render_tree::animations::NodeAnimationsMap;
+using render_tree::animations::AnimateNode;
 using render_tree::CompositionNode;
 using render_tree::ImageNode;
 using render_tree::PunchThroughVideoNode;
@@ -239,8 +239,7 @@
 }  // namespace
 
 void ReplacedBox::RenderAndAnimateContent(
-    CompositionNode::Builder* border_node_builder,
-    NodeAnimationsMap::Builder* node_animations_map_builder) const {
+    CompositionNode::Builder* border_node_builder) const {
   if (computed_style()->visibility() != cssom::KeywordValue::GetVisible()) {
     return;
   }
@@ -257,11 +256,13 @@
   scoped_refptr<CompositionNode> composition_node =
       new CompositionNode(composition_node_builder);
 
-  node_animations_map_builder->Add(
+  AnimateNode::Builder animate_node_builder;
+  animate_node_builder.Add(
       composition_node,
       base::Bind(AnimateCB, replace_image_cb_, content_box_size()));
 
-  border_node_builder->AddChild(composition_node);
+  border_node_builder->AddChild(
+      new AnimateNode(animate_node_builder, composition_node));
 }
 
 void ReplacedBox::UpdateContentSizeAndMargins(
diff --git a/src/cobalt/layout/replaced_box.h b/src/cobalt/layout/replaced_box.h
index f503db3..259b2d0 100644
--- a/src/cobalt/layout/replaced_box.h
+++ b/src/cobalt/layout/replaced_box.h
@@ -76,10 +76,8 @@
   // From |Box|.
   void UpdateContentSizeAndMargins(const LayoutParams& layout_params) OVERRIDE;
 
-  void RenderAndAnimateContent(
-      render_tree::CompositionNode::Builder* border_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder) const OVERRIDE;
+  void RenderAndAnimateContent(render_tree::CompositionNode::Builder*
+                                   border_node_builder) const OVERRIDE;
 
   bool IsTransformable() const OVERRIDE { return true; }
 
diff --git a/src/cobalt/layout/text_box.cc b/src/cobalt/layout/text_box.cc
index 84e5823..1b4e96e 100644
--- a/src/cobalt/layout/text_box.cc
+++ b/src/cobalt/layout/text_box.cc
@@ -46,6 +46,7 @@
       text_start_position_(text_start_position),
       text_end_position_(text_end_position),
       truncated_text_end_position_(text_end_position),
+      previous_truncated_text_end_position_(text_end_position),
       truncated_text_offset_from_left_(0),
       used_font_(used_style_provider->GetUsedFontList(
           css_computed_style_declaration->data()->font_family(),
@@ -225,10 +226,17 @@
   return GetNonCollapsedTextStartPosition() < GetNonCollapsedTextEndPosition();
 }
 
-void TextBox::ResetEllipses() {
+void TextBox::DoPreEllipsisPlacementProcessing() {
+  previous_truncated_text_end_position_ = truncated_text_end_position_;
   truncated_text_end_position_ = text_end_position_;
 }
 
+void TextBox::DoPostEllipsisPlacementProcessing() {
+  if (previous_truncated_text_end_position_ != truncated_text_end_position_) {
+    InvalidateRenderTreeNodesOfBoxAndAncestors();
+  }
+}
+
 void TextBox::SplitBidiLevelRuns() {}
 
 bool TextBox::TrySplitAtSecondBidiLevelRun() {
@@ -299,6 +307,14 @@
 }
 
 namespace {
+void PopulateBaseStyleForTextNode(
+    const scoped_refptr<const cssom::CSSComputedStyleData>& source_style,
+    const scoped_refptr<cssom::CSSComputedStyleData>& destination_style) {
+  // NOTE: Properties set by PopulateBaseStyleForTextNode() should match the
+  // properties used by SetupTextNodeFromStyle().
+  destination_style->set_color(source_style->color());
+}
+
 void SetupTextNodeFromStyle(
     const scoped_refptr<const cssom::CSSComputedStyleData>& style,
     render_tree::TextNode::Builder* text_node_builder) {
@@ -340,11 +356,7 @@
 }  // namespace
 
 void TextBox::RenderAndAnimateContent(
-    render_tree::CompositionNode::Builder* border_node_builder,
-    render_tree::animations::NodeAnimationsMap::Builder*
-        node_animations_map_builder) const {
-  UNREFERENCED_PARAMETER(node_animations_map_builder);
-
+    render_tree::CompositionNode::Builder* border_node_builder) const {
   if (computed_style()->visibility() != cssom::KeywordValue::GetVisible()) {
     return;
   }
@@ -376,23 +388,15 @@
         text_shadow != cssom::KeywordValue::GetNone()) {
       int32 text_start_position = GetNonCollapsedTextStartPosition();
       int32 text_length = GetVisibleTextLength();
-      // Generate the glyph buffer if it does not already exist or the position
-      // it covers has changed. Otherwise, just use the cached glyph buffer.
-      if (!cached_glyph_buffer_info_.glyph_buffer ||
-          text_start_position != cached_glyph_buffer_info_.start_position ||
-          text_length != cached_glyph_buffer_info_.length) {
-        cached_glyph_buffer_info_.start_position = text_start_position;
-        cached_glyph_buffer_info_.length = text_length;
-        cached_glyph_buffer_info_.glyph_buffer = used_font_->CreateGlyphBuffer(
-            paragraph_->GetTextBuffer() +
-                cached_glyph_buffer_info_.start_position,
-            cached_glyph_buffer_info_.length,
-            paragraph_->IsRTL(text_start_position));
-      }
+
+      scoped_refptr<render_tree::GlyphBuffer> glyph_buffer =
+          used_font_->CreateGlyphBuffer(
+              paragraph_->GetTextBuffer() + text_start_position, text_length,
+              paragraph_->IsRTL(text_start_position));
 
       render_tree::TextNode::Builder text_node_builder(
           math::Vector2dF(truncated_text_offset_from_left_, ascent_),
-          cached_glyph_buffer_info_.glyph_buffer, used_color);
+          glyph_buffer, used_color);
 
       if (text_shadow != cssom::KeywordValue::GetNone()) {
         cssom::PropertyListValue* shadow_list =
@@ -407,13 +411,20 @@
 
       // The render tree API considers text coordinates to be a position
       // of a baseline, offset the text node accordingly.
-      border_node_builder->AddChild(text_node);
+      scoped_refptr<render_tree::Node> node_to_add;
       if (is_color_animated) {
+        render_tree::animations::AnimateNode::Builder animate_node_builder;
         AddAnimations<render_tree::TextNode>(
+            base::Bind(&PopulateBaseStyleForTextNode),
             base::Bind(&SetupTextNodeFromStyle),
             *css_computed_style_declaration(), text_node,
-            node_animations_map_builder);
+            &animate_node_builder);
+        node_to_add = new render_tree::animations::AnimateNode(
+            animate_node_builder, text_node);
+      } else {
+        node_to_add = text_node;
       }
+      border_node_builder->AddChild(node_to_add);
     }
   }
 }
diff --git a/src/cobalt/layout/text_box.h b/src/cobalt/layout/text_box.h
index 792e5a7..dc55439 100644
--- a/src/cobalt/layout/text_box.h
+++ b/src/cobalt/layout/text_box.h
@@ -57,7 +57,8 @@
   Box* GetSplitSibling() const OVERRIDE;
 
   bool DoesFulfillEllipsisPlacementRequirement() const OVERRIDE;
-  void ResetEllipses() OVERRIDE;
+  void DoPreEllipsisPlacementProcessing() OVERRIDE;
+  void DoPostEllipsisPlacementProcessing() OVERRIDE;
 
   void SplitBidiLevelRuns() OVERRIDE;
   bool TrySplitAtSecondBidiLevelRun() OVERRIDE;
@@ -82,10 +83,8 @@
 
  protected:
   // From |Box|.
-  void RenderAndAnimateContent(
-      render_tree::CompositionNode::Builder* border_node_builder,
-      render_tree::animations::NodeAnimationsMap::Builder*
-          node_animations_map_builder) const OVERRIDE;
+  void RenderAndAnimateContent(render_tree::CompositionNode::Builder*
+                                   border_node_builder) const OVERRIDE;
   bool IsTransformable() const OVERRIDE;
 
 #ifdef COBALT_BOX_DUMP_ENABLED
@@ -95,14 +94,6 @@
 #endif  // COBALT_BOX_DUMP_ENABLED
 
  private:
-  struct CachedGlyphBufferInfo {
-    CachedGlyphBufferInfo() : start_position(-1), length(0) {}
-
-    scoped_refptr<render_tree::GlyphBuffer> glyph_buffer;
-    int32 start_position;
-    int32 length;
-  };
-
   // From |Box|.
   void DoPlaceEllipsisOrProcessPlacedEllipsis(
       BaseDirection base_direction, LayoutUnit desired_offset,
@@ -162,6 +153,11 @@
   // the applicable edge(s) of the line as necessary to fit the ellipsis."
   //   https://www.w3.org/TR/css3-ui/#propdef-text-overflow
   int32 truncated_text_end_position_;
+  // Tracking of the previous value of |truncated_text_end_position_|, which
+  // allows for determination of whether or not the value changed during
+  // ellipsis placement. When this occurs, the cached render tree nodes of this
+  // box and its ancestors are invalidated.
+  int32 previous_truncated_text_end_position_;
   // The horizontal offset to apply to rendered text as a result of an ellipsis
   // truncating the text. This value can be non-zero when the text box is in a
   // line with a right-to-left base direction. In this case, when an ellipsis is
@@ -197,11 +193,6 @@
   // The width of the portion of the text that is unaffected by whitespace
   // collapsing.
   base::optional<LayoutUnit> non_collapsible_text_width_;
-
-  // Glyph buffer caching is used to prevent it from needing to be recalculated
-  // during each call to RenderAndAnimateContent. It is mutable as a result of
-  // RenderAndAnimateContent being const.
-  mutable CachedGlyphBufferInfo cached_glyph_buffer_info_;
 };
 
 }  // namespace layout
diff --git a/src/cobalt/layout_tests/layout_benchmarks.cc b/src/cobalt/layout_tests/layout_benchmarks.cc
index 99e088d..164741c 100644
--- a/src/cobalt/layout_tests/layout_benchmarks.cc
+++ b/src/cobalt/layout_tests/layout_benchmarks.cc
@@ -62,9 +62,8 @@
     samples_to_gather_ = samples_to_gather;
     done_gathering_samples_.Reset();
 
-    renderer::Submission submission_with_callback(
-        layout_results.render_tree, layout_results.animations,
-        layout_results.layout_time);
+    renderer::Submission submission_with_callback(layout_results.render_tree,
+                                                  layout_results.layout_time);
     submission_with_callback.on_rasterized_callback = base::Bind(
         &RendererBenchmarkRunner::OnSubmitComplete, base::Unretained(this));
 
@@ -156,7 +155,7 @@
   layout_samples_[layout::kBenchmarkStatUpdateCrossReferences];
   layout_samples_[layout::kBenchmarkStatUpdateUsedSizes];
   layout_samples_[layout::kBenchmarkStatRenderAndAnimate];
-  renderer_samples_["NodeAnimationsMap::Apply()"];
+  renderer_samples_["AnimateNode::Apply()"];
   renderer_samples_["VisitRenderTree"];
   renderer_samples_["Skia Flush"];
 }
diff --git a/src/cobalt/layout_tests/layout_snapshot.cc b/src/cobalt/layout_tests/layout_snapshot.cc
index b07abfc..97b7689 100644
--- a/src/cobalt/layout_tests/layout_snapshot.cc
+++ b/src/cobalt/layout_tests/layout_snapshot.cc
@@ -41,8 +41,7 @@
     base::optional<browser::WebModule::LayoutResults>* out_results,
     base::RunLoop* run_loop, MessageLoop* message_loop,
     const browser::WebModule::LayoutResults& results) {
-  out_results->emplace(results.render_tree, results.animations,
-                       results.layout_time);
+  out_results->emplace(results.render_tree, results.layout_time);
   message_loop->PostTask(FROM_HERE, base::Bind(Quit, run_loop));
 }
 
diff --git a/src/cobalt/layout_tests/layout_tests.cc b/src/cobalt/layout_tests/layout_tests.cc
index 5a822d1..9ceb258 100644
--- a/src/cobalt/layout_tests/layout_tests.cc
+++ b/src/cobalt/layout_tests/layout_tests.cc
@@ -24,6 +24,7 @@
 #include "cobalt/layout_tests/layout_snapshot.h"
 #include "cobalt/layout_tests/test_parser.h"
 #include "cobalt/math/size.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 #include "cobalt/renderer/render_tree_pixel_tester.h"
 #include "googleurl/src/gurl.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -88,8 +89,13 @@
   browser::WebModule::LayoutResults layout_results = SnapshotURL(
       GetParam().url, viewport_size, pixel_tester.GetResourceProvider());
 
-  bool results = pixel_tester.TestTree(layout_results.render_tree,
-                                       GetParam().base_file_path);
+  render_tree::animations::AnimateNode* animated_node =
+      base::polymorphic_downcast<render_tree::animations::AnimateNode*>(
+          layout_results.render_tree.get());
+
+  bool results =
+      pixel_tester.TestTree(animated_node->Apply(layout_results.layout_time),
+                            GetParam().base_file_path);
   EXPECT_TRUE(results);
 
   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kRebaseline) ||
diff --git a/src/cobalt/layout_tests/web_platform_tests.cc b/src/cobalt/layout_tests/web_platform_tests.cc
index 42dbc90..0c28e1a 100644
--- a/src/cobalt/layout_tests/web_platform_tests.cc
+++ b/src/cobalt/layout_tests/web_platform_tests.cc
@@ -123,8 +123,7 @@
     base::optional<browser::WebModule::LayoutResults>* out_results,
     base::RunLoop* run_loop, MessageLoop* message_loop,
     const browser::WebModule::LayoutResults& results) {
-  out_results->emplace(results.render_tree, results.animations,
-                       results.layout_time);
+  out_results->emplace(results.render_tree, results.layout_time);
   message_loop->PostTask(FROM_HERE, base::Bind(Quit, run_loop));
 }
 
diff --git a/src/cobalt/media/sandbox/media_sandbox.cc b/src/cobalt/media/sandbox/media_sandbox.cc
index e3859b0..4f3a1a3 100644
--- a/src/cobalt/media/sandbox/media_sandbox.cc
+++ b/src/cobalt/media/sandbox/media_sandbox.cc
@@ -24,7 +24,7 @@
 #include "cobalt/math/size.h"
 #include "cobalt/math/size_f.h"
 #include "cobalt/network/network_module.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 #include "cobalt/render_tree/image_node.h"
 #include "cobalt/render_tree/resource_provider.h"
 #include "cobalt/renderer/pipeline.h"
@@ -85,7 +85,7 @@
   renderer_module_.reset(
       new renderer::RendererModule(system_window_.get(), renderer_options));
   MediaModule::Options media_module_options;
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   // Use string literals directly to avoid dependency on browser::switches.
   if (command_line->HasSwitch("audio_decoder_stub")) {
@@ -97,7 +97,7 @@
   if (command_line->HasSwitch("video_decoder_stub")) {
     media_module_options.use_video_decoder_stub = true;
   }
-#endif  // defined(ENABLE_COMMAND_LINE_SWITCHES)
+#endif  // defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 
   media_module_ =
       MediaModule::Create(renderer_module_->render_target()->GetSize(),
@@ -124,16 +124,15 @@
 void MediaSandbox::Impl::SetupAndSubmitScene() {
     scoped_refptr<render_tree::ImageNode> image_node =
         new render_tree::ImageNode(NULL);
-    render_tree::animations::NodeAnimationsMap::Builder
-        node_animations_map_builder;
+    render_tree::animations::AnimateNode::Builder animate_node_builder;
 
-    node_animations_map_builder.Add(
+    animate_node_builder.Add(
         image_node, base::Bind(&Impl::AnimateCB, base::Unretained(this)));
 
-    renderer_module_->pipeline()->Submit(renderer::Submission(
-        image_node, new render_tree::animations::NodeAnimationsMap(
-                        node_animations_map_builder.Pass()),
-        base::TimeDelta()));
+    renderer_module_->pipeline()->Submit(
+        renderer::Submission(new render_tree::animations::AnimateNode(
+                                 animate_node_builder, image_node),
+                             base::TimeDelta()));
 }
 
 MediaSandbox::MediaSandbox(int argc, char** argv,
diff --git a/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc b/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc
index b5ab128..724287e 100644
--- a/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc
+++ b/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc
@@ -192,9 +192,11 @@
     scoped_ptr<ShellRawVideoDecoder> decoder =
         media_sandbox_->GetMediaModule()->GetRawVideoDecoderFactory()->Create(
             demuxer->config(), NULL, false);
-    DCHECK(decoder);
-    VideoDecoderFuzzer decoder_fuzzer(fuzzing_content, demuxer, decoder.get());
-    decoder_fuzzer.Fuzz();
+    if (decoder) {
+      VideoDecoderFuzzer decoder_fuzzer(fuzzing_content, demuxer,
+                                        decoder.get());
+      decoder_fuzzer.Fuzz();
+    }
   }
 
  private:
diff --git a/src/cobalt/media/shell_media_platform_starboard.cc b/src/cobalt/media/shell_media_platform_starboard.cc
index 6278203..096b670 100644
--- a/src/cobalt/media/shell_media_platform_starboard.cc
+++ b/src/cobalt/media/shell_media_platform_starboard.cc
@@ -57,7 +57,8 @@
               kGPUMemoryBufferBudget);
     gpu_memory_pool_.reset(new nb::MemoryPool(
         gpu_memory_buffer_space_->GetMemory(),
-        gpu_memory_buffer_space_->GetSizeInBytes(), true /* thread_safe */));
+        gpu_memory_buffer_space_->GetSizeInBytes(), true, /* thread_safe */
+        true /* verify_full_capacity */));
   }
 
   DCHECK_LE(0, kMainMemoryBufferBudget > 0);
@@ -66,7 +67,8 @@
   DCHECK(main_memory_buffer_space_);
   main_memory_pool_.reset(new nb::MemoryPool(main_memory_buffer_space_.get(),
                                              kMainMemoryBufferBudget,
-                                             true /* thread_safe */));
+                                             true, /* thread_safe */
+                                             true /* verify_full_capacity */));
 
   ShellBufferFactory::Initialize();
   ShellAudioStreamer::Initialize();
diff --git a/src/cobalt/media/shell_video_data_allocator_common.cc b/src/cobalt/media/shell_video_data_allocator_common.cc
index be0107b..de8af74 100644
--- a/src/cobalt/media/shell_video_data_allocator_common.cc
+++ b/src/cobalt/media/shell_video_data_allocator_common.cc
@@ -89,29 +89,30 @@
   // TODO: Ensure it work with visible_rect with non-zero left and
   // top.  Note that simply add offset to the image buffer may cause alignment
   // issues.
-  gfx::Size visible_size(param.visible_rect().size());
+  gfx::Size plane_size(param.visible_rect().size());
 
   // Create image data descriptor for the frame in I420.
   MultiPlaneImageDataDescriptor descriptor(
       kMultiPlaneImageFormatYUV3PlaneBT709);
   descriptor.AddPlane(
       param.y_data() - frame_buffer->data(),
-      ImageDataDescriptor(visible_size, kPixelFormatY8,
+      ImageDataDescriptor(plane_size, kPixelFormatY8,
                           kAlphaFormatUnpremultiplied, param.y_pitch()));
-  visible_size.SetSize(visible_size.width() / 2, visible_size.height() / 2);
+  plane_size.SetSize(plane_size.width() / 2, plane_size.height() / 2);
   descriptor.AddPlane(
       param.u_data() - frame_buffer->data(),
-      ImageDataDescriptor(visible_size, kPixelFormatU8,
+      ImageDataDescriptor(plane_size, kPixelFormatU8,
                           kAlphaFormatUnpremultiplied, param.uv_pitch()));
   descriptor.AddPlane(
       param.v_data() - frame_buffer->data(),
-      ImageDataDescriptor(visible_size, kPixelFormatV8,
+      ImageDataDescriptor(plane_size, kPixelFormatV8,
                           kAlphaFormatUnpremultiplied, param.uv_pitch()));
 
   scoped_refptr<Image> image =
       resource_provider_->CreateMultiPlaneImageFromRawMemory(
           frame_buffer_common->DetachRawImageMemory(), descriptor);
 
+  gfx::Size visible_size(param.visible_rect().size());
   // The reference of the image is held by the closure that binds ReleaseImage,
   // so it won't be freed before the ReleaseImage is called.
   scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapNativeTexture(
@@ -130,7 +131,7 @@
   // TODO: Ensure it work with visible_rect with non-zero left and
   // top.  Note that simply add offset to the image buffer may cause alignment
   // issues.
-  gfx::Size visible_size(param.visible_rect().size());
+  gfx::Size plane_size(param.visible_rect().size());
 
   intptr_t offset = 0;
   int pitch_in_bytes = param.y_pitch();
@@ -141,12 +142,12 @@
   MultiPlaneImageDataDescriptor descriptor(
       kMultiPlaneImageFormatYUV2PlaneBT709);
   descriptor.AddPlane(
-      offset, ImageDataDescriptor(visible_size, kPixelFormatY8,
+      offset, ImageDataDescriptor(plane_size, kPixelFormatY8,
                                   kAlphaFormatPremultiplied, pitch_in_bytes));
   offset += pitch_in_bytes * param.decoded_height();
-  visible_size.SetSize(visible_size.width() / 2, visible_size.height() / 2);
+  plane_size.SetSize(plane_size.width() / 2, plane_size.height() / 2);
   descriptor.AddPlane(
-      offset, ImageDataDescriptor(visible_size, kPixelFormatUV8,
+      offset, ImageDataDescriptor(plane_size, kPixelFormatUV8,
                                   kAlphaFormatPremultiplied, pitch_in_bytes));
   offset += pitch_in_bytes * param.decoded_height() / 2;
   DCHECK_EQ(offset, pitch_in_bytes * param.decoded_height() * 3 / 2);
@@ -155,6 +156,7 @@
       resource_provider_->CreateMultiPlaneImageFromRawMemory(
           frame_buffer_common->DetachRawImageMemory(), descriptor);
 
+  gfx::Size visible_size(param.visible_rect().size());
   // The reference of the image is held by the closure that binds ReleaseImage,
   // so it won't be freed before the ReleaseImage is called.
   scoped_refptr<VideoFrame> video_frame = VideoFrame::WrapNativeTexture(
diff --git a/src/cobalt/media/shell_video_data_allocator_common.h b/src/cobalt/media/shell_video_data_allocator_common.h
index 03cdbfa..9673ded 100644
--- a/src/cobalt/media/shell_video_data_allocator_common.h
+++ b/src/cobalt/media/shell_video_data_allocator_common.h
@@ -53,9 +53,13 @@
    public:
     explicit FrameBufferCommon(scoped_ptr<RawImageMemory> raw_image_memory);
 
-    uint8* data() const OVERRIDE { return raw_image_memory_->GetMemory(); }
+    uint8* data() const OVERRIDE {
+      return raw_image_memory_ ? raw_image_memory_->GetMemory() : NULL;
+    }
 
-    size_t size() const OVERRIDE { return raw_image_memory_->GetSizeInBytes(); }
+    size_t size() const OVERRIDE {
+      return raw_image_memory_ ? raw_image_memory_->GetSizeInBytes() : 0;
+    }
 
     // Disown the image_data_.
     scoped_ptr<RawImageMemory> DetachRawImageMemory();
diff --git a/src/cobalt/network/switches.cc b/src/cobalt/network/switches.cc
index 83bb9a7..158833f 100644
--- a/src/cobalt/network/switches.cc
+++ b/src/cobalt/network/switches.cc
@@ -20,7 +20,7 @@
 namespace network {
 namespace switches {
 
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 // Log network events using Chromium's network logger. If a parameter is
 // specified, the parameter shall be interpreted as a file path and the network
 // log will be written into the file. Otherwise, logging will be written to
@@ -30,7 +30,7 @@
 // Corresponds to the levels described in the NetLog::LogLevel enum defined in
 // net/base/net_log.h
 const char kNetLogLevel[] = "net_log_level";
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
 }  // namespace switches
 }  // namespace network
diff --git a/src/cobalt/network/switches.h b/src/cobalt/network/switches.h
index 996c1d5..e95a70d 100644
--- a/src/cobalt/network/switches.h
+++ b/src/cobalt/network/switches.h
@@ -21,10 +21,10 @@
 namespace network {
 namespace switches {
 
-#if defined(ENABLE_COMMAND_LINE_SWITCHES)
+#if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 extern const char kNetLog[];
 extern const char kNetLogLevel[];
-#endif  // ENABLE_COMMAND_LINE_SWITCHES
+#endif  // ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
 }  // namespace switches
 }  // namespace network
diff --git a/src/cobalt/render_tree/animations/animate_node.cc b/src/cobalt/render_tree/animations/animate_node.cc
new file mode 100644
index 0000000..d51732a
--- /dev/null
+++ b/src/cobalt/render_tree/animations/animate_node.cc
@@ -0,0 +1,401 @@
+/*
+ * 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/render_tree/animations/animate_node.h"
+
+#include "base/debug/trace_event.h"
+#include "cobalt/base/enable_if.h"
+#include "cobalt/base/polymorphic_downcast.h"
+#include "cobalt/render_tree/child_iterator.h"
+#include "cobalt/render_tree/node_visitor.h"
+
+namespace cobalt {
+namespace render_tree {
+namespace animations {
+
+void AnimateNode::Builder::AddInternal(
+    const scoped_refptr<Node>& target_node,
+    const scoped_refptr<AnimationListBase>& animation_list) {
+  DCHECK(node_animation_map_.find(target_node) == node_animation_map_.end())
+      << "The target render tree node already has an associated animation "
+         "list.";
+
+  node_animation_map_[target_node.get()] = animation_list;
+  node_refs_.push_back(target_node);
+}
+
+void AnimateNode::Builder::Merge(const AnimateNode::Builder& other) {
+#if !defined(NDEBUG)
+  for (InternalMap::const_iterator iter = node_animation_map_.begin();
+       iter != node_animation_map_.end(); ++iter) {
+    DCHECK(other.node_animation_map_.find(iter->first) ==
+           other.node_animation_map_.end())
+        << "Only mutually exclusive AnimateNode::Builders can be merged!";
+  }
+#endif
+  node_animation_map_.insert(other.node_animation_map_.begin(),
+                             other.node_animation_map_.end());
+  node_refs_.insert(node_refs_.end(), other.node_refs_.begin(),
+                    other.node_refs_.end());
+}
+
+// A helper render tree visitor class used to compile sub render-tree
+// animations.  The same instance of the TraverseListBuilder class is reused for
+// traversing all nodes in a tree.  After visiting a render tree,
+// |traverse_list_| will contain a post-order traversal of animated nodes where
+// children are visited from right to left, and this should be reversed to
+// obtain a pre-order traversal of animated nodes where children are visited
+// from left to right, which is much more natural.
+class AnimateNode::TraverseListBuilder : public NodeVisitor {
+ public:
+  TraverseListBuilder(const AnimateNode::Builder::InternalMap& animation_map,
+                      TraverseList* traverse_list)
+      : animation_map_(animation_map), traverse_list_(traverse_list) {}
+
+  void Visit(animations::AnimateNode* animate) OVERRIDE;
+  void Visit(CompositionNode* composition) OVERRIDE { VisitNode(composition); }
+  void Visit(FilterNode* text) OVERRIDE { VisitNode(text); }
+  void Visit(ImageNode* image) OVERRIDE { VisitNode(image); }
+  void Visit(MatrixTransformNode* transform) OVERRIDE { VisitNode(transform); }
+  void Visit(PunchThroughVideoNode* punch_through) OVERRIDE {
+    VisitNode(punch_through);
+  }
+  void Visit(RectNode* rect) OVERRIDE { VisitNode(rect); }
+  void Visit(RectShadowNode* rect) OVERRIDE { VisitNode(rect); }
+  void Visit(TextNode* text) OVERRIDE { VisitNode(text); }
+
+ private:
+  template <typename T>
+  typename base::enable_if<!ChildIterator<T>::has_children>::type VisitNode(
+      T* node);
+
+  template <typename T>
+  typename base::enable_if<ChildIterator<T>::has_children>::type VisitNode(
+      T* node);
+  void ProcessNode(Node* node, bool animated_children);
+
+  // Adds a node to |traverse_list_|, indicating that it or its descendants are
+  // involved in animation.
+  void AddToTraverseList(
+      Node* node, AnimateNode::Builder::InternalMap::const_iterator found);
+
+  // A reference to the mapping from render tree node to animations.
+  const AnimateNode::Builder::InternalMap& animation_map_;
+
+  // A list of nodes that, if reversed, gives a pre-order traversal of only
+  // animated nodes.
+  // |traverse_list_| is the primary output of this visitor class.
+  TraverseList* traverse_list_;
+
+  // Signals to the caller of Visit() that this node was animated and so any
+  // parent nodes should also be added to the traversal list.
+  bool animated_;
+
+  // If non-null, references a node that this visitor's parent should replace
+  // this visitor's associated node with in its list of child nodes.
+  scoped_refptr<Node> replace_with_;
+
+  friend class AnimateNode;
+};
+
+void AnimateNode::TraverseListBuilder::Visit(animations::AnimateNode* animate) {
+  if (!animate->traverse_list_.empty()) {
+    // We merge all the information from this AnimateNode into the one we are
+    // constructing now.  Simply append the sub-AnimateNode to |traverse_list_|,
+    // but reverse it so its finalized pre-order, left to right traversal is
+    // switched to the intermediate format of a post-order, right to left
+    // traversal.
+    size_t start_size = traverse_list_->size();
+    traverse_list_->insert(traverse_list_->end(),
+                           animate->traverse_list_.begin(),
+                           animate->traverse_list_.end());
+    std::reverse(traverse_list_->begin() + static_cast<int64>(start_size),
+                 traverse_list_->end());
+    animated_ = true;
+  } else {
+    animated_ = false;
+  }
+
+  // Now that we have merged the sub-AnimateNode's information with the one
+  // under construction, remove this AnimateNode from the tree in order to
+  // maintain the invariant that an AnimateNode does not contain any
+  // AnimateNode descendants.
+  replace_with_ = animate->source_;
+}
+
+template <typename T>
+typename base::enable_if<!ChildIterator<T>::has_children>::type
+AnimateNode::TraverseListBuilder::VisitNode(T* node) {
+  // If we are dealing with a render tree node that has no children, all we
+  // need to do is call ProcessNode().
+  animated_ = false;
+  replace_with_ = NULL;
+  ProcessNode(node, false);
+}
+
+template <typename T>
+typename base::enable_if<ChildIterator<T>::has_children>::type
+AnimateNode::TraverseListBuilder::VisitNode(T* node) {
+  ChildIterator<T> child_iterator(node, kChildIteratorDirectionBackwards);
+  bool modified_children = false;
+  bool animated_children = false;
+  while (Node* child = child_iterator.GetCurrent()) {
+    child->Accept(this);
+
+    // Mark us as animated if any of our children are animated, so that we make
+    // sure to add ourselves to |traverse_list_|.
+    animated_children |= animated_;
+
+    if (replace_with_) {
+      // If the child node wishes to replace itself with a new node, then
+      // replace it within its parent's child list.
+      child_iterator.ReplaceCurrent(replace_with_);
+      modified_children = true;
+    }
+
+    child_iterator.Next();
+  }
+
+  if (modified_children) {
+    replace_with_ = new T(child_iterator.TakeReplacedChildrenBuilder());
+  } else {
+    replace_with_ = NULL;
+  }
+
+  // Finally, add this node to |traverse_list_| if it is animated either
+  // directly or indirectly (i.e. because its children are animated).
+  animated_ = false;
+  ProcessNode(node, animated_children);
+}
+
+void AnimateNode::TraverseListBuilder::ProcessNode(Node* node,
+                                                   bool animated_children) {
+  // If this node is animated, add it to the |traverse_list_|.
+  AnimateNode::Builder::InternalMap::const_iterator found =
+      animation_map_.find(node);
+  if (animated_children || found != animation_map_.end()) {
+    AddToTraverseList(replace_with_ ? replace_with_.get() : node, found);
+  }
+}
+
+// Adds a node to |traverse_list_| so that it can be quickly
+// found in the future.
+void AnimateNode::TraverseListBuilder::AddToTraverseList(
+    Node* node, AnimateNode::Builder::InternalMap::const_iterator found) {
+  if (found != animation_map_.end()) {
+    traverse_list_->push_back(TraverseListEntry(node, found->second));
+  } else {
+    traverse_list_->push_back(TraverseListEntry(node));
+  }
+  animated_ = true;
+}
+
+// A helper render tree visitor class used to apply compiled sub render-tree
+// animations.  Only one of these visitors is needed to visit an entire render
+// tree.
+class AnimateNode::ApplyVisitor : public NodeVisitor {
+ public:
+  ApplyVisitor(const TraverseList& traverse_list, base::TimeDelta time_offset);
+
+  void Visit(animations::AnimateNode* /* animate */) OVERRIDE {
+    // An invariant of AnimateNodes is that they should never contain descendant
+    // AnimateNodes.
+    NOTREACHED();
+  }
+  // Immediately switch to a templated visitor function.
+  void Visit(CompositionNode* composition) OVERRIDE { VisitNode(composition); }
+  void Visit(FilterNode* text) OVERRIDE { VisitNode(text); }
+  void Visit(ImageNode* image) OVERRIDE { VisitNode(image); }
+  void Visit(MatrixTransformNode* transform) OVERRIDE { VisitNode(transform); }
+  void Visit(PunchThroughVideoNode* punch_through) OVERRIDE {
+    VisitNode(punch_through);
+  }
+  void Visit(RectNode* rect) OVERRIDE { VisitNode(rect); }
+  void Visit(RectShadowNode* rect) OVERRIDE { VisitNode(rect); }
+  void Visit(TextNode* text) OVERRIDE { VisitNode(text); }
+
+  // Returns the animated version of the node last visited.  This is how the
+  // final animated result can be pulled from this visitor.
+  const scoped_refptr<Node>& animated() const { return animated_; }
+
+ private:
+  template <typename T>
+  typename base::enable_if<!ChildIterator<T>::has_children>::type VisitNode(
+      T* node);
+  template <typename T>
+  typename base::enable_if<ChildIterator<T>::has_children>::type VisitNode(
+      T* node);
+  template <typename T>
+  void ApplyAnimations(const TraverseListEntry& entry,
+                       typename T::Builder* builder);
+  TraverseListEntry AdvanceIterator(Node* node);
+
+  // The time offset to be passed in to individual animations.
+  base::TimeDelta time_offset_;
+  // The animated version of the last node visited.
+  scoped_refptr<Node> animated_;
+  // A list of nodes that we are allowed to traverse into (i.e. a traversal that
+  // guides us to animated nodes).  It assumes that a pre-order traversal will
+  // be taken.
+  const TraverseList& traverse_list_;
+  // An iterator pointing to the next valid render tree node to visit.
+  TraverseList::const_iterator iterator_;
+};
+
+AnimateNode::ApplyVisitor::ApplyVisitor(const TraverseList& traverse_list,
+                                        base::TimeDelta time_offset)
+    : time_offset_(time_offset), traverse_list_(traverse_list) {
+  iterator_ = traverse_list_.begin();
+}
+
+template <typename T>
+typename base::enable_if<!ChildIterator<T>::has_children>::type
+AnimateNode::ApplyVisitor::VisitNode(T* node) {
+  TraverseListEntry current_entry = AdvanceIterator(node);
+  // If we don't have any children, then for this node to be visited, we must
+  // have animations.
+  DCHECK(current_entry.animations);
+  typename T::Builder builder(node->data());
+  ApplyAnimations<T>(current_entry, &builder);
+  animated_ = new T(builder);
+}
+
+template <typename T>
+typename base::enable_if<ChildIterator<T>::has_children>::type
+AnimateNode::ApplyVisitor::VisitNode(T* node) {
+  TraverseListEntry current_entry = AdvanceIterator(node);
+
+  // Traverse the child nodes, but only the ones that are on the
+  // |traverse_list_|.  In particular, the next node we are allowed to visit
+  // is the one in the traverse list pointed to by |iterator_->node|.
+  ChildIterator<T> child_iterator(node);
+  bool children_modified = false;
+  while (Node* child = child_iterator.GetCurrent()) {
+    if (iterator_ == traverse_list_.end()) {
+      // If we've reached the end of |traverse_list_| then we are done
+      // iterating and it's time to return.
+      break;
+    }
+
+    if (child == iterator_->node) {
+      // If one of our children is next up on the path to animation, traverse
+      // into it.
+      child->Accept(this);
+      // Traversing into the child means that it was animated, and so replaced
+      // by an animated node while it was visited.  Thus, replace it in the
+      // current node's child list with its animated version.
+      child_iterator.ReplaceCurrent(animated_);
+      children_modified = true;
+    }
+
+    child_iterator.Next();
+  }
+
+  if (current_entry.animations) {
+    base::optional<typename T::Builder> builder;
+    if (children_modified) {
+      // Reuse the modified Builder object from child traversal if one of
+      // our children was animated.
+      builder.emplace(child_iterator.TakeReplacedChildrenBuilder());
+    } else {
+      // Create a fresh copy of the Builder object for this animated node, to
+      // be passed into the animations.
+      builder.emplace(node->data());
+    }
+    ApplyAnimations<T>(current_entry, &(*builder));
+    animated_ = new T(*builder);
+  } else {
+    // If there were no animations targeting this node directly, then its
+    // children must have been modified since otherwise it wouldn't be in
+    // the traverse list.
+    DCHECK(children_modified);
+    animated_ = new T(child_iterator.TakeReplacedChildrenBuilder());
+  }
+}
+
+template <typename T>
+void AnimateNode::ApplyVisitor::ApplyAnimations(const TraverseListEntry& entry,
+                                                typename T::Builder* builder) {
+  TRACE_EVENT0("cobalt::renderer",
+               "AnimateNode::ApplyVisitor::ApplyAnimations()");
+  // Cast to the specific type we expect these animations to have.
+  const AnimationList<T>* typed_node_animations =
+      base::polymorphic_downcast<const AnimationList<T>*>(
+          entry.animations.get());
+
+  // Iterate through each animation applying them one at a time.
+  for (typename AnimationList<T>::InternalList::const_iterator iter =
+           typed_node_animations->data().animations.begin();
+       iter != typed_node_animations->data().animations.end(); ++iter) {
+    iter->Run(builder, time_offset_);
+  }
+}
+
+AnimateNode::TraverseListEntry AnimateNode::ApplyVisitor::AdvanceIterator(
+    Node* node) {
+  // Check that the iterator that we are advancing past is indeed the one we
+  // expect it to be.
+  DCHECK_EQ(node, iterator_->node);
+  return *(iterator_++);
+}
+
+AnimateNode::AnimateNode(const Builder& builder,
+                         const scoped_refptr<Node>& source) {
+  TRACE_EVENT0("cobalt::renderer", "AnimateNode::AnimateNode(builder, source)");
+  CommonInit(builder.node_animation_map_, source);
+}
+
+AnimateNode::AnimateNode(const scoped_refptr<Node>& source) {
+  TRACE_EVENT0("cobalt::renderer", "AnimateNode::AnimateNode(source)");
+  CommonInit(Builder::InternalMap(), source);
+}
+
+scoped_refptr<Node> AnimateNode::Apply(base::TimeDelta time_offset) {
+  TRACE_EVENT0("cobalt::renderer", "AnimateNode::Apply()");
+  if (traverse_list_.empty()) {
+    return source_;
+  } else {
+    ApplyVisitor apply_visitor(traverse_list_, time_offset);
+    source_->Accept(&apply_visitor);
+    return apply_visitor.animated();
+  }
+}
+
+void AnimateNode::CommonInit(const Builder::InternalMap& node_animation_map,
+                             const scoped_refptr<Node>& source) {
+  TraverseListBuilder traverse_list_builder(node_animation_map,
+                                            &traverse_list_);
+  source->Accept(&traverse_list_builder);
+
+  if (traverse_list_builder.replace_with_) {
+    source_ = traverse_list_builder.replace_with_;
+  } else {
+    source_ = source;
+  }
+
+  if (!traverse_list_.empty()) {
+    // We must adjust the resulting |traverse_list_| from an awkward
+    // intermediate format of post-order right to left traversal to the more
+    // natural pre-order left to right traversal expected by ApplyVisitor.
+    // This can be done by simply reversing the list.
+    std::reverse(traverse_list_.begin(), traverse_list_.end());
+    DCHECK(source_.get() == traverse_list_.begin()->node);
+  }
+}
+
+}  // namespace animations
+}  // namespace render_tree
+}  // namespace cobalt
diff --git a/src/cobalt/render_tree/animations/animate_node.h b/src/cobalt/render_tree/animations/animate_node.h
new file mode 100644
index 0000000..4b9bfae
--- /dev/null
+++ b/src/cobalt/render_tree/animations/animate_node.h
@@ -0,0 +1,177 @@
+/*
+ * 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_RENDER_TREE_ANIMATIONS_ANIMATE_NODE_H_
+#define COBALT_RENDER_TREE_ANIMATIONS_ANIMATE_NODE_H_
+
+#include <map>
+#include <vector>
+
+#include "base/containers/small_map.h"
+#include "base/memory/ref_counted.h"
+#include "cobalt/render_tree/animations/animation_list.h"
+#include "cobalt/render_tree/movable.h"
+#include "cobalt/render_tree/node.h"
+#include "cobalt/render_tree/node_visitor.h"
+
+namespace cobalt {
+namespace render_tree {
+namespace animations {
+
+// An AnimateNode describes a set of animations that affect the subtree attached
+// to the AnimateNode.  In order to create an AnimateNode, one must first
+// populate an AnimateNode::Builder with a mapping of render tree node
+// references to corresponding animations that should be applied to them.
+// Construction of an AnimateNode object requires a populated
+// AnimateNode::Builder instance as well as the sub-tree that the animations
+// apply to.  Upon construction, AnimateNode will compile the set of animated
+// nodes into a format specialized to the associated subtree such that it is
+// much faster to apply the animations.  Once an AnimateNode is constructed,
+// it can generate static render trees representing frames of animation via
+// calls to AnimateNode::Apply(), which returns a static render tree.
+// When AnimateNodes are constructed they maintain an invariant that
+// AnimateNodes never have other AnimateNodes as descendants.  It does this
+// by traversing the subtree on construction and if another AnimateNode is
+// encountered, its information is merged into this root AnimateNode, and the
+// sub-AnimateNode is removed from the tree.
+class AnimateNode : public Node {
+ public:
+  // Manages a mapping of render tree nodes to corresponding animations.  Users
+  // of AnimateNode should populate the Builder with animations and then use
+  // that to construct the AnimateNode.
+  class Builder {
+   public:
+    DECLARE_AS_MOVABLE(Builder);
+
+    Builder() {}
+    explicit Builder(Moved moved) {
+      node_animation_map_ = moved->node_animation_map_;
+      node_refs_.swap(moved->node_refs_);
+    }
+
+    // This method is a template so that we can ensure that animations are not
+    // mismatched with render tree nodes of the wrong type.
+    template <typename T>
+    void Add(const scoped_refptr<T>& target_node,
+             const scoped_refptr<AnimationList<T> >& animation_list) {
+      AddInternal(target_node, animation_list);
+    }
+
+    // Convenience method to attach a single animation to a target node.
+    template <typename T>
+    void Add(const scoped_refptr<T>& target_node,
+             const typename Animation<T>::Function& single_animation) {
+      AddInternal(target_node, scoped_refptr<AnimationListBase>(
+                                   new AnimationList<T>(single_animation)));
+    }
+
+    // Merge all mappings from another AnimateNode::Builder into this one.
+    // There cannot be any keys that are in both the merge target and source.
+    void Merge(const Builder& other);
+
+    // Returns true if there are no animations added to this
+    // AnimateNode::Builder.
+    bool empty() const { return node_animation_map_.empty(); }
+
+   private:
+    // A non-template function that contains the logic for storing a target
+    // node and animation list pair.
+    void AddInternal(const scoped_refptr<Node>& target_node,
+                     const scoped_refptr<AnimationListBase>& animation_list);
+
+    // The primary internal data structure used to organize and store the
+    // mapping between target render tree node and animation list.
+    // In many cases there are not many active animations, and so we use a
+    // base::SmallMap for this.  std::map was found to be more performant than
+    // base::hash_map, so it is used as the fallback map.
+    typedef base::SmallMap<std::map<Node*, scoped_refptr<AnimationListBase> >,
+                           4> InternalMap;
+    InternalMap node_animation_map_;
+    std::vector<scoped_refptr<Node> > node_refs_;
+
+    friend class AnimateNode;
+  };
+
+  AnimateNode(const Builder& builder, const scoped_refptr<Node>& source);
+
+  // This will create an AnimateNode with no animations.  It is useful because
+  // construction of AnimateNodes maintain an invariant that there are no
+  // sub-AnimateNodes underneath them.  Thus, adding a AnimateNode, even if it
+  // has no animations, to an existing tree will result in existing AnimateNodes
+  // being merged into the new root AnimateNode, which can simplify the
+  // underlying tree.
+  explicit AnimateNode(const scoped_refptr<Node>& source);
+
+  // Cannot visit this node.
+  void Accept(NodeVisitor* visitor) OVERRIDE { visitor->Visit(this); }
+
+  // Since we don't have any bounds on the animations contained in this tree,
+  // we cannot know the bounds of the tree over all time.  Indeed animations
+  // may not have any bounds as time goes to infinity.  Despite this, we return
+  // the bounds of the initial render tree to enable AnimateNodes to be setup
+  // as children of CompositionNodes.
+  math::RectF GetBounds() const OVERRIDE { return source_->GetBounds(); }
+
+  base::TypeId GetTypeId() const OVERRIDE {
+    return base::GetTypeId<AnimateNode>();
+  }
+
+  // Apply the animations to the sub render tree with the given |time_offset|.
+  // An animated sub-tree is returned, which is guaranteed to not contain any
+  // AnimateNodes.
+  scoped_refptr<Node> Apply(base::TimeDelta time_offset);
+
+  // Returns the sub-tree for which the animations apply to.
+  const scoped_refptr<Node> source() const { return source_; }
+
+ private:
+  // A helper render tree visitor class used to compile sub render-tree
+  // animations.
+  class TraverseListBuilder;
+  // A helper render tree visitor class used to apply compiled sub render-tree
+  // animations.  This class follows the traversal generated by
+  // TraverseListBuilder.
+  class ApplyVisitor;
+
+  void CommonInit(const Builder::InternalMap& node_animation_map,
+                  const scoped_refptr<Node>& source);
+
+  // The compiled node animation list is a sequence of nodes that are either
+  // animated themselves, or on the path to an animated node.  Only nodes in
+  // this sequence need to be traversed.  TraverseListEntry is an entry in this
+  // list, complete with animations to be applied to the given node, if any.
+  struct TraverseListEntry {
+    TraverseListEntry(Node* node,
+                      const scoped_refptr<AnimationListBase>& animations)
+        : node(node), animations(animations) {}
+    explicit TraverseListEntry(Node* node) : node(node) {}
+
+    Node* node;
+    scoped_refptr<AnimationListBase> animations;
+  };
+  typedef std::vector<TraverseListEntry> TraverseList;
+
+  // The compiled traversal list through the sub-tree represented by |source_|
+  // that guides us towards all nodes that need to be animated.
+  TraverseList traverse_list_;
+  scoped_refptr<Node> source_;
+};
+
+}  // namespace animations
+}  // namespace render_tree
+}  // namespace cobalt
+
+#endif  // COBALT_RENDER_TREE_ANIMATIONS_ANIMATE_NODE_H_
diff --git a/src/cobalt/render_tree/animations/node_animations_map_test.cc b/src/cobalt/render_tree/animations/animate_node_test.cc
similarity index 67%
rename from src/cobalt/render_tree/animations/node_animations_map_test.cc
rename to src/cobalt/render_tree/animations/animate_node_test.cc
index 5e45af5..f46e63e 100644
--- a/src/cobalt/render_tree/animations/node_animations_map_test.cc
+++ b/src/cobalt/render_tree/animations/animate_node_test.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Google Inc. All Rights Reserved.
+ * 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.
@@ -21,7 +21,7 @@
 #include "cobalt/math/rect_f.h"
 #include "cobalt/math/size_f.h"
 #include "cobalt/math/transform_2d.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 #include "cobalt/render_tree/brush.h"
 #include "cobalt/render_tree/color_rgba.h"
 #include "cobalt/render_tree/composition_node.h"
@@ -46,12 +46,12 @@
 // Helper function to create an animation set for a render tree that consists
 // of only one animation targeting only one node in the render tree.
 template <typename T>
-scoped_refptr<NodeAnimationsMap> CreateSingleAnimation(
+scoped_refptr<AnimateNode> CreateSingleAnimation(
     const scoped_refptr<T>& target,
     typename Animation<T>::Function anim_function) {
-  NodeAnimationsMap::Builder animations_builder;
+  AnimateNode::Builder animations_builder;
   animations_builder.Add(target, anim_function);
-  return new NodeAnimationsMap(animations_builder.Pass());
+  return new AnimateNode(animations_builder, target);
 }
 
 class ImageFake : public Image {
@@ -68,16 +68,16 @@
   UNREFERENCED_PARAMETER(time_elapsed);
   text_node->color = ColorRGBA(.5f, .5f, .5f);
 }
-TEST(NodeAnimationsMapTest, EnsureSingleTextNodeAnimates) {
+TEST(AnimateNodeTest, EnsureSingleTextNodeAnimates) {
   scoped_refptr<TextNode> text_node(
       new TextNode(math::Vector2dF(0, 0), new GlyphBuffer(RectF(0, 0, 1, 1)),
                    ColorRGBA(1.0f, 1.0f, 1.0f)));
 
-  scoped_refptr<NodeAnimationsMap> animations =
+  scoped_refptr<AnimateNode> with_animations =
       CreateSingleAnimation(text_node, base::Bind(&AnimateText));
 
   scoped_refptr<Node> animated_render_tree =
-      animations->Apply(text_node, base::TimeDelta::FromSeconds(1));
+      with_animations->Apply(base::TimeDelta::FromSeconds(1));
   TextNode* animated_text_node =
       dynamic_cast<TextNode*>(animated_render_tree.get());
   EXPECT_TRUE(animated_text_node);
@@ -89,15 +89,15 @@
   UNREFERENCED_PARAMETER(time_elapsed);
   image_node->destination_rect = RectF(2.0f, 2.0f);
 }
-TEST(NodeAnimationsMapTest, EnsureSingleImageNodeAnimates) {
+TEST(AnimateNodeTest, EnsureSingleImageNodeAnimates) {
   scoped_refptr<ImageNode> image_node(
       new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
 
-  scoped_refptr<NodeAnimationsMap> animations =
+  scoped_refptr<AnimateNode> with_animations =
       CreateSingleAnimation(image_node, base::Bind(&AnimateImage));
 
   scoped_refptr<Node> animated_render_tree =
-      animations->Apply(image_node, base::TimeDelta::FromSeconds(1));
+      with_animations->Apply(base::TimeDelta::FromSeconds(1));
   ImageNode* animated_image_node =
       dynamic_cast<ImageNode*>(animated_render_tree.get());
   EXPECT_TRUE(animated_image_node);
@@ -109,16 +109,16 @@
   UNREFERENCED_PARAMETER(time_elapsed);
   rect_node->rect = RectF(2.0f, 2.0f);
 }
-TEST(NodeAnimationsMapTest, EnsureSingleRectNodeAnimates) {
+TEST(AnimateNodeTest, EnsureSingleRectNodeAnimates) {
   scoped_refptr<RectNode> rect_node(new RectNode(
       RectF(1.0f, 1.0f),
       scoped_ptr<Brush>(new SolidColorBrush(ColorRGBA(1.0f, 1.0f, 1.0f)))));
 
-  scoped_refptr<NodeAnimationsMap> animations =
+  scoped_refptr<AnimateNode> with_animations =
       CreateSingleAnimation(rect_node, base::Bind(&AnimateRect));
 
   scoped_refptr<Node> animated_render_tree =
-      animations->Apply(rect_node, base::TimeDelta::FromSeconds(1));
+      with_animations->Apply(base::TimeDelta::FromSeconds(1));
   RectNode* animated_rect_node =
       dynamic_cast<RectNode*>(animated_render_tree.get());
   EXPECT_TRUE(animated_rect_node);
@@ -135,33 +135,32 @@
       static_cast<float>(time_elapsed.InSecondsF()),
       static_cast<float>(time_elapsed.InSecondsF()));
 }
-TEST(NodeAnimationsMapTest,
-     SingleImageNodeAnimatesOverTimeRepeatedlyCorrectly) {
+TEST(AnimateNodeTest, SingleImageNodeAnimatesOverTimeRepeatedlyCorrectly) {
   scoped_refptr<ImageNode> image_node(
       new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
 
-  scoped_refptr<NodeAnimationsMap> animations =
+  scoped_refptr<AnimateNode> with_animations =
       CreateSingleAnimation(image_node, base::Bind(&AnimateImageAddWithTime));
 
   scoped_refptr<Node> animated_render_tree;
   ImageNode* animated_image_node;
 
   animated_render_tree =
-      animations->Apply(image_node, base::TimeDelta::FromSeconds(1));
+      with_animations->Apply(base::TimeDelta::FromSeconds(1));
   animated_image_node = dynamic_cast<ImageNode*>(animated_render_tree.get());
   EXPECT_TRUE(animated_image_node);
   EXPECT_TRUE(animated_image_node);
   EXPECT_FLOAT_EQ(3.0f, animated_image_node->data().destination_rect.width());
 
   animated_render_tree =
-      animations->Apply(image_node, base::TimeDelta::FromSeconds(2));
+      with_animations->Apply(base::TimeDelta::FromSeconds(2));
   animated_image_node = dynamic_cast<ImageNode*>(animated_render_tree.get());
   EXPECT_TRUE(animated_image_node);
   EXPECT_TRUE(animated_image_node);
   EXPECT_FLOAT_EQ(5.0f, animated_image_node->data().destination_rect.width());
 
   animated_render_tree =
-      animations->Apply(image_node, base::TimeDelta::FromSeconds(4));
+      with_animations->Apply(base::TimeDelta::FromSeconds(4));
   animated_image_node = dynamic_cast<ImageNode*>(animated_render_tree.get());
   EXPECT_TRUE(animated_image_node);
   EXPECT_TRUE(animated_image_node);
@@ -177,8 +176,7 @@
                    static_cast<float>(time_elapsed.InSecondsF()));
   image_node->destination_rect.set_size(image_size);
 }
-TEST(NodeAnimationsMapTest,
-     MultipleAnimationsTargetingOneNodeApplyInCorrectOrder) {
+TEST(AnimateNodeTest, MultipleAnimationsTargetingOneNodeApplyInCorrectOrder) {
   scoped_refptr<ImageNode> image_node(
       new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
 
@@ -192,15 +190,15 @@
   animation_list_builder.animations.push_back(
       base::Bind(&AnimateImageScaleWithTime));
 
-  NodeAnimationsMap::Builder animations_builder;
+  AnimateNode::Builder animations_builder;
   animations_builder.Add(image_node,
                          make_scoped_refptr(new AnimationList<ImageNode>(
                              animation_list_builder.Pass())));
-  scoped_refptr<NodeAnimationsMap> animations(
-      new NodeAnimationsMap(animations_builder.Pass()));
+  scoped_refptr<AnimateNode> with_animations(
+      new AnimateNode(animations_builder, image_node));
 
   scoped_refptr<Node> animated_render_tree =
-      animations->Apply(image_node, base::TimeDelta::FromSeconds(3));
+      with_animations->Apply(base::TimeDelta::FromSeconds(3));
 
   ImageNode* animated_image_node =
       dynamic_cast<ImageNode*>(animated_render_tree.get());
@@ -216,22 +214,21 @@
   UNREFERENCED_PARAMETER(time_elapsed);
   transform_node->transform = math::TranslateMatrix(2.0f, 2.0f);
 }
-TEST(NodeAnimationsMapTest, AnimatingTransformNodeDoesNotAffectSourceChild) {
+TEST(AnimateNodeTest, AnimatingTransformNodeDoesNotAffectSourceChild) {
   scoped_refptr<ImageNode> image_node(
       new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
   scoped_refptr<MatrixTransformNode> transform_node(
       new MatrixTransformNode(image_node, math::Matrix3F::Identity()));
 
-  scoped_refptr<NodeAnimationsMap> animations =
+  scoped_refptr<AnimateNode> with_animations =
       CreateSingleAnimation(transform_node, base::Bind(&AnimateTransform));
 
   scoped_refptr<Node> animated_render_tree =
-      animations->Apply(transform_node, base::TimeDelta::FromSeconds(1));
+      with_animations->Apply(base::TimeDelta::FromSeconds(1));
 
   MatrixTransformNode* animated_transform_node =
       dynamic_cast<MatrixTransformNode*>(animated_render_tree.get());
   EXPECT_TRUE(animated_transform_node);
-  EXPECT_TRUE(animated_transform_node);
 
   EXPECT_EQ(math::TranslateMatrix(2.0f, 2.0f),
             animated_transform_node->data().transform);
@@ -241,7 +238,7 @@
 // Test that animating a child correctly adjusts sub-node parameters but
 // not parent node parameters, though both child and parent are different nodes
 // now.  The animated child's sibling should be left untouched.
-TEST(NodeAnimationsMapTest,
+TEST(AnimateNodeTest,
      AnimatingCompositionChildNodeAffectsParentAsWellButNotSibling) {
   scoped_refptr<ImageNode> image_node_a(
       new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
@@ -253,11 +250,13 @@
   scoped_refptr<CompositionNode> composition_node(
       new CompositionNode(composition_node_builder.Pass()));
 
-  scoped_refptr<NodeAnimationsMap> animations =
-      CreateSingleAnimation(image_node_a, base::Bind(&AnimateImage));
+  AnimateNode::Builder animation_builder;
+  animation_builder.Add(image_node_a, base::Bind(&AnimateImage));
+  scoped_refptr<AnimateNode> with_animations =
+      new AnimateNode(animation_builder, composition_node);
 
   scoped_refptr<Node> animated_render_tree =
-      animations->Apply(composition_node, base::TimeDelta::FromSeconds(1));
+      with_animations->Apply(base::TimeDelta::FromSeconds(1));
 
   CompositionNode* animated_composition_node =
       dynamic_cast<CompositionNode*>(animated_render_tree.get());
@@ -273,6 +272,76 @@
   EXPECT_EQ(image_node_b.get(), animated_image_node_b);
 }
 
+TEST(AnimateNodeTest, SimpleSubAnimateNode) {
+  // Test that we can properly animate trees that built upon multiple
+  // AnimateNodes.
+  scoped_refptr<ImageNode> image_node(
+      new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
+  scoped_refptr<AnimateNode> image_animation =
+      CreateSingleAnimation(image_node, base::Bind(&AnimateImage));
+
+  scoped_refptr<MatrixTransformNode> transform_node(
+      new MatrixTransformNode(image_animation, math::Matrix3F::Identity()));
+
+  scoped_refptr<AnimateNode> with_animations =
+      CreateSingleAnimation(transform_node, base::Bind(&AnimateTransform));
+
+  scoped_refptr<Node> animated_render_tree =
+      with_animations->Apply(base::TimeDelta::FromSeconds(1));
+
+  MatrixTransformNode* animated_transform_node =
+      dynamic_cast<MatrixTransformNode*>(animated_render_tree.get());
+  EXPECT_TRUE(animated_transform_node);
+
+  // Check that the matrix transform node is animated.
+  EXPECT_EQ(math::TranslateMatrix(2.0f, 2.0f),
+            animated_transform_node->data().transform);
+
+  // Check also that the image node is animated.
+  ImageNode* animated_image_node =
+      dynamic_cast<ImageNode*>(animated_transform_node->data().source.get());
+  EXPECT_TRUE(animated_image_node);
+  EXPECT_EQ(RectF(2.0f, 2.0f), animated_image_node->data().destination_rect);
+}
+
+TEST(AnimateNodeTest, SubAnimateNodeWithTwoAncestors) {
+  // Test that we can properly animate trees that built upon multiple
+  // AnimateNodes.
+  scoped_refptr<ImageNode> image_node(
+      new ImageNode(make_scoped_refptr(new ImageFake()), RectF(1.0f, 1.0f)));
+  scoped_refptr<AnimateNode> image_animation =
+      CreateSingleAnimation(image_node, base::Bind(&AnimateImage));
+
+  // This node is used to make it so there is more than one node on the path
+  // between the two AnimateNodes.
+  scoped_refptr<MatrixTransformNode> transform_node_a(
+      new MatrixTransformNode(image_animation, math::Matrix3F::Identity()));
+
+  scoped_refptr<MatrixTransformNode> transform_node_b(
+      new MatrixTransformNode(transform_node_a, math::Matrix3F::Identity()));
+
+  scoped_refptr<AnimateNode> with_animations =
+      new AnimateNode(transform_node_b);
+
+  scoped_refptr<Node> animated_render_tree =
+      with_animations->Apply(base::TimeDelta::FromSeconds(1));
+
+  MatrixTransformNode* animated_transform_node =
+      dynamic_cast<MatrixTransformNode*>(animated_render_tree.get());
+  EXPECT_TRUE(animated_transform_node);
+
+  // Check that the image node is animated.
+  MatrixTransformNode* animated_dummy_transform_node =
+      dynamic_cast<MatrixTransformNode*>(
+          animated_transform_node->data().source.get());
+  EXPECT_TRUE(animated_dummy_transform_node);
+
+  ImageNode* animated_image_node = dynamic_cast<ImageNode*>(
+      animated_dummy_transform_node->data().source.get());
+  EXPECT_TRUE(animated_image_node);
+  EXPECT_EQ(RectF(2.0f, 2.0f), animated_image_node->data().destination_rect);
+}
+
 }  // namespace animations
 }  // namespace render_tree
 }  // namespace cobalt
diff --git a/src/cobalt/render_tree/animations/animation_list.h b/src/cobalt/render_tree/animations/animation_list.h
index 8c83f36..a37bd3f 100644
--- a/src/cobalt/render_tree/animations/animation_list.h
+++ b/src/cobalt/render_tree/animations/animation_list.h
@@ -67,7 +67,7 @@
   //                  base::TimeDelta::FromSeconds(1)));
   //
   // You can now create an AnimationList object from the AnimationList::Builder
-  // and ultimately add that to a NodeAnimationsMap object so that it can be
+  // and ultimately add that to a AnimateNode::Builder object so that it can be
   // mapped to a specific TextNode that it should be applied to.
   typedef base::Callback<void(typename T::Builder*, base::TimeDelta)> Function;
 };
diff --git a/src/cobalt/render_tree/animations/node_animations_map.cc b/src/cobalt/render_tree/animations/node_animations_map.cc
deleted file mode 100644
index c123536..0000000
--- a/src/cobalt/render_tree/animations/node_animations_map.cc
+++ /dev/null
@@ -1,314 +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/render_tree/animations/node_animations_map.h"
-
-#include "base/debug/trace_event.h"
-#include "base/optional.h"
-#include "cobalt/base/polymorphic_downcast.h"
-#include "cobalt/render_tree/composition_node.h"
-#include "cobalt/render_tree/filter_node.h"
-#include "cobalt/render_tree/image_node.h"
-#include "cobalt/render_tree/matrix_transform_node.h"
-#include "cobalt/render_tree/node_visitor.h"
-#include "cobalt/render_tree/punch_through_video_node.h"
-#include "cobalt/render_tree/rect_node.h"
-#include "cobalt/render_tree/rect_shadow_node.h"
-#include "cobalt/render_tree/text_node.h"
-
-namespace cobalt {
-namespace render_tree {
-namespace animations {
-
-void NodeAnimationsMap::Builder::AddInternal(
-    const scoped_refptr<Node>& target_node,
-    const scoped_refptr<AnimationListBase>& animation_list) {
-  DCHECK(node_animation_map_.find(target_node) == node_animation_map_.end())
-      << "The target render tree node already has an associated animation "
-         "list.";
-
-  node_animation_map_[target_node.get()] = animation_list;
-  node_refs_.push_back(target_node);
-}
-
-void NodeAnimationsMap::Builder::Merge(
-    const NodeAnimationsMap::Builder& other) {
-#if !defined(NDEBUG)
-  for (InternalMap::const_iterator iter = node_animation_map_.begin();
-       iter != node_animation_map_.end(); ++iter) {
-    DCHECK(other.node_animation_map_.find(iter->first) ==
-           other.node_animation_map_.end()) <<
-        "Only mutually exclusive NodeAnimationMaps can be merged!";
-  }
-#endif
-  node_animation_map_.insert(
-      other.node_animation_map_.begin(), other.node_animation_map_.end());
-  node_refs_.insert(
-      node_refs_.end(), other.node_refs_.begin(), other.node_refs_.end());
-}
-
-AnimationListBase* NodeAnimationsMap::GetAnimationsForNode(Node* target) const {
-  Builder::InternalMap::const_iterator found =
-      data_.node_animation_map_.find(target);
-  if (found == data_.node_animation_map_.end()) return NULL;
-  return found->second.get();
-}
-
-// This visitor object contains the logic for how to apply animation to each
-// render tree node.  Things are most interesting for node types that may
-// contain child render tree nodes, like CompositionNode.  In this case,
-// they will need to be animated not only if animations directly affect them,
-// but also if any of their children have been animated.
-class NodeAnimationsMap::NodeVisitor : public render_tree::NodeVisitor {
- public:
-  explicit NodeVisitor(const NodeAnimationsMap& animations,
-                       const base::TimeDelta& time_elapsed);
-
-  void Visit(CompositionNode* composition_node) OVERRIDE;
-  void Visit(FilterNode* image_node) OVERRIDE;
-  void Visit(ImageNode* image_node) OVERRIDE;
-  void Visit(MatrixTransformNode* matrix_transform_node) OVERRIDE;
-  void Visit(PunchThroughVideoNode* punch_through_video_node) OVERRIDE;
-  void Visit(RectNode* rect_node) OVERRIDE;
-  void Visit(RectShadowNode* rect_shadow_node) OVERRIDE;
-  void Visit(TextNode* text_node) OVERRIDE;
-
-  bool has_animated_node() const { return !!animated_node_; }
-
-  // NodeVisitor objects are intended to be "one-shot"
-  // visit objects.  The "return value" (e.g. the animated node) can be
-  // retrieved by calling animated_node() after Visit() has been called.
-  const scoped_refptr<Node>& animated_node() { return *animated_node_; }
-
-  // Helper function to apply all animations in a AnimationList to a specific
-  // node builder.
-  template <typename T>
-  static void ApplyAnimations(typename T::Builder* builder,
-                              const AnimationListBase* node_animations,
-                              base::TimeDelta time_elapsed);
-
-  // Helper function for applying animations to simple nodes that don't have any
-  // children or special cases.
-  template <typename T>
-  static base::optional<scoped_refptr<Node> >
-  MaybeCloneLeafNodeAndApplyAnimations(
-      T* node, const NodeAnimationsMap& animations,
-      base::TimeDelta time_elapsed);
-
- private:
-  const NodeAnimationsMap& animations_;
-  const base::TimeDelta& time_elapsed_;
-
-  base::optional<scoped_refptr<Node> > animated_node_;
-};
-
-NodeAnimationsMap::NodeVisitor::NodeVisitor(const NodeAnimationsMap& animations,
-                                            const base::TimeDelta& time_elapsed)
-    : animations_(animations), time_elapsed_(time_elapsed) {}
-
-template <typename T>
-void NodeAnimationsMap::NodeVisitor::ApplyAnimations(
-    typename T::Builder* builder, const AnimationListBase* node_animations,
-    base::TimeDelta time_elapsed) {
-  // Cast to the specific type we expect these animations to have.
-  const AnimationList<T>* typed_node_animations =
-      base::polymorphic_downcast<const AnimationList<T>*>(node_animations);
-
-  // Iterate through each animation applying them one at a time.
-  for (typename AnimationList<T>::InternalList::const_iterator iter =
-           typed_node_animations->data().animations.begin();
-       iter != typed_node_animations->data().animations.end(); ++iter) {
-    iter->Run(builder, time_elapsed);
-  }
-}
-
-template <typename T>
-base::optional<scoped_refptr<Node> >
-NodeAnimationsMap::NodeVisitor::MaybeCloneLeafNodeAndApplyAnimations(
-    T* node, const NodeAnimationsMap& animations,
-    base::TimeDelta time_elapsed) {
-  const AnimationListBase* node_animations =
-      animations.GetAnimationsForNode(node);
-  if (node_animations != NULL) {
-    typename T::Builder builder(node->data());
-
-    ApplyAnimations<T>(&builder, node_animations, time_elapsed);
-
-    return scoped_refptr<Node>(new T(builder));
-  } else {
-    // No animations were applied to this node, return NULL to signify this.
-    return base::nullopt;
-  }
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(CompositionNode* composition_node) {
-  // We declare the builder as an optional because we may not need one if we
-  // have no animations and none of our children are animated.
-  base::optional<CompositionNode::Builder> builder;
-
-  const CompositionNode::Children& original_children =
-      composition_node->data().children();
-
-  // Iterate through our children and visit them to apply animations.  After
-  // each one, check to see if it actually was animated, and if so, replace
-  // this composition node's reference to that child with the newly animated
-  // one.
-  for (size_t i = 0; i < original_children.size(); ++i) {
-    NodeVisitor child_visitor(animations_, time_elapsed_);
-    original_children[i]->Accept(&child_visitor);
-
-    // If a child was animated, then we must adjust our child node reference to
-    // the newly animated one.
-    if (child_visitor.has_animated_node()) {
-      if (!builder) {
-        builder.emplace(composition_node->data());
-      }
-      *builder->GetChild(static_cast<int>(i)) = child_visitor.animated_node();
-    }
-  }
-
-  // Check if any animations apply directly to us, and if so, apply them.
-  const AnimationListBase* animations =
-      animations_.GetAnimationsForNode(composition_node);
-  if (animations != NULL) {
-    if (!builder) {
-      builder.emplace(composition_node->data());
-    }
-    ApplyAnimations<CompositionNode>(&builder.value(), animations,
-                                     time_elapsed_);
-  }
-
-  // Return the animated node.  If no animations took place, leave
-  // animated_node_ as NULL to signify that no animations took place.
-  if (builder) {
-    animated_node_ = scoped_refptr<Node>(new CompositionNode(builder->Pass()));
-  }
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(FilterNode* filter_node) {
-  base::optional<FilterNode::Builder> builder;
-
-  // First check to see if our source node has any animations, and if so,
-  // animate it.
-  NodeVisitor child_visitor(animations_, time_elapsed_);
-  filter_node->data().source->Accept(&child_visitor);
-
-  if (child_visitor.has_animated_node()) {
-    // If our source node was animated, then so must we be, so create a
-    // builder and set it up to point to our animated source node.
-    builder.emplace(filter_node->data());
-    builder->source = child_visitor.animated_node();
-  }
-
-  // Apply any animations to the filter node itself.
-  const AnimationListBase* animations =
-      animations_.GetAnimationsForNode(filter_node);
-  if (animations != NULL) {
-    if (!builder) {
-      builder.emplace(filter_node->data());
-    }
-    ApplyAnimations<FilterNode>(&builder.value(), animations, time_elapsed_);
-  }
-
-  // Return the animated node.  If no animations took place, leave
-  // animated_node_ as NULL to signify that no animations took place.
-  if (builder) {
-    animated_node_ = scoped_refptr<Node>(new FilterNode(*builder));
-  }
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(ImageNode* image_node) {
-  animated_node_ = MaybeCloneLeafNodeAndApplyAnimations(
-      image_node, animations_, time_elapsed_);
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(
-    MatrixTransformNode* matrix_transform_node) {
-  base::optional<MatrixTransformNode::Builder> builder;
-
-  // First check to see if our source node has any animations, and if so,
-  // animate it.
-  NodeVisitor child_visitor(animations_, time_elapsed_);
-  matrix_transform_node->data().source->Accept(&child_visitor);
-
-  if (child_visitor.has_animated_node()) {
-    // If our source node was animated, then so must we be, so create a
-    // builder and set it up to point to our animated source node.
-    builder.emplace(matrix_transform_node->data());
-    builder->source = child_visitor.animated_node();
-  }
-
-  // Apply any animations to the filter node itself.
-  const AnimationListBase* animations =
-      animations_.GetAnimationsForNode(matrix_transform_node);
-  if (animations != NULL) {
-    if (!builder) {
-      builder.emplace(matrix_transform_node->data());
-    }
-    ApplyAnimations<MatrixTransformNode>(&builder.value(), animations,
-                                         time_elapsed_);
-  }
-
-  // Return the animated node.  If no animations took place, leave
-  // animated_node_ as NULL to signify that no animations took place.
-  if (builder) {
-    animated_node_ = scoped_refptr<Node>(new MatrixTransformNode(*builder));
-  }
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(
-    PunchThroughVideoNode* punch_through_video_node) {
-  animated_node_ = MaybeCloneLeafNodeAndApplyAnimations(
-      punch_through_video_node, animations_, time_elapsed_);
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(RectNode* rect_node) {
-  // We do not use MaybeCloneLeafNodeAndApplyAnimations() here so that we can
-  // construct our RectNode via a move of the RectNode::Builder object, instead
-  // of a copy.
-  const AnimationListBase* node_animations =
-      animations_.GetAnimationsForNode(rect_node);
-  if (node_animations != NULL) {
-    RectNode::Builder builder(rect_node->data());
-
-    ApplyAnimations<RectNode>(&builder, node_animations, time_elapsed_);
-
-    // Move construct our RectNode from the RectNode::Builder object.
-    animated_node_ = scoped_refptr<Node>(new RectNode(builder.Pass()));
-  }
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(RectShadowNode* rect_shadow_node) {
-  animated_node_ = MaybeCloneLeafNodeAndApplyAnimations(
-      rect_shadow_node, animations_, time_elapsed_);
-}
-
-void NodeAnimationsMap::NodeVisitor::Visit(TextNode* text_node) {
-  animated_node_ = MaybeCloneLeafNodeAndApplyAnimations(
-      text_node, animations_, time_elapsed_);
-}
-
-scoped_refptr<Node> NodeAnimationsMap::Apply(const scoped_refptr<Node>& root,
-                                             base::TimeDelta time_elapsed) {
-  TRACE_EVENT0("cobalt::renderer", "NodeAnimationsMap::Apply()");
-  NodeVisitor root_visitor(*this, time_elapsed);
-  root->Accept(&root_visitor);
-  return root_visitor.has_animated_node() ? root_visitor.animated_node() : root;
-}
-
-}  // namespace animations
-}  // namespace render_tree
-}  // namespace cobalt
diff --git a/src/cobalt/render_tree/animations/node_animations_map.h b/src/cobalt/render_tree/animations/node_animations_map.h
deleted file mode 100644
index 669cd61..0000000
--- a/src/cobalt/render_tree/animations/node_animations_map.h
+++ /dev/null
@@ -1,130 +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.
- */
-
-#ifndef COBALT_RENDER_TREE_ANIMATIONS_NODE_ANIMATIONS_MAP_H_
-#define COBALT_RENDER_TREE_ANIMATIONS_NODE_ANIMATIONS_MAP_H_
-
-#include <map>
-#include <vector>
-
-#include "base/containers/small_map.h"
-#include "base/memory/ref_counted.h"
-#include "cobalt/render_tree/animations/animation_list.h"
-#include "cobalt/render_tree/movable.h"
-#include "cobalt/render_tree/node.h"
-
-namespace cobalt {
-namespace render_tree {
-namespace animations {
-
-// A NodeAnimationsMap object represents a reference counted and immutable (so
-// they can be easily shared between threads) set of animations, along with
-// references to the render tree Nodes that they target.  NodeAnimationsMap
-// objects contain animation information about corresponding render trees and
-// are intended to be passed alongside them to modules that would like to
-// animate render trees.
-// NodeAnimationsMap objects essentially organize their collections of
-// animations as an unordered map from render tree Node objects to
-// AnimationLists. Thus, animation can be applied to a render tree by traversing
-// it and for each element checking to see if any animations exist for them, and
-// if so, apply them.  Indeed, the NodeAnimationsMap object's primary method,
-// Apply(), does just this.
-class NodeAnimationsMap : public base::RefCountedThreadSafe<NodeAnimationsMap> {
- public:
-  // Use this NodeAnimationsMap::Builder object to construct your collection of
-  // animations and corresponding render_tree Nodes.  When setup is complete,
-  // construct a NodeAnimationsMap object with the Builder.
-  class Builder {
-   public:
-    DECLARE_AS_MOVABLE(Builder);
-
-    Builder() {}
-    explicit Builder(Moved moved) {
-      node_animation_map_ = moved->node_animation_map_;
-      node_refs_.swap(moved->node_refs_);
-    }
-
-    // This method is a template so that we can ensure that animations are not
-    // mismatched with render tree nodes of the wrong type.
-    template <typename T>
-    void Add(const scoped_refptr<T>& target_node,
-             const scoped_refptr<AnimationList<T> >& animation_list) {
-      AddInternal(target_node, animation_list);
-    }
-
-    // Convenience method to attach a single animation to a target node.
-    template <typename T>
-    void Add(const scoped_refptr<T>& target_node,
-             const typename Animation<T>::Function& single_animation) {
-      AddInternal(target_node, scoped_refptr<AnimationListBase>(
-                                   new AnimationList<T>(single_animation)));
-    }
-
-    // Merge all mappings from another NodeAnimationsMap into this one.  There
-    // cannot be any keys that are in both the merge target and source.
-    void Merge(const NodeAnimationsMap& other) { Merge(other.data_); }
-    void Merge(const NodeAnimationsMap::Builder& other);
-
-   private:
-    // A non-template function that contains the logic for storing a target
-    // node and animation list pair.
-    void AddInternal(const scoped_refptr<Node>& target_node,
-                     const scoped_refptr<AnimationListBase>& animation_list);
-
-    // The primary internal data structure used to organize and store the
-    // mapping between target render tree node and animation list.
-    // In many cases there are not many active animations, and so we use a
-    // base::SmallMap for this.  std::map was found to be more performant than
-    // base::hash_map, so it is used as the fallback map.
-    typedef base::SmallMap<
-        std::map<Node*, scoped_refptr<AnimationListBase> >, 4> InternalMap;
-    InternalMap node_animation_map_;
-    std::vector<scoped_refptr<Node> > node_refs_;
-
-    friend class NodeAnimationsMap;
-  };
-
-  // Since Builder objects are heavy-weight, this constructor allows them to
-  // be move constructed into the NodeAnimationsMap object.
-  explicit NodeAnimationsMap(Builder::Moved builder) : data_(builder) {}
-
-  // Given the passed in current time, this method will apply all contained
-  // animations to the passed in render tree, returning a new render tree that
-  // has animations applied.  Nodes will only be newly created if they are
-  // animated or one of their descendants are animated, otherwise the original
-  // input node will be used and returned.
-  scoped_refptr<Node> Apply(const scoped_refptr<Node>& root,
-                            base::TimeDelta time_elapsed);
-
- private:
-  ~NodeAnimationsMap() {}
-
-  // Returns NULL if no animations exist for target node.
-  AnimationListBase* GetAnimationsForNode(Node* target) const;
-
-  const Builder data_;
-
-  class NodeVisitor;
-  friend class NodeVisitor;
-
-  friend class base::RefCountedThreadSafe<NodeAnimationsMap>;
-};
-
-}  // namespace animations
-}  // namespace render_tree
-}  // namespace cobalt
-
-#endif  // COBALT_RENDER_TREE_ANIMATIONS_NODE_ANIMATIONS_MAP_H_
diff --git a/src/cobalt/render_tree/child_iterator.h b/src/cobalt/render_tree/child_iterator.h
new file mode 100644
index 0000000..d5567c5
--- /dev/null
+++ b/src/cobalt/render_tree/child_iterator.h
@@ -0,0 +1,226 @@
+/*
+ * 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_RENDER_TREE_CHILD_ITERATOR_H_
+#define COBALT_RENDER_TREE_CHILD_ITERATOR_H_
+
+#include "cobalt/render_tree/composition_node.h"
+#include "cobalt/render_tree/filter_node.h"
+#include "cobalt/render_tree/image_node.h"
+#include "cobalt/render_tree/matrix_transform_node.h"
+#include "cobalt/render_tree/node.h"
+#include "cobalt/render_tree/punch_through_video_node.h"
+#include "cobalt/render_tree/rect_node.h"
+#include "cobalt/render_tree/rect_shadow_node.h"
+#include "cobalt/render_tree/text_node.h"
+
+namespace cobalt {
+namespace render_tree {
+
+class ImageNode;
+class PunchThroughVideoNode;
+class RectNode;
+class RectShadowNode;
+class TextNode;
+
+// The ChildIterator template provides a way to iterate over the children of
+// a node without concern for what type of node it is (though since it is a
+// template, the compiler must know the type).  Thus, render_tree::NodeVisitor
+// subclasses can forward visits to a ChildIterator if they want to traverse
+// the tree without writing traversal code for specific render tree node types.
+// Additionally, ReplaceCurrent() can be used to modify the list of children
+// at a given node, allowing render tree modifications to be made by code that
+// does not care about what type of render tree nodes it is dealing with.
+// Note that child-related methods like GetCurrent(), Next(), and
+// ReplaceCurrent() are only enabled for nodes that have children.  This can
+// be checked via |ChildIterator<T>::has_children|.
+//
+// Example usage:
+//
+//    void Visit(CompositionNode* node) { VisitNode(node); }
+//    void Visit(ImageNode* node) { VisitNode(node); }
+//    ...
+//
+//    template <typename T>
+//    typename base::enable_if<!ChildIterator<T>::has_children>::type
+//    VisitNode(T* node) {
+//      ProcessNode();
+//    }
+//
+//    template <typename T>
+//    typename base::enable_if<ChildIterator<T>::has_children>::type VisitNode(
+//        T* node) {
+//      ProcessNode();
+//
+//      // Visit children
+//      ChildIterator<T> child_iterator(node);
+//      while (Node* child = child_iterator.GetCurrent()) {
+//        Visit(child);
+//        child_iterator.Next();
+//      }
+//    }
+//
+//    void ProcessNode(Node* node) {
+//      // Called on every node
+//      ...
+//    }
+//
+
+template <typename T, typename = void>
+class ChildIterator {
+ public:
+  // This default class is used for all nodes that have no children.
+  static const bool has_children = false;
+};
+
+enum ChildIteratorDirection {
+  // Decides whether we start at the first or last child.
+  kChildIteratorDirectionForwards,
+  kChildIteratorDirectionBackwards,
+};
+
+// CompositionNodes may have multiple children, so we setup ChildIterator
+// to iterate through each of them.
+template <>
+class ChildIterator<CompositionNode> {
+ public:
+  static const bool has_children = true;
+
+  explicit ChildIterator(
+      CompositionNode* composition,
+      ChildIteratorDirection direction = kChildIteratorDirectionForwards)
+      : composition_node_(composition),
+        children_(composition_node_->data().children()),
+        child_number_(0),
+        direction_(direction) {}
+
+  Node* GetCurrent() const {
+    return done() ? NULL : children_[child_index()].get();
+  }
+  void Next() { ++child_number_; }
+
+  void ReplaceCurrent(const scoped_refptr<Node>& new_child) {
+    DCHECK(!done());
+    if (!modified_children_builder_) {
+      // If we haven't replaced any children yet, we start by constructing a new
+      // modifiable version of this CompositionNode's data so that we can
+      // modify its children.
+      modified_children_builder_ = composition_node_->data();
+    }
+    // Update the modified children list with the newly replaced child.
+    *modified_children_builder_->GetChild(static_cast<int>(child_index())) =
+        new_child;
+  }
+  CompositionNode::Builder::Moved TakeReplacedChildrenBuilder() {
+    return modified_children_builder_->Pass();
+  }
+
+ private:
+  size_t child_index() const {
+    DCHECK(!done());
+    return direction_ == kChildIteratorDirectionForwards
+               ? child_number_
+               : children_.size() - child_number_ - 1;
+  }
+  bool done() const { return child_number_ >= children_.size(); }
+
+  // The node whose children we are iterating through.
+  CompositionNode* composition_node_;
+  // A quick reference to the node's children.
+  const CompositionNode::Children& children_;
+  // The current child index we are at with our iteration.
+  size_t child_number_;
+
+  ChildIteratorDirection direction_;
+
+  // The builder to use if we are modifying the children.  If constructed, it
+  // starts as a copy of the origin CompositionNode's data.
+  base::optional<CompositionNode::Builder> modified_children_builder_;
+};
+
+// FilterNodes can have up to 1 child.
+template <>
+class ChildIterator<FilterNode> {
+ public:
+  static const bool has_children = true;
+
+  explicit ChildIterator(
+      FilterNode* filter,
+      ChildIteratorDirection direction = kChildIteratorDirectionForwards)
+      : filter_node_(filter), source_(filter->data().source.get()) {
+    UNREFERENCED_PARAMETER(direction);
+  }
+
+  Node* GetCurrent() const { return source_; }
+  void Next() { source_ = NULL; }
+
+  void ReplaceCurrent(const scoped_refptr<Node>& new_child) {
+    DCHECK(GetCurrent());
+    if (!modified_children_builder_) {
+      modified_children_builder_ = filter_node_->data();
+    }
+    modified_children_builder_->source = new_child;
+  }
+  FilterNode::Builder TakeReplacedChildrenBuilder() {
+    return *modified_children_builder_;
+  }
+
+ private:
+  FilterNode* filter_node_;
+  Node* source_;
+
+  base::optional<FilterNode::Builder> modified_children_builder_;
+};
+
+// MatrixTransformNodes can have up to 1 child.
+template <>
+class ChildIterator<MatrixTransformNode> {
+ public:
+  static const bool has_children = true;
+
+  explicit ChildIterator(
+      MatrixTransformNode* matrix_transform,
+      ChildIteratorDirection direction = kChildIteratorDirectionForwards)
+      : matrix_transform_node_(matrix_transform),
+        source_(matrix_transform->data().source.get()) {
+    UNREFERENCED_PARAMETER(direction);
+  }
+
+  Node* GetCurrent() const { return source_; }
+  void Next() { source_ = NULL; }
+
+  void ReplaceCurrent(const scoped_refptr<Node>& new_child) {
+    DCHECK(GetCurrent());
+    if (!modified_children_builder_) {
+      modified_children_builder_ = matrix_transform_node_->data();
+    }
+    modified_children_builder_->source = new_child;
+  }
+  MatrixTransformNode::Builder TakeReplacedChildrenBuilder() {
+    return *modified_children_builder_;
+  }
+
+ private:
+  MatrixTransformNode* matrix_transform_node_;
+  Node* source_;
+
+  base::optional<MatrixTransformNode::Builder> modified_children_builder_;
+};
+
+}  // namespace render_tree
+}  // namespace cobalt
+
+#endif  // COBALT_RENDER_TREE_CHILD_ITERATOR_H_
diff --git a/src/cobalt/render_tree/dump_render_tree_to_string.cc b/src/cobalt/render_tree/dump_render_tree_to_string.cc
index adee88e..6fdc38e 100644
--- a/src/cobalt/render_tree/dump_render_tree_to_string.cc
+++ b/src/cobalt/render_tree/dump_render_tree_to_string.cc
@@ -31,6 +31,10 @@
 namespace cobalt {
 namespace render_tree {
 
+namespace animations {
+class AnimateNode;
+}  // namespace animations
+
 namespace {
 
 // A render tree visitor that accumulates node dumps to text within a
@@ -39,6 +43,7 @@
  public:
   DebugTreePrinter() : indent_(0) {}
 
+  void Visit(animations::AnimateNode* /* animate */) OVERRIDE { NOTREACHED(); }
   void Visit(CompositionNode* composition) OVERRIDE;
   void Visit(FilterNode* text) OVERRIDE;
   void Visit(ImageNode* image) OVERRIDE;
diff --git a/src/cobalt/render_tree/node_visitor.h b/src/cobalt/render_tree/node_visitor.h
index 73b9c21..de6c026 100644
--- a/src/cobalt/render_tree/node_visitor.h
+++ b/src/cobalt/render_tree/node_visitor.h
@@ -29,11 +29,16 @@
 class RectShadowNode;
 class TextNode;
 
+namespace animations {
+class AnimateNode;
+}  // namespace animations
+
 // Type-safe branching on a class hierarchy of render tree nodes,
 // implemented after a classical GoF pattern (see
 // http://en.wikipedia.org/wiki/Visitor_pattern#Java_example).
 class NodeVisitor {
  public:
+  virtual void Visit(animations::AnimateNode* animate) = 0;
   virtual void Visit(CompositionNode* composition) = 0;
   virtual void Visit(FilterNode* text) = 0;
   virtual void Visit(ImageNode* image) = 0;
diff --git a/src/cobalt/render_tree/node_visitor_test.cc b/src/cobalt/render_tree/node_visitor_test.cc
index 502a749..7a24cc4 100644
--- a/src/cobalt/render_tree/node_visitor_test.cc
+++ b/src/cobalt/render_tree/node_visitor_test.cc
@@ -20,6 +20,7 @@
 
 #include "cobalt/math/rect_f.h"
 #include "cobalt/math/size.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 #include "cobalt/render_tree/composition_node.h"
 #include "cobalt/render_tree/filter_node.h"
 #include "cobalt/render_tree/font.h"
@@ -33,6 +34,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using cobalt::render_tree::animations::AnimateNode;
 using cobalt::render_tree::Brush;
 using cobalt::render_tree::BrushVisitor;
 using cobalt::render_tree::ColorRGBA;
@@ -53,6 +55,7 @@
 
 class MockNodeVisitor : public NodeVisitor {
  public:
+  MOCK_METHOD1(Visit, void(AnimateNode* animate));
   MOCK_METHOD1(Visit, void(CompositionNode* composition));
   MOCK_METHOD1(Visit, void(FilterNode* image));
   MOCK_METHOD1(Visit, void(ImageNode* image));
@@ -99,6 +102,15 @@
 
 }  // namespace
 
+TEST(NodeVisitorTest, VisitsAnimate) {
+  scoped_refptr<DummyImage> dummy_image = make_scoped_refptr(new DummyImage());
+  scoped_refptr<ImageNode> dummy_image_node(new ImageNode(dummy_image));
+  scoped_refptr<AnimateNode> animate_node(new AnimateNode(dummy_image_node));
+  MockNodeVisitor mock_visitor;
+  EXPECT_CALL(mock_visitor, Visit(animate_node.get()));
+  animate_node->Accept(&mock_visitor);
+}
+
 TEST(NodeVisitorTest, VisitsImage) {
   scoped_refptr<DummyImage> image = make_scoped_refptr(new DummyImage());
   scoped_refptr<ImageNode> image_node(new ImageNode(image));
diff --git a/src/cobalt/render_tree/render_tree.gyp b/src/cobalt/render_tree/render_tree.gyp
index 5af25ff..6e7c6a7 100644
--- a/src/cobalt/render_tree/render_tree.gyp
+++ b/src/cobalt/render_tree/render_tree.gyp
@@ -30,6 +30,7 @@
         'brush.cc',
         'brush.h',
         'brush_visitor.h',
+        'child_iterator.h',
         'color_rgba.h',
         'composition_node.cc',
         'composition_node.h',
@@ -73,8 +74,8 @@
       'target_name': 'animations',
       'type': 'static_library',
       'sources': [
-        'animations/node_animations_map.cc',
-        'animations/node_animations_map.h',
+        'animations/animate_node.cc',
+        'animations/animate_node.h',
       ],
       'dependencies': [
         'render_tree',
@@ -86,7 +87,7 @@
       'target_name': 'render_tree_test',
       'type': '<(gtest_target_type)',
       'sources': [
-        'animations/node_animations_map_test.cc',
+        'animations/animate_node_test.cc',
         'brush_visitor_test.cc',
         'color_rgba_test.cc',
         'node_visitor_test.cc',
diff --git a/src/cobalt/renderer/animations_test.cc b/src/cobalt/renderer/animations_test.cc
index 8c488a5..033a78f 100644
--- a/src/cobalt/renderer/animations_test.cc
+++ b/src/cobalt/renderer/animations_test.cc
@@ -16,6 +16,7 @@
 
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/simple_thread.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 #include "cobalt/render_tree/image.h"
 #include "cobalt/render_tree/image_node.h"
 #include "cobalt/render_tree/resource_provider.h"
@@ -29,10 +30,10 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
+using cobalt::render_tree::animations::AnimateNode;
 using cobalt::render_tree::Image;
 using cobalt::render_tree::ImageNode;
 using cobalt::render_tree::ResourceProvider;
-using cobalt::render_tree::animations::NodeAnimationsMap;
 
 namespace cobalt {
 namespace renderer {
@@ -179,7 +180,7 @@
 
     // Animate the ImageNode and pass in our callback function to be executed
     // upon render_tree animation.
-    NodeAnimationsMap::Builder animations;
+    AnimateNode::Builder animations;
     bool first_animate = true;
     animations.Add(test_node,
                    base::Bind(&AnimateImageNode, &animate_has_started,
@@ -194,9 +195,8 @@
 
     // Submit the render tree and animation to the rendering pipeline for
     // rasterization (and the execution of our animation callback).
-    pipeline.Submit(Submission(
-        test_node, new NodeAnimationsMap(animations.Pass()),
-        base::Time::Now() - base::Time::UnixEpoch()));
+    pipeline.Submit(Submission(new AnimateNode(animations, test_node),
+                               base::Time::Now() - base::Time::UnixEpoch()));
 
     // Wait for all events that we have planned to occur.
     animate_has_started.Wait();
diff --git a/src/cobalt/renderer/pipeline.cc b/src/cobalt/renderer/pipeline.cc
index 66ea9a2..a5f38e7 100644
--- a/src/cobalt/renderer/pipeline.cc
+++ b/src/cobalt/renderer/pipeline.cc
@@ -22,10 +22,11 @@
 #include "base/file_util.h"
 #include "base/path_service.h"
 #include "cobalt/base/cobalt_paths.h"
+#include "cobalt/base/polymorphic_downcast.h"
 #include "cobalt/render_tree/dump_render_tree_to_string.h"
 
 using cobalt::render_tree::Node;
-using cobalt::render_tree::animations::NodeAnimationsMap;
+using cobalt::render_tree::animations::AnimateNode;
 
 namespace cobalt {
 namespace renderer {
@@ -134,10 +135,11 @@
 
 void Pipeline::Submit(const Submission& render_tree_submission) {
   TRACE_EVENT0("cobalt::renderer", "Pipeline::Submit()");
+
   // Execute the actual set of the new render tree on the rasterizer tree.
   rasterizer_thread_.message_loop()->PostTask(
       FROM_HERE, base::Bind(&Pipeline::SetNewRenderTree, base::Unretained(this),
-                            render_tree_submission));
+                            CollectAnimations(render_tree_submission)));
 }
 
 void Pipeline::Clear() {
@@ -160,7 +162,7 @@
     rasterizer_thread_.message_loop()->PostTask(
         FROM_HERE,
         base::Bind(&Pipeline::RasterizeToRGBAPixels, base::Unretained(this),
-                   render_tree_submission, complete));
+                   CollectAnimations(render_tree_submission), complete));
     return;
   }
   // Create a new target that is the same dimensions as the display target.
@@ -231,8 +233,11 @@
   TRACE_EVENT0("cobalt::renderer",
                "Pipeline::RasterizeSubmissionToRenderTarget()");
   // Animate the render tree using the submitted animations.
-  scoped_refptr<Node> animated_render_tree = submission.animations->Apply(
-      submission.render_tree, submission.time_offset);
+  render_tree::animations::AnimateNode* animate_node =
+      base::polymorphic_downcast<render_tree::animations::AnimateNode*>(
+          submission.render_tree.get());
+  scoped_refptr<Node> animated_render_tree =
+      animate_node->Apply(submission.time_offset);
 
   // Rasterize the animated render tree.
   rasterizer_->Submit(animated_render_tree, render_target);
@@ -311,8 +316,11 @@
   Submission submission =
       submission_queue_->GetCurrentSubmission(base::TimeTicks::Now());
 
-  scoped_refptr<Node> animated_render_tree = submission.animations->Apply(
-      submission.render_tree, submission.time_offset);
+  render_tree::animations::AnimateNode* animate_node =
+      base::polymorphic_downcast<render_tree::animations::AnimateNode*>(
+          submission.render_tree.get());
+  scoped_refptr<Node> animated_render_tree =
+      animate_node->Apply(submission.time_offset);
 
   std::string tree_dump =
       render_tree::DumpRenderTreeToString(animated_render_tree);
@@ -330,5 +338,16 @@
 }
 #endif  // #if defined(ENABLE_DEBUG_CONSOLE)
 
+Submission Pipeline::CollectAnimations(
+    const Submission& render_tree_submission) {
+  // Constructing an AnimateNode will result in the tree being traversed to
+  // collect all sub-AnimateNodes into the new one, in order to maintain the
+  // invariant that a sub-tree of an AnimateNode has no AnimateNodes.
+  Submission collected_submission = render_tree_submission;
+  collected_submission.render_tree = new render_tree::animations::AnimateNode(
+      render_tree_submission.render_tree);
+  return collected_submission;
+}
+
 }  // namespace renderer
 }  // namespace cobalt
diff --git a/src/cobalt/renderer/pipeline.h b/src/cobalt/renderer/pipeline.h
index 98f3f1c..ad05b29 100644
--- a/src/cobalt/renderer/pipeline.h
+++ b/src/cobalt/renderer/pipeline.h
@@ -27,7 +27,7 @@
 #include "base/threading/thread_checker.h"
 #include "base/timer.h"
 #include "cobalt/base/c_val_time_interval_timer.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 #include "cobalt/render_tree/node.h"
 #include "cobalt/renderer/backend/graphics_context.h"
 #include "cobalt/renderer/rasterizer/rasterizer.h"
@@ -125,6 +125,13 @@
   void OnDumpCurrentRenderTree(const std::string&);
 #endif  // defined(ENABLE_DEBUG_CONSOLE)
 
+  // Render trees may contain a number of AnimateNodes (or none).  In order
+  // to optimize for applying the animations on the rasterizer thread, this
+  // function searches the tree for AnimateNodes and collects all of their
+  // information into a single AnimateNode at the root of the returned
+  // render tree.
+  Submission CollectAnimations(const Submission& render_tree_submission);
+
   base::WaitableEvent rasterizer_created_event_;
 
   // The render_target that all submitted render trees will be rasterized to.
diff --git a/src/cobalt/renderer/rasterizer/benchmark.cc b/src/cobalt/renderer/rasterizer/benchmark.cc
index aefb362..097d0bf 100644
--- a/src/cobalt/renderer/rasterizer/benchmark.cc
+++ b/src/cobalt/renderer/rasterizer/benchmark.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "cobalt/base/polymorphic_downcast.h"
 #include "cobalt/math/size.h"
 #include "cobalt/renderer/backend/default_graphics_system.h"
 #include "cobalt/renderer/backend/graphics_context.h"
@@ -28,19 +29,20 @@
 using cobalt::math::Size;
 using cobalt::math::SizeF;
 using cobalt::render_tree::AlphaFormat;
+using cobalt::render_tree::animations::AnimateNode;
 using cobalt::render_tree::ImageData;
+using cobalt::render_tree::Node;
 using cobalt::render_tree::PixelFormat;
 using cobalt::render_tree::ResourceProvider;
-using cobalt::renderer::rasterizer::Rasterizer;
-using cobalt::renderer::RendererModule;
 using cobalt::renderer::backend::Display;
 using cobalt::renderer::backend::GraphicsContext;
 using cobalt::renderer::backend::GraphicsSystem;
 using cobalt::renderer::backend::RenderTarget;
 using cobalt::renderer::backend::SurfaceInfo;
+using cobalt::renderer::rasterizer::Rasterizer;
+using cobalt::renderer::RendererModule;
 using cobalt::renderer::test::scenes::AddBlankBackgroundToScene;
 using cobalt::renderer::test::scenes::CreateAllScenesCombinedScene;
-using cobalt::renderer::test::scenes::RenderTreeWithAnimations;
 using cobalt::system_window::SystemWindow;
 
 namespace {
@@ -63,7 +65,7 @@
   kOutputSurfaceTypeOffscreen,
 };
 
-typedef base::Callback<RenderTreeWithAnimations(
+typedef base::Callback<scoped_refptr<Node>(
     ResourceProvider*, const SizeF&, base::TimeDelta)> SceneCreateFunction;
 
 // RunRenderTreeSceneBenchmark serves as a framework for render tree scene
@@ -105,15 +107,16 @@
     DLOG(FATAL) << "Unknown output surface type.";
   }
 
-  RenderTreeWithAnimations scene =
+  scoped_refptr<Node> scene =
       scene_create_function.Run(rasterizer->GetResourceProvider(),
                                 test_surface->GetSize(), base::TimeDelta());
 
   const int kRenderIterationCount = 100;
   const float kFixedTimeStepInSecondsPerFrame = 0.016f;
   for (int i = 0; i < kRenderIterationCount; ++i) {
-    scoped_refptr<cobalt::render_tree::Node> animated = scene.animations->Apply(
-        scene.render_tree,
+    AnimateNode* animate_node =
+        base::polymorphic_downcast<AnimateNode*>(scene.get());
+    scoped_refptr<Node> animated = animate_node->Apply(
         base::TimeDelta::FromSecondsD(i * kFixedTimeStepInSecondsPerFrame));
 
     // Submit the render tree to be rendered.
@@ -133,7 +136,7 @@
 #define RENDER_TREE_BUILDER_BENCHMARK(test_name)                              \
   TRACE_EVENT_BENCHMARK5(                                                     \
       test_name, "BuildRenderTree", cobalt::trace_event::IN_SCOPE_DURATION,   \
-      "NodeAnimationsMap::Apply()", cobalt::trace_event::IN_SCOPE_DURATION,   \
+      "AnimateNode::Apply()", cobalt::trace_event::IN_SCOPE_DURATION,         \
       "Rasterizer::Submit()", cobalt::trace_event::FLOW_DURATION,             \
       "Rasterizer::Submit()", cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS, \
       "VisitRenderTree", cobalt::trace_event::IN_SCOPE_DURATION)
diff --git a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
index 2f73a29..2868926 100644
--- a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
@@ -38,6 +38,7 @@
 class HardwareRasterizer::Impl {
  public:
   explicit Impl(backend::GraphicsContext* graphics_context,
+                int scratch_surface_size_in_bytes,
                 int surface_cache_size_in_bytes);
   ~Impl();
 
@@ -57,16 +58,21 @@
 
   int64 submit_count_;
 
+  ScratchSurfaceCache scratch_surface_cache_;
   base::optional<SurfaceCacheDelegate> surface_cache_delegate_;
   base::optional<common::SurfaceCache> surface_cache_;
 };
 
 HardwareRasterizer::Impl::Impl(backend::GraphicsContext* graphics_context,
+                               int scratch_surface_size_in_bytes,
                                int surface_cache_size_in_bytes)
     : context_(base::polymorphic_downcast<backend::GraphicsContextBlitter*>(
           graphics_context)),
       software_rasterizer_(0),
-      submit_count_(0) {
+      submit_count_(0),
+      scratch_surface_cache_(context_->GetSbBlitterDevice(),
+                             context_->GetSbBlitterContext(),
+                             scratch_surface_size_in_bytes) {
   resource_provider_ = scoped_ptr<render_tree::ResourceProvider>(
       new ResourceProvider(context_->GetSbBlitterDevice(),
                            software_rasterizer_.GetResourceProvider()));
@@ -126,7 +132,7 @@
         RenderState(render_target_blitter->GetSbRenderTarget(), Transform(),
                     BoundsStack(context_->GetSbBlitterContext(),
                                 math::Rect(render_target_blitter->GetSize()))),
-        &software_rasterizer_,
+        &software_rasterizer_, &scratch_surface_cache_,
         surface_cache_delegate_ ? &surface_cache_delegate_.value() : NULL,
         surface_cache_ ? &surface_cache_.value() : NULL);
     render_tree->Accept(&visitor);
@@ -144,8 +150,10 @@
 }
 
 HardwareRasterizer::HardwareRasterizer(
-    backend::GraphicsContext* graphics_context, int surface_cache_size_in_bytes)
-    : impl_(new Impl(graphics_context, surface_cache_size_in_bytes)) {}
+    backend::GraphicsContext* graphics_context,
+    int scratch_surface_size_in_bytes, int surface_cache_size_in_bytes)
+    : impl_(new Impl(graphics_context, scratch_surface_size_in_bytes,
+                     surface_cache_size_in_bytes)) {}
 
 HardwareRasterizer::~HardwareRasterizer() {}
 
diff --git a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h
index 7562d32..abf4d4e 100644
--- a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h
+++ b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.h
@@ -21,6 +21,7 @@
 #include "cobalt/render_tree/resource_provider.h"
 #include "cobalt/renderer/backend/graphics_context.h"
 #include "cobalt/renderer/backend/render_target.h"
+#include "cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h"
 #include "cobalt/renderer/rasterizer/rasterizer.h"
 
 #if SB_HAS(BLITTER)
@@ -37,6 +38,7 @@
 class HardwareRasterizer : public Rasterizer {
  public:
   explicit HardwareRasterizer(backend::GraphicsContext* graphics_context,
+                              int scratch_surface_size_in_bytes,
                               int surface_cache_size_in_bytes);
   virtual ~HardwareRasterizer();
 
diff --git a/src/cobalt/renderer/rasterizer/blitter/rasterizer.gyp b/src/cobalt/renderer/rasterizer/blitter/rasterizer.gyp
index 0f7f474..8c75fd1 100644
--- a/src/cobalt/renderer/rasterizer/blitter/rasterizer.gyp
+++ b/src/cobalt/renderer/rasterizer/blitter/rasterizer.gyp
@@ -45,6 +45,7 @@
         'render_tree_blitter_conversions.cc',
         'render_tree_node_visitor.cc',
         'resource_provider.cc',
+        'scratch_surface_cache.cc',
         'surface_cache_delegate.cc',
       ],
 
diff --git a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
index 9af227b..3f37aeb 100644
--- a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
@@ -54,12 +54,14 @@
     SbBlitterDevice device, SbBlitterContext context,
     const RenderState& render_state,
     skia::SoftwareRasterizer* software_rasterizer,
+    ScratchSurfaceCache* scratch_surface_cache,
     SurfaceCacheDelegate* surface_cache_delegate,
     common::SurfaceCache* surface_cache)
     : software_rasterizer_(software_rasterizer),
       device_(device),
       context_(context),
       render_state_(render_state),
+      scratch_surface_cache_(scratch_surface_cache),
       surface_cache_delegate_(surface_cache_delegate),
       surface_cache_(surface_cache) {
   DCHECK_EQ(surface_cache_delegate_ == NULL, surface_cache_ == NULL);
@@ -135,16 +137,16 @@
 
     // Render our source subtree to an offscreen surface, and then we will
     // re-render it to our main render target with an alpha value applied to it.
-    OffscreenRender offscreen_render = RenderToOffscreenSurface(source);
-    if (!SbBlitterIsSurfaceValid(offscreen_render.surface)) {
+    scoped_ptr<OffscreenRender> offscreen_render =
+        RenderToOffscreenSurface(source);
+    if (!offscreen_render) {
       // This can happen if the output area of the source node is 0, in which
       // case we're trivially done.
       return;
     }
 
-    SbBlitterSurfaceInfo offscreen_surface_info;
-    CHECK(SbBlitterGetSurfaceInfo(offscreen_render.surface,
-                                  &offscreen_surface_info));
+    SbBlitterSurface offscreen_surface =
+        offscreen_render->scratch_surface->GetSurface();
 
     // Now blit our offscreen surface to our main render target with opacity
     // applied.
@@ -154,15 +156,10 @@
         context_,
         SbBlitterColorFromRGBA(255, 255, 255, static_cast<int>(255 * opacity)));
     SbBlitterBlitRectToRect(
-        context_, offscreen_render.surface,
-        SbBlitterMakeRect(0, 0, offscreen_surface_info.width,
-                          offscreen_surface_info.height),
-        SbBlitterMakeRect(
-            offscreen_render.position.x(), offscreen_render.position.y(),
-            offscreen_surface_info.width, offscreen_surface_info.height));
-
-    // Destroy our temporary offscreeen surface now that we are done with it.
-    SbBlitterDestroySurface(offscreen_render.surface);
+        context_, offscreen_surface,
+        SbBlitterMakeRect(0, 0, offscreen_render->destination_rect.width(),
+                          offscreen_render->destination_rect.height()),
+        RectFToBlitterRect(offscreen_render->destination_rect));
   }
 }
 
@@ -456,7 +453,7 @@
   SbBlitterDestroySurface(surface);
 }
 
-RenderTreeNodeVisitor::OffscreenRender
+scoped_ptr<RenderTreeNodeVisitor::OffscreenRender>
 RenderTreeNodeVisitor::RenderToOffscreenSurface(render_tree::Node* node) {
   common::OffscreenRenderCoordinateMapping coord_mapping =
       common::GetOffscreenRenderCoordinateMapping(
@@ -464,9 +461,7 @@
           render_state_.bounds_stack.Top());
   if (coord_mapping.output_bounds.IsEmpty()) {
     // There's nothing to render if the bounds are 0.
-    OffscreenRender ret;
-    ret.surface = kSbBlitterInvalidSurface;
-    return ret;
+    return scoped_ptr<OffscreenRender>();
   }
   DCHECK_GE(0.001f, std::abs(1.0f -
                              render_state_.transform.scale().x() *
@@ -475,28 +470,22 @@
                              render_state_.transform.scale().y() *
                                  coord_mapping.output_post_scale.y()));
 
-  SbBlitterSurface surface = SbBlitterCreateRenderTargetSurface(
-      device_, coord_mapping.output_bounds.width(),
-      coord_mapping.output_bounds.height(), kSbBlitterSurfaceFormatRGBA8);
+  scoped_ptr<CachedScratchSurface> scratch_surface(new CachedScratchSurface(
+      scratch_surface_cache_, coord_mapping.output_bounds.size()));
+  SbBlitterSurface surface = scratch_surface->GetSurface();
   SbBlitterRenderTarget render_target =
       SbBlitterGetRenderTargetFromSurface(surface);
 
   SbBlitterSetRenderTarget(context_, render_target);
 
-  // Clear the background to fully transparent before we begin rendering the
-  // subtree.
-  SbBlitterSetBlending(context_, false);
-  SbBlitterSetColor(context_, SbBlitterColorFromRGBA(0, 0, 0, 0));
-  SbBlitterFillRect(
-      context_, RectToBlitterRect(Rect(coord_mapping.output_bounds.size())));
-
   // Render to the sub-surface.
   RenderTreeNodeVisitor sub_visitor(
       device_, context_,
       RenderState(
           render_target, Transform(coord_mapping.sub_render_transform),
           BoundsStack(context_, Rect(coord_mapping.output_bounds.size()))),
-      software_rasterizer_, surface_cache_delegate_, surface_cache_);
+      software_rasterizer_, scratch_surface_cache_, surface_cache_delegate_,
+      surface_cache_);
   node->Accept(&sub_visitor);
 
   // Restore our original render target.
@@ -509,11 +498,12 @@
                               coord_mapping.output_pre_translate +
                               render_state_.transform.translate();
 
-  OffscreenRender ret;
-  ret.position.SetPoint(output_point.x(), output_point.y());
-  ret.surface = surface;
+  scoped_ptr<OffscreenRender> ret(new OffscreenRender());
+  ret->destination_rect =
+      math::RectF(output_point, coord_mapping.output_bounds.size());
+  ret->scratch_surface = scratch_surface.Pass();
 
-  return ret;
+  return ret.Pass();
 }
 
 }  // namespace blitter
diff --git a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h
index 3370321..4677308 100644
--- a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h
+++ b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.h
@@ -33,6 +33,7 @@
 #include "cobalt/render_tree/rect_shadow_node.h"
 #include "cobalt/render_tree/text_node.h"
 #include "cobalt/renderer/rasterizer/blitter/render_state.h"
+#include "cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h"
 #include "cobalt/renderer/rasterizer/blitter/surface_cache_delegate.h"
 #include "cobalt/renderer/rasterizer/common/surface_cache.h"
 #include "cobalt/renderer/rasterizer/skia/software_rasterizer.h"
@@ -42,6 +43,13 @@
 #if SB_HAS(BLITTER)
 
 namespace cobalt {
+
+namespace render_tree {
+namespace animations {
+class AnimateNode;
+}  // namespace animations
+}  // namespace render_tree
+
 namespace renderer {
 namespace rasterizer {
 namespace blitter {
@@ -55,9 +63,13 @@
   RenderTreeNodeVisitor(SbBlitterDevice device, SbBlitterContext context,
                         const RenderState& render_state,
                         skia::SoftwareRasterizer* software_rasterizer,
+                        ScratchSurfaceCache* scratch_surface_cache,
                         SurfaceCacheDelegate* surface_cache_delegate,
                         common::SurfaceCache* surface_cache);
 
+  void Visit(render_tree::animations::AnimateNode* animate_node) OVERRIDE {
+    NOTREACHED();
+  }
   void Visit(render_tree::CompositionNode* composition_node) OVERRIDE;
   void Visit(render_tree::FilterNode* filter_node) OVERRIDE;
   void Visit(render_tree::ImageNode* image_node) OVERRIDE;
@@ -82,10 +94,10 @@
   // Uses a Blitter API sub-visitor to render the provided render tree to a
   // offscreen SbBlitterSurface which is then returned.
   struct OffscreenRender {
-    math::Point position;
-    SbBlitterSurface surface;
+    math::RectF destination_rect;
+    scoped_ptr<CachedScratchSurface> scratch_surface;
   };
-  OffscreenRender RenderToOffscreenSurface(render_tree::Node* node);
+  scoped_ptr<OffscreenRender> RenderToOffscreenSurface(render_tree::Node* node);
 
   // We maintain an instance of a software skia rasterizer which is used to
   // render anything that we cannot render via the Blitter API directly.
@@ -97,6 +109,10 @@
   // Keeps track of our current render target, transform and clip stack.
   RenderState render_state_;
 
+  // Manager for scratch surfaces used for intermediate rendering during render
+  // tree traversal.
+  ScratchSurfaceCache* scratch_surface_cache_;
+
   SurfaceCacheDelegate* surface_cache_delegate_;
   common::SurfaceCache* surface_cache_;
   base::optional<SurfaceCacheDelegate::ScopedContext>
diff --git a/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.cc b/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.cc
new file mode 100644
index 0000000..d9b3790
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.cc
@@ -0,0 +1,93 @@
+/*
+ * 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/renderer/rasterizer/blitter/scratch_surface_cache.h"
+
+#include "cobalt/base/polymorphic_downcast.h"
+#include "starboard/blitter.h"
+
+#if SB_HAS(BLITTER)
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace blitter {
+
+namespace {
+
+class BlitterSurface : public common::ScratchSurfaceCache::Surface {
+ public:
+  BlitterSurface(SbBlitterSurface surface, const math::Size& size)
+      : surface_(surface), size_(size) {}
+  ~BlitterSurface() OVERRIDE { SbBlitterDestroySurface(surface_); }
+
+  math::Size GetSize() const OVERRIDE { return size_; }
+
+  SbBlitterSurface blitter_surface() { return surface_; }
+
+ private:
+  SbBlitterSurface surface_;
+  math::Size size_;
+};
+}  // namespace
+
+ScratchSurfaceCache::ScratchSurfaceCache(SbBlitterDevice device,
+                                         SbBlitterContext context,
+                                         int cache_capacity_in_bytes)
+    : delegate_(device, context), cache_(&delegate_, cache_capacity_in_bytes) {}
+
+ScratchSurfaceCache::Delegate::Delegate(SbBlitterDevice device,
+                                        SbBlitterContext context)
+    : device_(device), context_(context) {}
+
+common::ScratchSurfaceCache::Surface*
+ScratchSurfaceCache::Delegate::CreateSurface(const math::Size& size) {
+  return new BlitterSurface(
+      SbBlitterCreateRenderTargetSurface(device_, size.width(), size.height(),
+                                         kSbBlitterSurfaceFormatRGBA8),
+      size);
+}
+
+void ScratchSurfaceCache::Delegate::DestroySurface(
+    common::ScratchSurfaceCache::Surface* surface) {
+  delete surface;
+}
+
+void ScratchSurfaceCache::Delegate::PrepareForUse(
+    common::ScratchSurfaceCache::Surface* surface, const math::Size& area) {
+  SbBlitterSurface blitter_surface =
+      base::polymorphic_downcast<BlitterSurface*>(surface)->blitter_surface();
+
+  SbBlitterSetRenderTarget(
+      context_, SbBlitterGetRenderTargetFromSurface(blitter_surface));
+  SbBlitterSetBlending(context_, false);
+  SbBlitterSetColor(context_, SbBlitterColorFromRGBA(0, 0, 0, 0));
+  SbBlitterFillRect(context_,
+                    SbBlitterMakeRect(0, 0, area.width(), area.height()));
+}
+
+SbBlitterSurface CachedScratchSurface::GetSurface() {
+  return base::polymorphic_downcast<BlitterSurface*>(
+             common_scratch_surface_.GetSurface())
+      ->blitter_surface();
+}
+
+}  // namespace blitter
+}  // namespace rasterizer
+}  // namespace renderer
+}  // namespace cobalt
+
+#endif  // SB_HAS(BLITTER)
diff --git a/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h b/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h
new file mode 100644
index 0000000..675a498
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.h
@@ -0,0 +1,89 @@
+/*
+ * 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_RENDERER_RASTERIZER_BLITTER_SCRATCH_SURFACE_CACHE_H_
+#define COBALT_RENDERER_RASTERIZER_BLITTER_SCRATCH_SURFACE_CACHE_H_
+
+#include "cobalt/math/size.h"
+#include "cobalt/renderer/rasterizer/common/scratch_surface_cache.h"
+#include "starboard/blitter.h"
+
+#if SB_HAS(BLITTER)
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace blitter {
+
+// We define a blitter::ScratchSurfaceCache class here that decorates
+// common::ScratchSurfaceCache by customizing it to be Blitter API specific.
+// A Blitter API renderer can use this class to request temporary scratch
+// SbBlitterSurfaces that can be automatically re-used over the course of a
+// frame.  CachedScratchSurface objects must be created in order to actually
+// interact with ScratchSurfaceCache.
+class ScratchSurfaceCache {
+ public:
+  // |device| specifies the |device| from which surfaces should be allocated
+  // from and |context| specifies which context to use when draw commands need
+  // to be issued (e.g. to clear a surface so it is ready for use).
+  ScratchSurfaceCache(SbBlitterDevice device, SbBlitterContext context,
+                      int cache_capacity_in_bytes);
+
+ private:
+  class Delegate : public common::ScratchSurfaceCache::Delegate {
+   public:
+    Delegate(SbBlitterDevice device, SbBlitterContext context);
+
+    common::ScratchSurfaceCache::Surface* CreateSurface(
+        const math::Size& size) OVERRIDE;
+    void DestroySurface(common::ScratchSurfaceCache::Surface* surface) OVERRIDE;
+    void PrepareForUse(common::ScratchSurfaceCache::Surface* surface,
+                       const math::Size& area) OVERRIDE;
+
+   private:
+    SbBlitterDevice device_;
+    SbBlitterContext context_;
+  };
+
+  Delegate delegate_;
+  common::ScratchSurfaceCache cache_;
+
+  friend class CachedScratchSurface;
+};
+
+// This class acts as the interface to ScratchSurfaceCache.  It does so by
+// decorating common::CachedScratchSurface and adding methods to obtain
+// a reference to the Blitter API-specific SbBlitterSurface object.
+class CachedScratchSurface {
+ public:
+  CachedScratchSurface(ScratchSurfaceCache* cache, const math::Size& size)
+      : common_scratch_surface_(&cache->cache_, size) {}
+
+  // Returns a pointer to the Blitter surface.
+  SbBlitterSurface GetSurface();
+
+ private:
+  common::CachedScratchSurface common_scratch_surface_;
+};
+
+}  // namespace blitter
+}  // namespace rasterizer
+}  // namespace renderer
+}  // namespace cobalt
+
+#endif  // SB_HAS(BLITTER)
+
+#endif  // COBALT_RENDERER_RASTERIZER_BLITTER_SCRATCH_SURFACE_CACHE_H_
diff --git a/src/cobalt/renderer/rasterizer/common/common.gyp b/src/cobalt/renderer/rasterizer/common/common.gyp
index b03b34a..3db2828 100644
--- a/src/cobalt/renderer/rasterizer/common/common.gyp
+++ b/src/cobalt/renderer/rasterizer/common/common.gyp
@@ -20,8 +20,13 @@
 
       'sources': [
         'offscreen_render_coordinate_mapping.cc',
+        'offscreen_render_coordinate_mapping.h',
+        'scratch_surface_cache.cc',
+        'scratch_surface_cache.h',
         'streaming_best_fit_line.cc',
+        'streaming_best_fit_line.h',
         'surface_cache.cc',
+        'surface_cache.h',
       ],
 
       'dependencies': [
diff --git a/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.cc b/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.cc
new file mode 100644
index 0000000..dac975b
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.cc
@@ -0,0 +1,180 @@
+/*
+ * 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/renderer/rasterizer/common/scratch_surface_cache.h"
+
+#include <limits>
+
+#include "base/debug/trace_event.h"
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace common {
+
+namespace {
+
+// Approximate the memory usage of a given surface size.
+size_t ApproximateSurfaceMemory(const math::Size& size) {
+  // Here we assume that we use 4 bytes per pixel.
+  return size.width() * size.height() * 4;
+}
+
+}  // namespace
+
+ScratchSurfaceCache::ScratchSurfaceCache(Delegate* delegate,
+                                         int cache_capacity_in_bytes)
+    : delegate_(delegate),
+      cache_capacity_in_bytes_(cache_capacity_in_bytes),
+      surface_memory_(0) {}
+
+ScratchSurfaceCache::~ScratchSurfaceCache() {
+  DCHECK(surface_stack_.empty());
+  for (std::vector<Surface*>::iterator iter = unused_surfaces_.begin();
+       iter != unused_surfaces_.end(); ++iter) {
+    delegate_->DestroySurface(*iter);
+  }
+}
+
+ScratchSurfaceCache::Surface* ScratchSurfaceCache::AcquireScratchSurface(
+    const math::Size& size) {
+  TRACE_EVENT2("cobalt::renderer",
+               "ScratchSurfaceCache::AcquireScratchSurface()", "width",
+               size.width(), "height", size.height());
+
+  // First check if we can find a suitable surface in our cache that is at
+  // least the size requested.
+  Surface* surface = FindBestCachedSurface(size);
+
+  // If we didn't have any suitable surfaces in our cache, create a new one.
+  if (!surface) {
+    // Increase our total memory used on surfaces, and then initiate a purge
+    // to reduce memory to below our cache limit, if necessary.
+    surface_memory_ += ApproximateSurfaceMemory(size);
+    Purge();
+
+    // Create the surface.
+    surface = delegate_->CreateSurface(size);
+
+    if (!surface) {
+      // We were unable to allocate a scratch surface, either because we are
+      // low on memory or because the requested surface has large dimensions.
+      // Return null.
+      surface_memory_ -= ApproximateSurfaceMemory(size);
+      return NULL;
+    }
+  }
+
+  DCHECK(surface);
+
+  // Track that we have handed out this surface.
+  surface_stack_.push_back(surface);
+
+  delegate_->PrepareForUse(surface, size);
+
+  return surface;
+}
+
+void ScratchSurfaceCache::ReleaseScratchSurface(Surface* surface) {
+  TRACE_EVENT2("cobalt::renderer",
+               "ScratchSurfaceCache::ReleaseScratchSurface()", "width",
+               surface->GetSize().width(), "height",
+               surface->GetSize().height());
+
+  DCHECK_EQ(surface_stack_.back(), surface);
+  surface_stack_.pop_back();
+
+  // Add this surface to the end (where most recently used surfaces go) of the
+  // unused surfaces list, so that it can be returned by later calls to acquire
+  // a surface.
+  unused_surfaces_.push_back(surface);
+}
+
+namespace {
+
+float GetMatchScoreForSurfaceAndSize(ScratchSurfaceCache::Surface* surface,
+                                     const math::Size& size) {
+  math::Size surface_size = surface->GetSize();
+
+  // We use the negated sum of the squared differences between the requested
+  // width/height and the surface width/height as the score.
+  // This promotes returning the smallest surface possible that has a similar
+  // ratio.
+  int width_diff = surface_size.width() - size.width();
+  int height_diff = surface_size.height() - size.height();
+
+  return -width_diff * width_diff - height_diff * height_diff;
+}
+
+}  // namespace
+
+ScratchSurfaceCache::Surface* ScratchSurfaceCache::FindBestCachedSurface(
+    const math::Size& size) {
+  // Iterate through all cached surfaces to find the one that is the best match
+  // for the given size.  The function GetMatchScoreForSurfaceAndSize() is
+  // responsible for assigning a score to a Surface/math::Size pair.
+  float max_surface_score = -std::numeric_limits<float>::infinity();
+  std::vector<Surface*>::iterator max_iter = unused_surfaces_.end();
+  for (std::vector<Surface*>::iterator iter = unused_surfaces_.begin();
+       iter != unused_surfaces_.end(); ++iter) {
+    Surface* current_surface = *iter;
+    math::Size surface_size = current_surface->GetSize();
+    if (surface_size.width() >= size.width() &&
+        surface_size.height() >= size.height()) {
+      float surface_score =
+          GetMatchScoreForSurfaceAndSize(current_surface, size);
+
+      if (surface_score > max_surface_score) {
+        max_surface_score = surface_score;
+        max_iter = iter;
+      }
+    }
+  }
+
+  // If any of the cached unused surfaces had at least the specified
+  // width/height, return the one that had the highest score.
+  if (max_iter != unused_surfaces_.end()) {
+    Surface* surface = *max_iter;
+    // Remove this surface from the list of unused surfaces.
+    unused_surfaces_.erase(max_iter);
+    // Return the cached surface.
+    return surface;
+  } else {
+    // Otherwise return NULL to indicate that we do not have any suitable cached
+    // surfaces.
+    return NULL;
+  }
+}
+
+void ScratchSurfaceCache::Purge() {
+  // Delete surfaces from the front (least recently used) of |unused_surfaces_|
+  // until we have deleted all surfaces or lowered our memory usage to under
+  // |cache_capacity_in_bytes_|.
+  while (!unused_surfaces_.empty() &&
+         surface_memory_ > cache_capacity_in_bytes_) {
+    Surface* to_free = unused_surfaces_.front();
+    math::Size surface_size = to_free->GetSize();
+    surface_memory_ -= ApproximateSurfaceMemory(
+        math::Size(surface_size.width(), surface_size.height()));
+    delegate_->DestroySurface(to_free);
+    unused_surfaces_.erase(unused_surfaces_.begin());
+  }
+}
+
+}  // namespace common
+}  // namespace rasterizer
+}  // namespace renderer
+}  // namespace cobalt
diff --git a/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.h b/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.h
new file mode 100644
index 0000000..a482ffc
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.h
@@ -0,0 +1,130 @@
+/*
+ * 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_RENDERER_RASTERIZER_COMMON_SCRATCH_SURFACE_CACHE_H_
+#define COBALT_RENDERER_RASTERIZER_COMMON_SCRATCH_SURFACE_CACHE_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "cobalt/math/size.h"
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace common {
+
+// The ScratchSurfaceCache manages a set of platform-specific surface objects
+// that can be used for offscreen rendering (e.g. by a RenderTreeNodeVisitor).
+// In order to acquire surfaces from ScratchSurfaceCache, one should construct
+// a CachedScratchSurface object, from which they can get a pointer to the
+// Surface object.
+// It is unique because it caters to RenderTreeNodeVisitor's scratch
+// surface allocation pattern.  In particular, we don't mind handing out very
+// large scratch surfaces when very small surfaces are requested, because
+// typically only one surface is ever needed at a time.  When multiple surfaces
+// are necessary, the subsequent ones tend to be smaller than the previous
+// (because rendering is now happening within the previous ones), and so handing
+// out textures in large to small order makes sense.
+class ScratchSurfaceCache {
+ public:
+  class Surface {
+   public:
+    virtual ~Surface() {}
+    virtual math::Size GetSize() const = 0;
+  };
+  class Delegate {
+   public:
+    virtual Surface* CreateSurface(const math::Size& size) = 0;
+    virtual void DestroySurface(Surface* surface) = 0;
+    virtual void PrepareForUse(Surface* surface, const math::Size& area) = 0;
+  };
+
+  ScratchSurfaceCache(Delegate* delegate, int cache_capacity_in_bytes);
+  ~ScratchSurfaceCache();
+
+ private:
+  // Acquire (either via cache lookup or by creation if that fails) a scratch
+  // surface.
+  Surface* AcquireScratchSurface(const math::Size& size);
+  void ReleaseScratchSurface(Surface* surface);
+
+  // Searches through |unused_surfaces_| for one the one that best matches the
+  // requested size, among all those cached surfaces that have at least the
+  // requested size.
+  Surface* FindBestCachedSurface(const math::Size& size);
+
+  // Removes elements from the cache until we are below the cache limit.
+  void Purge();
+
+  // Allocate a new Surface and return it.
+  Surface* CreateScratchSurface(const math::Size& size);
+
+  // Implementation-specific details about how to create/destroy surfaces.
+  Delegate* delegate_;
+
+  // The maximum number of surface bytes that can be stored in the cache.
+  int cache_capacity_in_bytes_;
+
+  // We keep track of all surfaces we've handed out using |surface_stack_|.
+  // This is mostly for debug checks to verify that surfaces returned to us
+  // actually did come from us, and that they are returned in the expected
+  // order.
+  std::vector<Surface*> surface_stack_;
+
+  // |unused_surfaces_| is the heart of the cache, as it stores the surfaces
+  // that are unused but allocated and available to be handed out upon request.
+  // Most recently used surfaces are found at the end of this vector.
+  std::vector<Surface*> unused_surfaces_;
+
+  // Tracks how much total memory we've allocated towards surfaces.
+  size_t surface_memory_;
+
+  friend class CachedScratchSurface;
+};
+
+// The primary interface to ScratchSurfaceCache is through CachedScratchSurface
+// objects.  These effectively scope the acquisition of a cached surface, RAII
+// style.
+class CachedScratchSurface {
+ public:
+  CachedScratchSurface(ScratchSurfaceCache* cache, const math::Size& size)
+      : cache_(cache) {
+    surface_ = cache_->AcquireScratchSurface(size);
+  }
+
+  ~CachedScratchSurface() {
+    if (surface_) {
+      cache_->ReleaseScratchSurface(surface_);
+    }
+  }
+
+  // Returns a pointer to the platform-specific surface.  The platform can then
+  // downcast to the expected surface type.
+  ScratchSurfaceCache::Surface* GetSurface() { return surface_; }
+
+ private:
+  ScratchSurfaceCache* cache_;
+  ScratchSurfaceCache::Surface* surface_;
+};
+
+}  // namespace common
+}  // namespace rasterizer
+}  // namespace renderer
+}  // namespace cobalt
+
+#endif  // COBALT_RENDERER_RASTERIZER_COMMON_SCRATCH_SURFACE_CACHE_H_
diff --git a/src/cobalt/renderer/rasterizer/rasterizer_benchmark.cc b/src/cobalt/renderer/rasterizer/rasterizer_benchmark.cc
index 943cb95..ca2cc73 100644
--- a/src/cobalt/renderer/rasterizer/rasterizer_benchmark.cc
+++ b/src/cobalt/renderer/rasterizer/rasterizer_benchmark.cc
@@ -134,14 +134,13 @@
 
 // Setup a quick macro so that we can measure the same events for each
 // render tree builder benchmark.
-#define RENDER_TREE_BUILDER_BENCHMARK(test_name)\
-TRACE_EVENT_BENCHMARK5(\
-    test_name, \
-    "BuildRenderTree", cobalt::trace_event::IN_SCOPE_DURATION, \
-    "NodeAnimationsMap::Apply()", cobalt::trace_event::IN_SCOPE_DURATION, \
-    "Rasterizer::Submit()", cobalt::trace_event::FLOW_DURATION, \
-    "Rasterizer::Submit()", cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS, \
-    "VisitRenderTree", cobalt::trace_event::IN_SCOPE_DURATION)
+#define RENDER_TREE_BUILDER_BENCHMARK(test_name)                              \
+  TRACE_EVENT_BENCHMARK5(                                                     \
+      test_name, "BuildRenderTree", cobalt::trace_event::IN_SCOPE_DURATION,   \
+      "AnimateNode::Apply()", cobalt::trace_event::IN_SCOPE_DURATION,         \
+      "Rasterizer::Submit()", cobalt::trace_event::FLOW_DURATION,             \
+      "Rasterizer::Submit()", cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS, \
+      "VisitRenderTree", cobalt::trace_event::IN_SCOPE_DURATION)
 
 // A catch-all test that excercises every different render tree node at the
 // same time.  This is the same render tree builder used by the renderer
diff --git a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.h b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.h
index 74f4be2..b325107 100644
--- a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.h
+++ b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.h
@@ -33,6 +33,13 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 
 namespace cobalt {
+
+namespace render_tree {
+namespace animations {
+class AnimateNode;
+}  // namespace animations
+}  // namespace render_tree
+
 namespace renderer {
 namespace rasterizer {
 namespace skia {
@@ -68,6 +75,9 @@
       SurfaceCacheDelegate* surface_cache_delegate,
       common::SurfaceCache* surface_cache, Type visitor_type = kType_Normal);
 
+  void Visit(render_tree::animations::AnimateNode* animate_node) OVERRIDE {
+    NOTREACHED();
+  }
   void Visit(render_tree::CompositionNode* composition_node) OVERRIDE;
   void Visit(render_tree::FilterNode* filter_node) OVERRIDE;
   void Visit(render_tree::ImageNode* image_node) OVERRIDE;
diff --git a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
index 1b62b9c..409c787 100644
--- a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
+++ b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
@@ -16,10 +16,7 @@
 
 #include "cobalt/renderer/rasterizer/skia/scratch_surface_cache.h"
 
-#include <limits>
-
-#include "base/debug/trace_event.h"
-
+#include "cobalt/base/polymorphic_downcast.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 
 namespace cobalt {
@@ -29,160 +26,68 @@
 
 namespace {
 
-// Approximate the memory usage of a given surface size.
-size_t ApproximateSurfaceMemory(const math::Size& size) {
-  // Here we assume that we use 4 bytes per pixel.
-  return size.width() * size.height() * 4;
-}
+class SkiaSurface : public common::ScratchSurfaceCache::Surface {
+ public:
+  SkiaSurface(SkSurface* surface, const math::Size& size)
+      : surface_(surface), size_(size) {}
 
+  math::Size GetSize() const OVERRIDE { return size_; }
+
+  SkSurface* sk_surface() { return surface_.get(); }
+
+ private:
+  SkAutoTUnref<SkSurface> surface_;
+  math::Size size_;
+};
 }  // namespace
 
 ScratchSurfaceCache::ScratchSurfaceCache(
-    const CreateSkSurfaceFunction& create_sk_surface_function,
+    CreateSkSurfaceFunction create_sk_surface_function,
     int cache_capacity_in_bytes)
-    : create_sk_surface_function_(create_sk_surface_function),
-      cache_capacity_in_bytes_(cache_capacity_in_bytes),
-      surface_memory_(0) {}
+    : delegate_(create_sk_surface_function),
+      cache_(&delegate_, cache_capacity_in_bytes) {}
 
-ScratchSurfaceCache::~ScratchSurfaceCache() {
-  DCHECK(surface_stack_.empty());
-  for (std::vector<SkSurface*>::iterator iter = unused_surfaces_.begin();
-       iter != unused_surfaces_.end(); ++iter) {
-    (*iter)->unref();
-  }
+ScratchSurfaceCache::Delegate::Delegate(
+    CreateSkSurfaceFunction create_sk_surface_function)
+    : create_sk_surface_function_(create_sk_surface_function) {}
+
+common::ScratchSurfaceCache::Surface*
+ScratchSurfaceCache::Delegate::CreateSurface(const math::Size& size) {
+  return new SkiaSurface(create_sk_surface_function_.Run(size), size);
 }
 
-SkSurface* ScratchSurfaceCache::AcquireScratchSurface(const math::Size& size) {
-  TRACE_EVENT2("cobalt::renderer",
-               "ScratchSurfaceCache::AcquireScratchSurface()", "width",
-               size.width(), "height", size.height());
+void ScratchSurfaceCache::Delegate::DestroySurface(
+    common::ScratchSurfaceCache::Surface* surface) {
+  delete surface;
+}
 
-  // First check if we can find a suitable surface in our cache that is at
-  // least the size requested.
-  SkSurface* surface = FindBestCachedSurface(size);
+void ScratchSurfaceCache::Delegate::PrepareForUse(
+    common::ScratchSurfaceCache::Surface* surface, const math::Size& area) {
+  SkSurface* sk_surface =
+      base::polymorphic_downcast<SkiaSurface*>(surface)->sk_surface();
 
-  // If we didn't have any suitable surfaces in our cache, create a new one.
-  if (!surface) {
-    // Increase our total memory used on surfaces, and then initiate a purge
-    // to reduce memory to below our cache limit, if necessary.
-    surface_memory_ += ApproximateSurfaceMemory(size);
-    Purge();
-
-    // Create the surface.
-    surface = create_sk_surface_function_.Run(size);
-
-    if (!surface) {
-      // We were unable to allocate a scratch surface, either because we are
-      // low on memory or because the requested surface has large dimensions.
-      // Return null.
-      surface_memory_ -= ApproximateSurfaceMemory(size);
-      return NULL;
-    }
-  }
-
-  DCHECK(surface);
-
-  // Track that we have handed out this surface.
-  surface_stack_.push_back(surface);
-
-  // Reset the surface's canvas settings such as transform matrix and clip.
-  SkCanvas* canvas = surface->getCanvas();
+  // Reset the sk_surface's canvas settings such as transform matrix and clip.
+  SkCanvas* canvas = sk_surface->getCanvas();
   canvas->restoreToCount(1);
   // Setup a save marker on the reset canvas so that we can restore this reset
-  // state when re-using the surface.
+  // state when re-using the sk_surface.
   canvas->save();
 
-  // Setup a clip rect on the surface to the requested size.  This can save
-  // us from drawing to pixels outside of the requested size, since the actual
-  // surface returned may be larger than the requested size.
-  canvas->clipRect(SkRect::MakeWH(size.width(), size.height()),
+  // Setup a clip rect on the sk_surface to the requested area.  This can save
+  // us from drawing to pixels outside of the requested area, since the actual
+  // sk_surface returned may be larger than the requested area.
+  canvas->clipRect(SkRect::MakeWH(area.width(), area.height()),
                    SkRegion::kReplace_Op);
 
   // Clear the draw area to RGBA(0, 0, 0, 0), as expected for a fresh scratch
-  // surface, before returning.
+  // sk_surface, before returning.
   canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
-
-  return surface;
 }
 
-void ScratchSurfaceCache::ReleaseScratchSurface(SkSurface* surface) {
-  TRACE_EVENT2("cobalt::renderer",
-               "ScratchSurfaceCache::ReleaseScratchSurface()", "width",
-               surface->width(), "height", surface->height());
-
-  DCHECK_EQ(surface_stack_.back(), surface);
-  surface_stack_.pop_back();
-
-  // Add this surface to the end (where most recently used surfaces go) of the
-  // unused surfaces list, so that it can be returned by later calls to acquire
-  // a surface.
-  unused_surfaces_.push_back(surface);
-}
-
-namespace {
-
-float GetMatchScoreForSurfaceAndSize(SkSurface* surface,
-                                     const math::Size& size) {
-  // We use the negated sum of the squared differences between the requested
-  // width/height and the surface width/height as the score.
-  // This promotes returning the smallest surface possible that has a similar
-  // ratio.
-  int width_diff = surface->width() - size.width();
-  int height_diff = surface->height() - size.height();
-
-  return -width_diff * width_diff - height_diff * height_diff;
-}
-
-}  // namespace
-
-SkSurface* ScratchSurfaceCache::FindBestCachedSurface(const math::Size& size) {
-  // Iterate through all cached surfaces to find the one that is the best match
-  // for the given size.  The function GetMatchScoreForSurfaceAndSize() is
-  // responsible for assigning a score to a SkSurface/math::Size pair.
-  float max_surface_score = -std::numeric_limits<float>::infinity();
-  std::vector<SkSurface*>::iterator max_iter = unused_surfaces_.end();
-  for (std::vector<SkSurface*>::iterator iter = unused_surfaces_.begin();
-       iter != unused_surfaces_.end(); ++iter) {
-    SkSurface* current_surface = *iter;
-    if (current_surface->width() >= size.width() &&
-        current_surface->height() >= size.height()) {
-      float surface_score =
-          GetMatchScoreForSurfaceAndSize(current_surface, size);
-
-      if (surface_score > max_surface_score) {
-        max_surface_score = surface_score;
-        max_iter = iter;
-      }
-    }
-  }
-
-  // If any of the cached unused surfaces had at least the specified
-  // width/height, return the one that had the highest score.
-  if (max_iter != unused_surfaces_.end()) {
-    SkSurface* surface = *max_iter;
-    // Remove this surface from the list of unused surfaces.
-    unused_surfaces_.erase(max_iter);
-    // Return the cached surface.
-    return surface;
-  } else {
-    // Otherwise return NULL to indicate that we do not have any suitable cached
-    // surfaces.
-    return NULL;
-  }
-}
-
-void ScratchSurfaceCache::Purge() {
-  // Delete surfaces from the front (least recently used) of |unused_surfaces_|
-  // until we have deleted all surfaces or lowered our memory usage to under
-  // |cache_capacity_in_bytes_|.
-  while (!unused_surfaces_.empty() &&
-         surface_memory_ > cache_capacity_in_bytes_) {
-    SkSurface* to_free = unused_surfaces_.front();
-    surface_memory_ -= ApproximateSurfaceMemory(
-        math::Size(to_free->width(), to_free->height()));
-    to_free->unref();
-    unused_surfaces_.erase(unused_surfaces_.begin());
-  }
+SkSurface* CachedScratchSurface::GetSurface() {
+  return base::polymorphic_downcast<SkiaSurface*>(
+             common_scratch_surface_.GetSurface())
+      ->sk_surface();
 }
 
 }  // namespace skia
diff --git a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.h b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.h
index 374cc66..eaf7ea5 100644
--- a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.h
+++ b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.h
@@ -22,96 +22,52 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "cobalt/math/size.h"
+#include "cobalt/renderer/rasterizer/common/scratch_surface_cache.h"
 #include "third_party/skia/include/core/SkSurface.h"
-#include "third_party/skia/include/core/SkSurfaceProps.h"
 
 namespace cobalt {
 namespace renderer {
 namespace rasterizer {
 namespace skia {
 
-// The ScratchSurfaceCache manages a set of Skia SkSurface objects that can
-// be used for offscreen rendering (mainly by SkiaRenderTreeNodeVisitor).
-// In order to acquire surfaces from ScratchSurfaceCache, one should construct
-// a CachedScratchSurface object, from which they can get a pointer to the
-// SkSurface object.
-// It is unique because it caters to SkiaRenderTreeNodeVisitor's scratch
-// surface allocation pattern.  In particular, we don't mind handing out very
-// large scratch surfaces when very small surfaces are requested, because
-// typically only one surface is ever needed at a time.  When multiple surfaces
-// are necessary, the subsequent ones tend to be smaller than the previous
-// (because rendering is now happening within the previous ones), and so handing
-// out textures in large to small order makes sense.
 class ScratchSurfaceCache {
  public:
   typedef base::Callback<SkSurface*(const math::Size&)> CreateSkSurfaceFunction;
 
-  ScratchSurfaceCache(const CreateSkSurfaceFunction& create_sk_surface_function,
+  ScratchSurfaceCache(CreateSkSurfaceFunction create_sk_surface_function,
                       int cache_capacity_in_bytes);
-  ~ScratchSurfaceCache();
 
  private:
-  // Acquire (either via cache lookup or by creation if that fails) a scratch
-  // surface.
-  SkSurface* AcquireScratchSurface(const math::Size& size);
-  void ReleaseScratchSurface(SkSurface* surface);
+  class Delegate : public common::ScratchSurfaceCache::Delegate {
+   public:
+    explicit Delegate(CreateSkSurfaceFunction create_sk_surface_function);
 
-  // Searches through |unused_surfaces_| for one the one that best matches the
-  // requested size, among all those cached surfaces that have at least the
-  // requested size.
-  SkSurface* FindBestCachedSurface(const math::Size& size);
+    common::ScratchSurfaceCache::Surface* CreateSurface(
+        const math::Size& size) OVERRIDE;
+    void DestroySurface(common::ScratchSurfaceCache::Surface* surface) OVERRIDE;
+    void PrepareForUse(common::ScratchSurfaceCache::Surface* surface,
+                       const math::Size& area) OVERRIDE;
 
-  // Removes elements from the cache until we are below the cache limit.
-  void Purge();
+   private:
+    CreateSkSurfaceFunction create_sk_surface_function_;
+  };
 
-  // Allocate a new SkSurface and return it.
-  SkSurface* CreateScratchSurface(const math::Size& size);
-
-  // Called to allocate new SkSurfaces.
-  CreateSkSurfaceFunction create_sk_surface_function_;
-
-  // The maximum number of surface bytes that can be stored in the cache.
-  int cache_capacity_in_bytes_;
-
-  // We keep track of all surfaces we've handed out using |surface_stack_|.
-  // This is mostly for debug checks to verify that surfaces returned to us
-  // actually did come from us, and that they are returned in the expected
-  // order.
-  std::vector<SkSurface*> surface_stack_;
-
-  // |unused_surfaces_| is the heart of the cache, as it stores the surfaces
-  // that are unused but allocated and available to be handed out upon request.
-  // Most recently used surfaces are found at the end of this vector.
-  std::vector<SkSurface*> unused_surfaces_;
-
-  // Tracks how much total memory we've allocated towards surfaces.
-  size_t surface_memory_;
+  Delegate delegate_;
+  common::ScratchSurfaceCache cache_;
 
   friend class CachedScratchSurface;
 };
 
-// The primary interface to ScratchSurfaceCache is through CachedScratchSurface
-// objects.  These effectively scope the acquisition of a cached surface, RAII
-// style.
 class CachedScratchSurface {
  public:
   CachedScratchSurface(ScratchSurfaceCache* cache, const math::Size& size)
-      : cache_(cache) {
-    surface_ = cache_->AcquireScratchSurface(size);
-  }
-
-  ~CachedScratchSurface() {
-    if (surface_) {
-      cache_->ReleaseScratchSurface(surface_);
-    }
-  }
+      : common_scratch_surface_(&cache->cache_, size) {}
 
   // Returns a pointer to the Skia SkSurface.
-  SkSurface* GetSurface() { return surface_; }
+  SkSurface* GetSurface();
 
  private:
-  ScratchSurfaceCache* cache_;
-  SkSurface* surface_;
+  common::CachedScratchSurface common_scratch_surface_;
 };
 
 }  // namespace skia
diff --git a/src/cobalt/renderer/renderer_module_default_options_starboard.cc b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
index 50a38f0..db5086b 100644
--- a/src/cobalt/renderer/renderer_module_default_options_starboard.cc
+++ b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
@@ -53,7 +53,8 @@
 #else
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::blitter::HardwareRasterizer(
-          graphics_context, options.surface_cache_size_in_bytes));
+          graphics_context, options.scratch_surface_cache_size_in_bytes,
+          options.surface_cache_size_in_bytes));
 #endif  // COBALT_FORCE_SOFTWARE_RASTERIZER
 #else
 #error "Either GLES2 or the Starboard Blitter API must be available."
diff --git a/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc b/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc
index dc54939..3fddb14 100644
--- a/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc
+++ b/src/cobalt/renderer/sandbox/renderer_sandbox_main.cc
@@ -30,7 +30,6 @@
 using cobalt::render_tree::ResourceProvider;
 using cobalt::renderer::test::scenes::AddBlankBackgroundToScene;
 using cobalt::renderer::test::scenes::CreateAllScenesCombinedScene;
-using cobalt::renderer::test::scenes::RenderTreeWithAnimations;
 using cobalt::system_window::SystemWindow;
 
 namespace {
@@ -67,7 +66,7 @@
   // Construct our render tree and associated animations to be passed into
   // the renderer pipeline for display.
   base::TimeDelta start_time = base::Time::Now() - base::Time::UnixEpoch();
-  RenderTreeWithAnimations scene = AddBlankBackgroundToScene(
+  scoped_refptr<cobalt::render_tree::Node> scene = AddBlankBackgroundToScene(
       CreateAllScenesCombinedScene(
           renderer_module_->pipeline()->GetResourceProvider(),
           output_dimensions, start_time),
@@ -75,8 +74,8 @@
 
   // Pass the render tree along with associated animations into the renderer
   // module to be displayed.
-  renderer_module_->pipeline()->Submit(cobalt::renderer::Submission(
-      scene.render_tree, scene.animations, start_time));
+  renderer_module_->pipeline()->Submit(
+      cobalt::renderer::Submission(scene, start_time));
 }
 
 RendererSandbox* g_renderer_sandbox = NULL;
diff --git a/src/cobalt/renderer/sandbox/scaling_text_sandbox_main.cc b/src/cobalt/renderer/sandbox/scaling_text_sandbox_main.cc
index 20f2685..71d2f04 100644
--- a/src/cobalt/renderer/sandbox/scaling_text_sandbox_main.cc
+++ b/src/cobalt/renderer/sandbox/scaling_text_sandbox_main.cc
@@ -30,7 +30,6 @@
 using cobalt::render_tree::ResourceProvider;
 using cobalt::renderer::test::scenes::AddBlankBackgroundToScene;
 using cobalt::renderer::test::scenes::CreateScalingTextScene;
-using cobalt::renderer::test::scenes::RenderTreeWithAnimations;
 using cobalt::system_window::SystemWindow;
 
 namespace {
@@ -62,15 +61,15 @@
   // Construct our render tree and associated animations to be passed into
   // the renderer pipeline for display.
   base::TimeDelta start_time = base::Time::Now() - base::Time::UnixEpoch();
-  RenderTreeWithAnimations scene = AddBlankBackgroundToScene(
+  scoped_refptr<cobalt::render_tree::Node> scene = AddBlankBackgroundToScene(
       CreateScalingTextScene(renderer_module.pipeline()->GetResourceProvider(),
                              output_dimensions, start_time),
       output_dimensions);
 
   // Pass the render tree along with associated animations into the renderer
   // module to be displayed.
-  renderer_module.pipeline()->Submit(cobalt::renderer::Submission(
-      scene.render_tree, scene.animations, start_time));
+  renderer_module.pipeline()->Submit(
+      cobalt::renderer::Submission(scene, start_time));
 
   base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(30));
 
diff --git a/src/cobalt/renderer/submission.h b/src/cobalt/renderer/submission.h
index 7cc86f2..2652e35 100644
--- a/src/cobalt/renderer/submission.h
+++ b/src/cobalt/renderer/submission.h
@@ -21,7 +21,7 @@
 #include "base/debug/trace_event.h"
 #include "base/memory/ref_counted.h"
 #include "base/time.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 #include "cobalt/render_tree/node.h"
 
 namespace cobalt {
@@ -32,20 +32,14 @@
   // Convenience constructor that assumes there are no animations and sets up
   // an empty animation map.
   explicit Submission(scoped_refptr<render_tree::Node> render_tree)
-      : render_tree(render_tree),
-        animations(new render_tree::animations::NodeAnimationsMap(
-            render_tree::animations::NodeAnimationsMap::Builder().Pass())) {}
+      : render_tree(render_tree) {}
 
   // Submit a render tree as well as associated animations.  The
   // time_offset parameter indicates a time that will be used to offset all
   // times passed into animation functions.
-  Submission(
-      scoped_refptr<render_tree::Node> render_tree,
-      scoped_refptr<render_tree::animations::NodeAnimationsMap> animations,
-      base::TimeDelta time_offset)
-      : render_tree(render_tree),
-        animations(animations),
-        time_offset(time_offset) {}
+  Submission(scoped_refptr<render_tree::Node> render_tree,
+             base::TimeDelta time_offset)
+      : render_tree(render_tree), time_offset(time_offset) {}
 
   ~Submission() {
     TRACE_EVENT0("cobalt::renderer", "~Submission()");
@@ -53,17 +47,11 @@
     // Explicitly dereference the render tree and animation under the scope of
     // the above trace event.
     render_tree = NULL;
-    animations = NULL;
   }
 
   // Maintains the current render tree that is to be rendered next frame.
   scoped_refptr<render_tree::Node> render_tree;
 
-  // Maintains the current animations that are to be in effect (i.e. applied
-  // to current_tree_) for all rasterizations until specifically updated by a
-  // call to Submit().
-  scoped_refptr<render_tree::animations::NodeAnimationsMap> animations;
-
   // The time from some origin that the associated render tree animations were
   // created.  This permits the render thread to compute times relative
   // to the same origin when updating the animations, as well as hinting
diff --git a/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.cc b/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.cc
index ff5045a..133aa88 100644
--- a/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.cc
+++ b/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.cc
@@ -29,48 +29,41 @@
 using cobalt::math::SizeF;
 using cobalt::render_tree::CompositionNode;
 using cobalt::render_tree::ResourceProvider;
-using cobalt::render_tree::animations::NodeAnimationsMap;
+using cobalt::render_tree::animations::AnimateNode;
 
 namespace cobalt {
 namespace renderer {
 namespace test {
 namespace scenes {
 
-RenderTreeWithAnimations CreateAllScenesCombinedScene(
+scoped_refptr<render_tree::Node> CreateAllScenesCombinedScene(
     ResourceProvider* resource_provider, const SizeF& output_dimensions,
     base::TimeDelta start_time) {
   TRACE_EVENT0("cobalt::renderer_sandbox",
                "CreateAllScenesCombinedScene()");
   CompositionNode::Builder all_scenes_combined_scene_builder;
-  NodeAnimationsMap::Builder animations;
 
   // Compose all the render trees representing the sub-scenes through a
   // composition node, and merge the animations into one large set.
-  RenderTreeWithAnimations growing_rect_scene =
+  scoped_refptr<render_tree::Node> growing_rect_scene =
       CreateGrowingRectScene(output_dimensions, start_time);
-  all_scenes_combined_scene_builder.AddChild(growing_rect_scene.render_tree);
-  animations.Merge(*growing_rect_scene.animations);
+  all_scenes_combined_scene_builder.AddChild(growing_rect_scene);
 
-  RenderTreeWithAnimations spinning_sprites_scene =
-      CreateSpinningSpritesScene(
-          resource_provider, output_dimensions, start_time);
-  all_scenes_combined_scene_builder.AddChild(
-      spinning_sprites_scene.render_tree);
-  animations.Merge(*spinning_sprites_scene.animations);
+  scoped_refptr<render_tree::Node> spinning_sprites_scene =
+      CreateSpinningSpritesScene(resource_provider, output_dimensions,
+                                 start_time);
+  all_scenes_combined_scene_builder.AddChild(spinning_sprites_scene);
 
-  RenderTreeWithAnimations image_wrap_scene =
+  scoped_refptr<render_tree::Node> image_wrap_scene =
       CreateImageWrapScene(resource_provider, output_dimensions, start_time);
-  all_scenes_combined_scene_builder.AddChild(image_wrap_scene.render_tree);
-  animations.Merge(*image_wrap_scene.animations);
+  all_scenes_combined_scene_builder.AddChild(image_wrap_scene);
 
-  RenderTreeWithAnimations marquee_scene =
+  scoped_refptr<render_tree::Node> marquee_scene =
       CreateMarqueeScene(resource_provider, output_dimensions, start_time);
-  all_scenes_combined_scene_builder.AddChild(marquee_scene.render_tree);
-  animations.Merge(*marquee_scene.animations);
+  all_scenes_combined_scene_builder.AddChild(marquee_scene);
 
-  return RenderTreeWithAnimations(
-      new CompositionNode(all_scenes_combined_scene_builder.Pass()),
-      new NodeAnimationsMap(animations.Pass()));
+  return new AnimateNode(
+      new CompositionNode(all_scenes_combined_scene_builder.Pass()));
 }
 
 }  // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.h b/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.h
index 2d098fc..e5c1eec 100644
--- a/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.h
+++ b/src/cobalt/renderer/test/scenes/all_scenes_combined_scene.h
@@ -29,7 +29,7 @@
 
 // This scene will simply composite all other scene types together into one
 // mega scene.
-RenderTreeWithAnimations CreateAllScenesCombinedScene(
+scoped_refptr<render_tree::Node> CreateAllScenesCombinedScene(
     render_tree::ResourceProvider* resource_provider,
     const math::SizeF& output_dimensions, base::TimeDelta start_time);
 
diff --git a/src/cobalt/renderer/test/scenes/growing_rect_scene.cc b/src/cobalt/renderer/test/scenes/growing_rect_scene.cc
index 54edd16..1f06a4b 100644
--- a/src/cobalt/renderer/test/scenes/growing_rect_scene.cc
+++ b/src/cobalt/renderer/test/scenes/growing_rect_scene.cc
@@ -27,15 +27,15 @@
 using cobalt::math::ScaleMatrix;
 using cobalt::math::SizeF;
 using cobalt::math::TranslateMatrix;
+using cobalt::render_tree::animations::AnimateNode;
+using cobalt::render_tree::animations::Animation;
+using cobalt::render_tree::animations::AnimationList;
 using cobalt::render_tree::Brush;
 using cobalt::render_tree::ColorRGBA;
 using cobalt::render_tree::MatrixTransformNode;
 using cobalt::render_tree::Node;
 using cobalt::render_tree::RectNode;
 using cobalt::render_tree::SolidColorBrush;
-using cobalt::render_tree::animations::Animation;
-using cobalt::render_tree::animations::AnimationList;
-using cobalt::render_tree::animations::NodeAnimationsMap;
 
 namespace cobalt {
 namespace renderer {
@@ -62,13 +62,13 @@
 
 }  // namespace
 
-RenderTreeWithAnimations CreateGrowingRectScene(
+scoped_refptr<render_tree::Node> CreateGrowingRectScene(
     const math::SizeF& output_dimensions, base::TimeDelta start_time) {
   // Create a centered, sawtoothed-growing black rectangle.  We need a
   // composition node for this so that the rectangle's position can be set
   // and animated.  We also use the composition node to animate the RectNode's
   // size.
-  NodeAnimationsMap::Builder animations;
+  AnimateNode::Builder animations;
 
   scoped_refptr<RectNode> growing_rect_node(new RectNode(
       math::RectF(output_dimensions),
@@ -81,8 +81,7 @@
                  base::Bind(&AnimateGrowingRectComposition, start_time,
                             output_dimensions));
 
-  return RenderTreeWithAnimations(transformed_growing_rect,
-                                  new NodeAnimationsMap(animations.Pass()));
+  return new AnimateNode(animations, transformed_growing_rect);
 }
 
 }  // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/growing_rect_scene.h b/src/cobalt/renderer/test/scenes/growing_rect_scene.h
index d57c5b7..9ffabbc 100644
--- a/src/cobalt/renderer/test/scenes/growing_rect_scene.h
+++ b/src/cobalt/renderer/test/scenes/growing_rect_scene.h
@@ -28,7 +28,7 @@
 
 // This scene gives a gray rectangle centered in the screen that slowly grows
 // to fill the screen.
-RenderTreeWithAnimations CreateGrowingRectScene(
+scoped_refptr<render_tree::Node> CreateGrowingRectScene(
     const math::SizeF& output_dimensions, base::TimeDelta start_time);
 
 }  // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/image_wrap_scene.cc b/src/cobalt/renderer/test/scenes/image_wrap_scene.cc
index ee70281..1add5b4 100644
--- a/src/cobalt/renderer/test/scenes/image_wrap_scene.cc
+++ b/src/cobalt/renderer/test/scenes/image_wrap_scene.cc
@@ -34,15 +34,15 @@
 
 using cobalt::math::Matrix3F;
 using cobalt::math::SizeF;
+using cobalt::render_tree::animations::AnimateNode;
+using cobalt::render_tree::animations::Animation;
+using cobalt::render_tree::animations::AnimationList;
 using cobalt::render_tree::CompositionNode;
 using cobalt::render_tree::Image;
 using cobalt::render_tree::ImageNode;
 using cobalt::render_tree::MatrixTransformNode;
 using cobalt::render_tree::Node;
 using cobalt::render_tree::ResourceProvider;
-using cobalt::render_tree::animations::Animation;
-using cobalt::render_tree::animations::AnimationList;
-using cobalt::render_tree::animations::NodeAnimationsMap;
 using cobalt::renderer::test::png_utils::DecodePNGToRenderTreeImage;
 
 namespace cobalt {
@@ -89,10 +89,10 @@
 
 }  // namespace
 
-RenderTreeWithAnimations CreateImageWrapScene(
+scoped_refptr<render_tree::Node> CreateImageWrapScene(
     ResourceProvider* resource_provider, const math::SizeF& output_dimensions,
     base::TimeDelta start_time) {
-  NodeAnimationsMap::Builder animations;
+  AnimateNode::Builder animations;
 
   // Create an image node that will have its local_transform animated to
   // demonstrate what local_transform allows one to do.
@@ -107,8 +107,7 @@
 
   animations.Add(image_node, base::Bind(&AnimateImage, start_time));
 
-  return RenderTreeWithAnimations(
-      image_wrap_scene, new NodeAnimationsMap(animations.Pass()));
+  return new AnimateNode(animations, image_wrap_scene);
 }
 
 }  // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/image_wrap_scene.h b/src/cobalt/renderer/test/scenes/image_wrap_scene.h
index 4c2d631..27726ff 100644
--- a/src/cobalt/renderer/test/scenes/image_wrap_scene.h
+++ b/src/cobalt/renderer/test/scenes/image_wrap_scene.h
@@ -31,7 +31,7 @@
 // shrunk, and so the texture repeats to fill the size of the image node.
 // The texture is also spinning.  This scene effectively shows off
 // ImageNode's local_matrix parameter.
-RenderTreeWithAnimations CreateImageWrapScene(
+scoped_refptr<render_tree::Node> CreateImageWrapScene(
     render_tree::ResourceProvider* resource_provider,
     const math::SizeF& output_dimensions, base::TimeDelta start_time);
 
diff --git a/src/cobalt/renderer/test/scenes/marquee_scene.cc b/src/cobalt/renderer/test/scenes/marquee_scene.cc
index f2630ce..3d44382 100644
--- a/src/cobalt/renderer/test/scenes/marquee_scene.cc
+++ b/src/cobalt/renderer/test/scenes/marquee_scene.cc
@@ -33,6 +33,9 @@
 using cobalt::math::RectF;
 using cobalt::math::SizeF;
 using cobalt::math::TranslateMatrix;
+using cobalt::render_tree::animations::AnimateNode;
+using cobalt::render_tree::animations::Animation;
+using cobalt::render_tree::animations::AnimationList;
 using cobalt::render_tree::Brush;
 using cobalt::render_tree::ColorRGBA;
 using cobalt::render_tree::CompositionNode;
@@ -45,9 +48,6 @@
 using cobalt::render_tree::ResourceProvider;
 using cobalt::render_tree::SolidColorBrush;
 using cobalt::render_tree::TextNode;
-using cobalt::render_tree::animations::Animation;
-using cobalt::render_tree::animations::AnimationList;
-using cobalt::render_tree::animations::NodeAnimationsMap;
 
 namespace cobalt {
 namespace renderer {
@@ -85,11 +85,11 @@
 
 }  // namespace
 
-RenderTreeWithAnimations CreateMarqueeScene(
+scoped_refptr<render_tree::Node> CreateMarqueeScene(
     ResourceProvider* resource_provider, const math::SizeF& output_dimensions,
     base::TimeDelta start_time) {
   CompositionNode::Builder marquee_scene_builder;
-  NodeAnimationsMap::Builder animations;
+  AnimateNode::Builder animations;
 
   const std::string kMarqueeText("YouTube");
 
@@ -130,8 +130,7 @@
   animations.Add(marquee_node, base::Bind(&AnimateMarqueeElement, start_time,
                                           text_bounds, output_dimensions));
 
-  return RenderTreeWithAnimations(marquee_node,
-                                  new NodeAnimationsMap(animations.Pass()));
+  return new AnimateNode(animations, marquee_node);
 }
 
 }  // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/marquee_scene.h b/src/cobalt/renderer/test/scenes/marquee_scene.h
index 0d15965..5b2055a 100644
--- a/src/cobalt/renderer/test/scenes/marquee_scene.h
+++ b/src/cobalt/renderer/test/scenes/marquee_scene.h
@@ -29,7 +29,7 @@
 
 // This render tree builder will create a scene containing highlighted
 // text scrolling smoothly from left to right.
-RenderTreeWithAnimations CreateMarqueeScene(
+scoped_refptr<render_tree::Node> CreateMarqueeScene(
     render_tree::ResourceProvider* resource_provider,
     const math::SizeF& output_dimensions, base::TimeDelta start_time);
 
diff --git a/src/cobalt/renderer/test/scenes/scaling_text_scene.cc b/src/cobalt/renderer/test/scenes/scaling_text_scene.cc
index 4ac33b5..952b03b 100644
--- a/src/cobalt/renderer/test/scenes/scaling_text_scene.cc
+++ b/src/cobalt/renderer/test/scenes/scaling_text_scene.cc
@@ -45,7 +45,7 @@
 using cobalt::render_tree::TextNode;
 using cobalt::render_tree::animations::Animation;
 using cobalt::render_tree::animations::AnimationList;
-using cobalt::render_tree::animations::NodeAnimationsMap;
+using cobalt::render_tree::animations::AnimateNode;
 
 namespace cobalt {
 namespace renderer {
@@ -62,7 +62,7 @@
 
 }  // namespace
 
-RenderTreeWithAnimations CreateScalingTextScene(
+scoped_refptr<render_tree::Node> CreateScalingTextScene(
     ResourceProvider* resource_provider, const math::SizeF& output_dimensions,
     base::TimeDelta start_time) {
   const std::string kText(
@@ -91,11 +91,10 @@
       Matrix3F::Identity()));
 
   // Setup the scaling animation on the text
-  NodeAnimationsMap::Builder animations;
+  AnimateNode::Builder animations;
   animations.Add(scaling_text_node, base::Bind(&ScaleText));
 
-  return RenderTreeWithAnimations(scaling_text_node,
-                                  new NodeAnimationsMap(animations.Pass()));
+  return new AnimateNode(animations, scaling_text_node);
 }
 
 }  // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/scaling_text_scene.h b/src/cobalt/renderer/test/scenes/scaling_text_scene.h
index c6d8771..4b3226d 100644
--- a/src/cobalt/renderer/test/scenes/scaling_text_scene.h
+++ b/src/cobalt/renderer/test/scenes/scaling_text_scene.h
@@ -31,7 +31,7 @@
 // scale being applied to it, and the scale of all text is animated.
 // This is very useful for investigating issues with text scaling, which
 // internally can be quite non-trivial.
-RenderTreeWithAnimations CreateScalingTextScene(
+scoped_refptr<render_tree::Node> CreateScalingTextScene(
     render_tree::ResourceProvider* resource_provider,
     const math::SizeF& output_dimensions, base::TimeDelta start_time);
 
diff --git a/src/cobalt/renderer/test/scenes/scene_helpers.cc b/src/cobalt/renderer/test/scenes/scene_helpers.cc
index 724142c..39aa8d5 100644
--- a/src/cobalt/renderer/test/scenes/scene_helpers.cc
+++ b/src/cobalt/renderer/test/scenes/scene_helpers.cc
@@ -36,8 +36,8 @@
 namespace test {
 namespace scenes {
 
-RenderTreeWithAnimations AddBlankBackgroundToScene(
-    const RenderTreeWithAnimations& scene,
+scoped_refptr<render_tree::Node> AddBlankBackgroundToScene(
+    const scoped_refptr<render_tree::Node>& scene,
     const SizeF& output_dimensions) {
   // Declare a rectangle that fills the background to effectively clear the
   // screen.
@@ -45,10 +45,10 @@
   with_background_scene_builder.AddChild(make_scoped_refptr(new RectNode(
       RectF(output_dimensions),
       scoped_ptr<Brush>(new SolidColorBrush(ColorRGBA(1.0f, 1.0f, 1.0f))))));
-  with_background_scene_builder.AddChild(scene.render_tree);
+  with_background_scene_builder.AddChild(scene);
 
-  return RenderTreeWithAnimations(new CompositionNode(
-      with_background_scene_builder.Pass()), scene.animations);
+  return new render_tree::animations::AnimateNode(
+      new CompositionNode(with_background_scene_builder.Pass()));
 }
 
 }  // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/scene_helpers.h b/src/cobalt/renderer/test/scenes/scene_helpers.h
index 67b6ab1..7c84d41 100644
--- a/src/cobalt/renderer/test/scenes/scene_helpers.h
+++ b/src/cobalt/renderer/test/scenes/scene_helpers.h
@@ -18,7 +18,7 @@
 #define COBALT_RENDERER_TEST_SCENES_SCENE_HELPERS_H_
 
 #include "cobalt/math/size_f.h"
-#include "cobalt/render_tree/animations/node_animations_map.h"
+#include "cobalt/render_tree/animations/animate_node.h"
 #include "cobalt/render_tree/node.h"
 
 namespace cobalt {
@@ -30,18 +30,8 @@
 // animations.
 inline float Sawtooth(float x) { return x - static_cast<int>(x); }
 
-struct RenderTreeWithAnimations {
-  RenderTreeWithAnimations(
-      scoped_refptr<render_tree::Node> render_tree,
-      scoped_refptr<render_tree::animations::NodeAnimationsMap> animations)
-      : render_tree(render_tree), animations(animations) {}
-
-  scoped_refptr<render_tree::Node> render_tree;
-  scoped_refptr<render_tree::animations::NodeAnimationsMap> animations;
-};
-
-RenderTreeWithAnimations AddBlankBackgroundToScene(
-    const RenderTreeWithAnimations& scene,
+scoped_refptr<render_tree::Node> AddBlankBackgroundToScene(
+    const scoped_refptr<render_tree::Node>& scene,
     const math::SizeF& output_dimensions);
 
 }  // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/spinning_sprites_scene.cc b/src/cobalt/renderer/test/scenes/spinning_sprites_scene.cc
index c338454..e54d4b0 100644
--- a/src/cobalt/renderer/test/scenes/spinning_sprites_scene.cc
+++ b/src/cobalt/renderer/test/scenes/spinning_sprites_scene.cc
@@ -35,20 +35,20 @@
 
 using cobalt::math::Matrix3F;
 using cobalt::math::PointF;
-using cobalt::math::RotateMatrix;
 using cobalt::math::RectF;
+using cobalt::math::RotateMatrix;
 using cobalt::math::ScaleMatrix;
 using cobalt::math::SizeF;
 using cobalt::math::TranslateMatrix;
+using cobalt::render_tree::animations::AnimateNode;
+using cobalt::render_tree::animations::Animation;
+using cobalt::render_tree::animations::AnimationList;
 using cobalt::render_tree::CompositionNode;
 using cobalt::render_tree::Image;
 using cobalt::render_tree::ImageNode;
 using cobalt::render_tree::MatrixTransformNode;
 using cobalt::render_tree::Node;
 using cobalt::render_tree::ResourceProvider;
-using cobalt::render_tree::animations::Animation;
-using cobalt::render_tree::animations::AnimationList;
-using cobalt::render_tree::animations::NodeAnimationsMap;
 using cobalt::renderer::test::png_utils::DecodePNGToRenderTreeImage;
 
 namespace cobalt {
@@ -118,14 +118,14 @@
 
 }  // namespace
 
-RenderTreeWithAnimations CreateSpinningSpritesScene(
+scoped_refptr<render_tree::Node> CreateSpinningSpritesScene(
     ResourceProvider* resource_provider, const math::SizeF& output_dimensions,
     base::TimeDelta start_time) {
   // Create an image for each SpriteInfo we have in our sprite_infos vector.
   // They will be positioned and scaled according to their SpriteInfo settings,
   // and rotated according to time.
   CompositionNode::Builder spinning_sprites_scene_builder;
-  NodeAnimationsMap::Builder animations;
+  AnimateNode::Builder animations;
 
   // Now, setup a plurality of spinning images that contain the test image.
   std::vector<SpriteInfo> sprite_infos = CreateSpriteInfos();
@@ -154,8 +154,7 @@
   scoped_refptr<CompositionNode> spinning_sprites_composition(
       new CompositionNode(spinning_sprites_scene_builder.Pass()));
 
-  return RenderTreeWithAnimations(spinning_sprites_composition,
-                                  new NodeAnimationsMap(animations.Pass()));
+  return new AnimateNode(animations, spinning_sprites_composition);
 }
 
 }  // namespace scenes
diff --git a/src/cobalt/renderer/test/scenes/spinning_sprites_scene.h b/src/cobalt/renderer/test/scenes/spinning_sprites_scene.h
index 9e56e63..56595ab 100644
--- a/src/cobalt/renderer/test/scenes/spinning_sprites_scene.h
+++ b/src/cobalt/renderer/test/scenes/spinning_sprites_scene.h
@@ -29,7 +29,7 @@
 
 // This scene will create a plurality of randomly positioned and sized sprites
 // that are all spinning at different rates.
-RenderTreeWithAnimations CreateSpinningSpritesScene(
+scoped_refptr<render_tree::Node> CreateSpinningSpritesScene(
     render_tree::ResourceProvider* resource_provider,
     const math::SizeF& output_dimensions, base::TimeDelta start_time);
 
diff --git a/src/cobalt/script/javascriptcore/jsc_global_object.cc b/src/cobalt/script/javascriptcore/jsc_global_object.cc
index 6596d1b..9122348 100644
--- a/src/cobalt/script/javascriptcore/jsc_global_object.cc
+++ b/src/cobalt/script/javascriptcore/jsc_global_object.cc
@@ -17,6 +17,7 @@
 #include "cobalt/script/javascriptcore/jsc_global_object.h"
 
 #include "base/logging.h"
+#include "cobalt/script/javascriptcore/util/exception_helpers.h"
 
 namespace cobalt {
 namespace script {
@@ -57,6 +58,10 @@
       script_object_registry_(script_object_registry),
       environment_settings_(environment_settings) {}
 
+std::vector<script::StackFrame> JSCGlobalObject::GetStackTrace(int max_frames) {
+  return util::GetStackTrace(globalExec(), max_frames);
+}
+
 }  // namespace javascriptcore
 }  // namespace script
 }  // namespace cobalt
diff --git a/src/cobalt/script/javascriptcore/jsc_global_object.h b/src/cobalt/script/javascriptcore/jsc_global_object.h
index 9671b44..89f0dc6 100644
--- a/src/cobalt/script/javascriptcore/jsc_global_object.h
+++ b/src/cobalt/script/javascriptcore/jsc_global_object.h
@@ -26,6 +26,7 @@
 #include "cobalt/script/javascriptcore/js_object_cache.h"
 #include "cobalt/script/javascriptcore/script_object_registry.h"
 #include "cobalt/script/javascriptcore/wrapper_factory.h"
+#include "cobalt/script/stack_frame.h"
 #include "cobalt/script/wrappable.h"
 #include "third_party/WebKit/Source/JavaScriptCore/config.h"
 #include "third_party/WebKit/Source/JavaScriptCore/runtime/JSGlobalData.h"
@@ -59,6 +60,7 @@
   EnvironmentSettings* GetEnvironmentSettings() {
     return environment_settings_;
   }
+  std::vector<StackFrame> GetStackTrace(int max_frames = 0);
 
   // JavaScriptCore stuff
   DECLARE_CLASSINFO();
diff --git a/src/cobalt/script/mozjs/mozjs.cc b/src/cobalt/script/mozjs/mozjs.cc
index 0de17d2..6625ed2 100644
--- a/src/cobalt/script/mozjs/mozjs.cc
+++ b/src/cobalt/script/mozjs/mozjs.cc
@@ -21,8 +21,10 @@
 #include "base/string_util.h"
 #include "cobalt/base/wrap_main.h"
 #include "cobalt/script/mozjs/mozjs_global_object_proxy.h"
+#include "cobalt/script/source_code.h"
 #include "cobalt/script/standalone_javascript_runner.h"
 #include "third_party/mozjs/js/src/jsapi.h"
+#include "third_party/mozjs/js/src/jsproxy.h"
 
 namespace cobalt {
 namespace script {
@@ -50,6 +52,8 @@
 }
 
 void SetupBindings(JSContext* context, JSObject* global_object) {
+  DCHECK(JS_IsGlobalObject(global_object));
+
   JSAutoRequest auto_request(context);
   JSAutoCompartment auto_comparment(context, global_object);
   JS_DefineFunction(context, global_object, "print", &Print, 0,
@@ -58,18 +62,43 @@
 
 int MozjsMain(int argc, char** argv) {
   cobalt::script::StandaloneJavascriptRunner standalone_runner;
-  MozjsGlobalObjectProxy* global_object_proxy =
+  MozjsGlobalObjectProxy* global_object_environment =
       static_cast<MozjsGlobalObjectProxy*>(
           standalone_runner.global_object_proxy().get());
 
-  SetupBindings(global_object_proxy->context(),
-                global_object_proxy->global_object());
+  SetupBindings(global_object_environment->context(),
+                global_object_environment->global_object());
 
-  CommandLine command_line(argc, argv);
-  CommandLine::StringVector args = command_line.GetArgs();
-  if (!args.empty()) {
-    FilePath source_file(args[0]);
-    standalone_runner.ExecuteFile(source_file);
+  if (argc > 1) {
+    // Command line arguments will be flag-value pairs of the form
+    // -f filename
+    // and
+    // -e "inline script"
+    // and will be evaluated in order.
+    for (int i = 1; (i + 1) < argc; ++i) {
+      if (std::string(argv[i]) == "-f") {
+        std::string filename = std::string(argv[i + 1]);
+        // Execute source file.
+        FilePath source_file(filename);
+        standalone_runner.ExecuteFile(source_file);
+        ++i;
+      } else if (std::string(argv[i]) == "-e") {
+        // Execute inline script.
+        scoped_refptr<SourceCode> source = SourceCode::CreateSourceCode(
+            argv[i + 1], base::SourceLocation("[stdin]", 1, 1));
+
+        // Execute the script and get the results of execution.
+        std::string result;
+        bool success =
+            global_object_environment->EvaluateScript(source, &result);
+        // Echo the results to stdout.
+        if (!success) {
+          std::cout << "Exception: ";
+        }
+        std::cout << result << std::endl;
+        ++i;
+      }
+    }
   } else {
     standalone_runner.RunInteractive();
   }
diff --git a/src/cobalt/script/mozjs/mozjs.gyp b/src/cobalt/script/mozjs/mozjs.gyp
index 58728de..49f8313 100644
--- a/src/cobalt/script/mozjs/mozjs.gyp
+++ b/src/cobalt/script/mozjs/mozjs.gyp
@@ -27,6 +27,7 @@
         'mozjs_property_enumerator.cc',
         'mozjs_source_code.cc',
         'proxy_handler.cc',
+        'util/exception_helpers.cc',
         'wrapper_factory.cc',
         'wrapper_private.cc',
       ],
@@ -41,6 +42,11 @@
         'ENGINE_SUPPORTS_INDEXED_DELETERS',
         'ENGINE_SUPPORTS_INT64', ],
       },
+      'conditions' :[
+        ['cobalt_enable_jit == 1', {
+          'defines': [ 'ENGINE_SUPPORTS_JIT', ],
+        }],
+      ],
     },
 
     {
diff --git a/src/cobalt/script/mozjs/mozjs_exception_state.cc b/src/cobalt/script/mozjs/mozjs_exception_state.cc
index a4c575b..e7839c4 100644
--- a/src/cobalt/script/mozjs/mozjs_exception_state.cc
+++ b/src/cobalt/script/mozjs/mozjs_exception_state.cc
@@ -49,7 +49,18 @@
 void MozjsExceptionState::SetException(
     const scoped_refptr<ScriptException>& exception) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  NOTIMPLEMENTED();
+  DCHECK(!is_exception_set_);
+
+  MozjsGlobalObjectProxy* global_object_proxy =
+      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context_));
+
+  JS::RootedObject exception_object(
+      context_,
+      global_object_proxy->wrapper_factory()->GetWrapperProxy(exception));
+  JS::RootedValue exception_value(context_, OBJECT_TO_JSVAL(exception_object));
+  JS_SetPendingException(context_, exception_value);
+
+  is_exception_set_ = true;
 }
 
 void MozjsExceptionState::SetSimpleException(
diff --git a/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc b/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
index 43c45bc..8622146 100644
--- a/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
+++ b/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
@@ -15,13 +15,18 @@
  */
 #include "cobalt/script/mozjs/mozjs_global_object_proxy.h"
 
+#include <algorithm>
 #include <utility>
 
+#include "base/lazy_instance.h"
 #include "base/stringprintf.h"
 #include "cobalt/base/polymorphic_downcast.h"
 #include "cobalt/script/mozjs/conversion_helpers.h"
 #include "cobalt/script/mozjs/mozjs_exception_state.h"
 #include "cobalt/script/mozjs/mozjs_source_code.h"
+#include "cobalt/script/mozjs/mozjs_wrapper_handle.h"
+#include "cobalt/script/mozjs/proxy_handler.h"
+#include "cobalt/script/mozjs/util/exception_helpers.h"
 #include "third_party/mozjs/js/src/jsfriendapi.h"
 #include "third_party/mozjs/js/src/jsfun.h"
 #include "third_party/mozjs/js/src/jsobj.h"
@@ -66,6 +71,52 @@
 
 // This is the default in the spidermonkey shell.
 const uint32_t kMaxCodeCacheBytes = 16 * 1024 * 1024;
+
+// DOM proxies have an extra slot for the expando object at index
+// kJSProxySlotExpando.
+// The expando object is a plain JSObject whose properties correspond to
+// "expandos" (custom properties set by the script author).
+// The exact value stored in the kJSProxySlotExpando slot depends on whether
+// the interface is annotated with the [OverrideBuiltins] extended attribute.
+const uint32_t kJSProxySlotExpando = 0;
+
+// The DOMProxyShadowsCheck function will be called to check if the property for
+// id should be gotten from the prototype, or if there is an own property that
+// shadows it.
+js::DOMProxyShadowsResult DOMProxyShadowsCheck(JSContext* context,
+                                               JS::HandleObject proxy,
+                                               JS::HandleId id) {
+  DCHECK(IsProxy(proxy));
+  JS::Value value = js::GetProxyExtra(proxy, kJSProxySlotExpando);
+  DCHECK(value.isUndefined() || value.isObject());
+
+  // [OverrideBuiltins] extended attribute is not supported.
+  NOTIMPLEMENTED();
+
+  // If DoesntShadow is returned then the slot at listBaseExpandoSlot should
+  // either be undefined or point to an expando object that would contain the
+  // own property.
+  return js::DoesntShadow;
+}
+
+class MozjsStubHandler : public ProxyHandler {
+ public:
+  MozjsStubHandler()
+      : ProxyHandler(indexed_property_hooks, named_property_hooks) {}
+
+ private:
+  static NamedPropertyHooks named_property_hooks;
+  static IndexedPropertyHooks indexed_property_hooks;
+};
+
+ProxyHandler::NamedPropertyHooks MozjsStubHandler::named_property_hooks = {
+    NULL, NULL, NULL, NULL, NULL,
+};
+ProxyHandler::IndexedPropertyHooks MozjsStubHandler::indexed_property_hooks = {
+    NULL, NULL, NULL, NULL, NULL,
+};
+
+static base::LazyInstance<MozjsStubHandler> proxy_handler;
 }  // namespace
 
 MozjsGlobalObjectProxy::MozjsGlobalObjectProxy(JSRuntime* runtime)
@@ -82,16 +133,18 @@
 
   JS_SetGCParameterForThread(context_, JSGC_MAX_CODE_CACHE_BYTES,
                              kMaxCodeCacheBytes);
-
   uint32_t options =
       JSOPTION_TYPE_INFERENCE |
       JSOPTION_VAROBJFIX |       // Recommended to enable this in the API docs.
       JSOPTION_COMPILE_N_GO |    // Compiled scripts will be run only once.
       JSOPTION_UNROOTED_GLOBAL;  // Global handle must be visited to ensure it
                                  // is not GC'd.
-#if SB_CAN(MAP_EXECUTABLE_MEMORY)
+#if ENGINE_SUPPORTS_JIT
   options |= JSOPTION_BASELINE |  // Enable baseline compiler.
              JSOPTION_ION;        // Enable IonMonkey
+  // This is required by baseline and IonMonkey.
+  js::SetDOMProxyInformation(0 /*domProxyHandlerFamily*/, kJSProxySlotExpando,
+                             DOMProxyShadowsCheck);
 #endif
 #if !defined(COBALT_BUILD_TYPE_GOLD) && !defined(COBALT_BUILD_TYPE_QA)
   options |= JSOPTION_EXTRA_WARNINGS;
@@ -101,6 +154,7 @@
   JS_SetErrorReporter(context_, &MozjsGlobalObjectProxy::ReportErrorHandler);
 
   wrapper_factory_.reset(new WrapperFactory(context_));
+
   JS_AddExtraGCRootsTracer(runtime, TraceFunction, this);
 }
 
@@ -111,7 +165,7 @@
 
 void MozjsGlobalObjectProxy::CreateGlobalObject() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!global_object_);
+  DCHECK(!global_object_proxy_);
 
   // The global object is automatically rooted unless the
   // JSOPTION_UNROOTED_GLOBAL option is set.
@@ -128,7 +182,11 @@
   JSAutoCompartment auto_compartment(context_, global_object);
   bool success = JS_InitStandardClasses(context_, global_object);
   DCHECK(success);
-  SetGlobalObject(global_object);
+
+  JS::RootedObject proxy(
+      context_, ProxyHandler::NewProxy(context_, global_object, NULL, NULL,
+                                       proxy_handler.Pointer()));
+  global_object_proxy_ = proxy;
 }
 
 bool MozjsGlobalObjectProxy::EvaluateScript(
@@ -142,12 +200,14 @@
   const base::SourceLocation location = mozjs_source_code->location();
 
   JSAutoRequest auto_request(context_);
-  JSAutoCompartment auto_comparment(context_, global_object_);
+  JSAutoCompartment auto_comparment(context_, global_object_proxy_);
   JS::RootedValue result_value(context_);
   std::string error_message;
   last_error_message_ = &error_message;
+  JS::RootedObject global_object(
+      context_, js::GetProxyTargetObject(global_object_proxy_));
   bool success = JS_EvaluateScript(
-      context_, global_object_, script.c_str(), script.size(),
+      context_, global_object, script.c_str(), script.size(),
       location.file_path.c_str(), location.line_number, result_value.address());
   if (out_result_utf8) {
     if (success) {
@@ -162,6 +222,11 @@
   return success;
 }
 
+std::vector<StackFrame> MozjsGlobalObjectProxy::GetStackTrace(int max_frames) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return util::GetStackTrace(context_, max_frames);
+}
+
 void MozjsGlobalObjectProxy::DisableEval(const std::string& message) {
   DCHECK(thread_checker_.CalledOnValidThread());
   eval_disabled_message_.emplace(message);
@@ -183,11 +248,14 @@
 void MozjsGlobalObjectProxy::Bind(const std::string& identifier,
                                   const scoped_refptr<Wrappable>& impl) {
   JSAutoRequest auto_request(context_);
-  JSAutoCompartment auto_comparment(context_, global_object_);
+  JSAutoCompartment auto_comparment(context_, global_object_proxy_);
+
   JS::RootedObject wrapper_proxy(context_,
                                  wrapper_factory_->GetWrapperProxy(impl));
+  JS::RootedObject global_object(
+      context_, js::GetProxyTargetObject(global_object_proxy_));
   JS::Value wrapper_value = OBJECT_TO_JSVAL(wrapper_proxy);
-  bool success = JS_SetProperty(context_, global_object_, identifier.c_str(),
+  bool success = JS_SetProperty(context_, global_object, identifier.c_str(),
                                 &wrapper_value);
   DCHECK(success);
 }
@@ -208,6 +276,28 @@
   return global_proxy;
 }
 
+void MozjsGlobalObjectProxy::SetGlobalObjectProxyAndWrapper(
+    JS::HandleObject global_object_proxy,
+    const scoped_refptr<Wrappable>& wrappable) {
+  DCHECK(!global_object_proxy_);
+  DCHECK(global_object_proxy);
+  DCHECK(JS_IsGlobalObject(js::GetProxyTargetObject(global_object_proxy)));
+  DCHECK(IsObjectProxy(global_object_proxy));
+
+  global_object_proxy_ = global_object_proxy;
+
+  // Global object cached wrapper is not set as usual object.
+  // Set the global object cached wrapper, so we can get the object proxy
+  // through wrapper handle.
+  WrapperPrivate* wrapper_private =
+      WrapperPrivate::GetFromProxyObject(context_, global_object_proxy_);
+  DCHECK(wrapper_private);
+
+  scoped_ptr<Wrappable::WeakWrapperHandle> object_handle(
+      new MozjsWrapperHandle(wrapper_private));
+  SetCachedWrapper(wrappable.get(), object_handle.Pass());
+}
+
 void MozjsGlobalObjectProxy::CacheInterfaceData(intptr_t key,
                                                 InterfaceData* interface_data) {
   std::pair<CachedInterfaceData::iterator, bool> pib =
@@ -235,15 +325,16 @@
 }
 
 void MozjsGlobalObjectProxy::TraceFunction(JSTracer* trace, void* data) {
-  MozjsGlobalObjectProxy* global_object_proxy =
+  MozjsGlobalObjectProxy* global_object_environment =
       reinterpret_cast<MozjsGlobalObjectProxy*>(data);
-  if (global_object_proxy->global_object_) {
-    JS_CallHeapObjectTracer(trace, &global_object_proxy->global_object_,
+  if (global_object_environment->global_object_proxy_) {
+    JS_CallHeapObjectTracer(trace,
+                            &global_object_environment->global_object_proxy_,
                             "MozjsGlobalObjectProxy");
   }
   for (CachedInterfaceData::iterator it =
-           global_object_proxy->cached_interface_data_.begin();
-       it != global_object_proxy->cached_interface_data_.end(); ++it) {
+           global_object_environment->cached_interface_data_.begin();
+       it != global_object_environment->cached_interface_data_.end(); ++it) {
     InterfaceData* data = it->second;
     JS_CallHeapObjectTracer(trace, &data->prototype, "MozjsGlobalObjectProxy");
     JS_CallHeapObjectTracer(trace, &data->interface_object,
diff --git a/src/cobalt/script/mozjs/mozjs_global_object_proxy.h b/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
index decac4e..0355d37 100644
--- a/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
+++ b/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
@@ -26,8 +26,10 @@
 #include "base/threading/thread_checker.h"
 #include "cobalt/script/global_object_proxy.h"
 #include "cobalt/script/mozjs/interface_data.h"
+#include "cobalt/script/mozjs/util/exception_helpers.h"
 #include "cobalt/script/mozjs/wrapper_factory.h"
 #include "third_party/mozjs/js/src/jsapi.h"
+#include "third_party/mozjs/js/src/jsproxy.h"
 
 namespace cobalt {
 namespace script {
@@ -35,7 +37,8 @@
 
 // Manages a handle to a JavaScript engine's global object. The lifetime of
 // the global object is not necessarily tied to the lifetime of the proxy.
-class MozjsGlobalObjectProxy : public GlobalObjectProxy {
+class MozjsGlobalObjectProxy : public GlobalObjectProxy,
+                               public Wrappable::CachedWrapperAccessor {
  public:
   explicit MozjsGlobalObjectProxy(JSRuntime* runtime);
   ~MozjsGlobalObjectProxy() OVERRIDE;
@@ -53,10 +56,7 @@
     return false;
   }
 
-  std::vector<StackFrame> GetStackTrace(int max_frames) OVERRIDE {
-    NOTIMPLEMENTED();
-    return std::vector<StackFrame>();
-  }
+  std::vector<StackFrame> GetStackTrace(int max_frames = 0) OVERRIDE;
 
   void PreventGarbageCollection(
       const scoped_refptr<Wrappable>& wrappable) OVERRIDE {
@@ -79,7 +79,10 @@
 
   JSContext* context() const { return context_; }
 
-  JSObject* global_object() const { return global_object_; }
+  JSObject* global_object_proxy() const { return global_object_proxy_; }
+  JSObject* global_object() const {
+    return js::GetProxyTargetObject(global_object_proxy_);
+  }
 
   WrapperFactory* wrapper_factory() { return wrapper_factory_.get(); }
 
@@ -94,11 +97,9 @@
     return environment_settings_;
   }
 
-  void SetGlobalObject(JS::HandleObject global_object) {
-    DCHECK(!global_object_);
-    DCHECK(global_object);
-    global_object_ = global_object;
-  }
+  void SetGlobalObjectProxyAndWrapper(
+      JS::HandleObject global_object_proxy,
+      const scoped_refptr<Wrappable>& wrappable);
 
   // Any tracked InterfaceData will have it's GC handles visited and marked as
   // roots. The MozjsGlobalObjectProxy takes ownership of the InterfaceData
@@ -135,7 +136,7 @@
   STLValueDeleter<CachedInterfaceData> cached_interface_data_deleter_;
   ContextDestructor context_destructor_;
   scoped_ptr<WrapperFactory> wrapper_factory_;
-  JS::Heap<JSObject*> global_object_;
+  JS::Heap<JSObject*> global_object_proxy_;
   EnvironmentSettings* environment_settings_;
 
   // If non-NULL, the error message from the ReportErrorHandler will get
diff --git a/src/cobalt/script/mozjs/mozjs_user_object_holder.h b/src/cobalt/script/mozjs/mozjs_user_object_holder.h
index 0551bff..de47435 100644
--- a/src/cobalt/script/mozjs/mozjs_user_object_holder.h
+++ b/src/cobalt/script/mozjs/mozjs_user_object_holder.h
@@ -16,6 +16,8 @@
 #ifndef COBALT_SCRIPT_MOZJS_MOZJS_USER_OBJECT_HOLDER_H_
 #define COBALT_SCRIPT_MOZJS_MOZJS_USER_OBJECT_HOLDER_H_
 
+#include "base/hash_tables.h"
+#include "base/memory/weak_ptr.h"
 #include "cobalt/base/polymorphic_downcast.h"
 #include "cobalt/script/mozjs/wrapper_factory.h"
 #include "cobalt/script/mozjs/wrapper_private.h"
@@ -50,14 +52,21 @@
     JS::RootedObject owned_object(context_, js_object());
     WrapperPrivate* wrapper_private =
         WrapperPrivate::GetFromWrappable(owner, context_, wrapper_factory_);
+    wrappable_and_private_hash_map_.insert(
+        std::make_pair(owner, wrapper_private->AsWeakPtr()));
     wrapper_private->AddReferencedObject(owned_object);
   }
 
   void DeregisterOwner(Wrappable* owner) OVERRIDE {
     JS::RootedObject owned_object(context_, js_object());
-    WrapperPrivate* wrapper_private =
-        WrapperPrivate::GetFromWrappable(owner, context_, wrapper_factory_);
-    wrapper_private->RemoveReferencedObject(owned_object);
+    WrappableAndPrivateHashMap::iterator it =
+        wrappable_and_private_hash_map_.find(owner);
+    if (it != wrappable_and_private_hash_map_.end() && it->second) {
+      JS::RootedObject object_proxy(context_, it->second->js_object_proxy());
+      if (object_proxy) {
+        it->second->RemoveReferencedObject(owned_object);
+      }
+    }
   }
 
   const typename MozjsUserObjectType::BaseType* GetScriptObject()
@@ -89,9 +98,13 @@
   }
 
  private:
+  typedef base::hash_map<const Wrappable*, base::WeakPtr<WrapperPrivate> >
+      WrappableAndPrivateHashMap;
+
   JSContext* context_;
   base::optional<MozjsUserObjectType> object_handle_;
   WrapperFactory* wrapper_factory_;
+  WrappableAndPrivateHashMap wrappable_and_private_hash_map_;
 };
 
 }  // namespace mozjs
diff --git a/src/cobalt/script/mozjs/util/exception_helpers.cc b/src/cobalt/script/mozjs/util/exception_helpers.cc
new file mode 100644
index 0000000..9ef7f2c
--- /dev/null
+++ b/src/cobalt/script/mozjs/util/exception_helpers.cc
@@ -0,0 +1,65 @@
+/*
+ * 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/script/mozjs/util/exception_helpers.h"
+
+#include <algorithm>
+
+#include "cobalt/script/mozjs/conversion_helpers.h"
+#include "cobalt/script/mozjs/mozjs_exception_state.h"
+#include "third_party/mozjs/js/src/jsdbgapi.h"
+#include "third_party/mozjs/js/src/jsscript.h"
+
+namespace cobalt {
+namespace script {
+namespace mozjs {
+namespace util {
+std::vector<StackFrame> GetStackTrace(JSContext* context, int max_frames) {
+  JS::StackDescription* stack_description =
+      JS::DescribeStack(context, max_frames);
+  if (max_frames == 0) {
+    max_frames = static_cast<int>(stack_description->nframes);
+  } else {
+    max_frames =
+        std::min(max_frames, static_cast<int>(stack_description->nframes));
+  }
+  JS::FrameDescription* stack_trace = stack_description->frames;
+  std::vector<StackFrame> stack_frames(max_frames);
+  for (int i = 0; i < max_frames; ++i) {
+    StackFrame sf;
+    sf.line_number = stack_trace[i].lineno;
+    sf.column_number = 0;
+    sf.function_name = "global code";
+    if (stack_trace[i].fun) {
+      JS::RootedString rooted_string(context,
+                                     JS_GetFunctionId(stack_trace[i].fun));
+      JS::RootedValue rooted_value(context, STRING_TO_JSVAL(rooted_string));
+      MozjsExceptionState exception_state(context);
+      FromJSValue(context, rooted_value, kNoConversionFlags, &exception_state,
+                  &sf.function_name);
+    }
+    if (stack_trace[i].script) {
+      sf.source_url = stack_trace[i].script->filename();
+    }
+    stack_frames[i] = sf;
+  }
+  JS::FreeStackDescription(context, stack_description);
+  return stack_frames;
+}
+}  // namespace util
+}  // namespace mozjs
+}  // namespace script
+}  // namespace cobalt
diff --git a/src/cobalt/script/mozjs/util/exception_helpers.h b/src/cobalt/script/mozjs/util/exception_helpers.h
new file mode 100644
index 0000000..75dff27
--- /dev/null
+++ b/src/cobalt/script/mozjs/util/exception_helpers.h
@@ -0,0 +1,33 @@
+/*
+ * 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_SCRIPT_MOZJS_UTIL_EXCEPTION_HELPERS_H_
+#define COBALT_SCRIPT_MOZJS_UTIL_EXCEPTION_HELPERS_H_
+
+#include <vector>
+
+#include "cobalt/script/stack_frame.h"
+#include "third_party/mozjs/js/src/jsapi.h"
+
+namespace cobalt {
+namespace script {
+namespace mozjs {
+namespace util {
+std::vector<StackFrame> GetStackTrace(JSContext* context, int max_frames);
+}  // namespace util
+}  // namespace mozjs
+}  // namespace script
+}  // namespace cobalt
+#endif  // COBALT_SCRIPT_MOZJS_UTIL_EXCEPTION_HELPERS_H_
diff --git a/src/cobalt/script/mozjs/wrapper_private.cc b/src/cobalt/script/mozjs/wrapper_private.cc
index b7b3443..e129678 100644
--- a/src/cobalt/script/mozjs/wrapper_private.cc
+++ b/src/cobalt/script/mozjs/wrapper_private.cc
@@ -39,11 +39,13 @@
 }
 
 // static
-void WrapperPrivate::AddPrivateData(JS::HandleObject wrapper_proxy,
+void WrapperPrivate::AddPrivateData(JSContext* context,
+                                    JS::HandleObject wrapper_proxy,
                                     const scoped_refptr<Wrappable>& wrappable) {
   DCHECK(js::IsProxy(wrapper_proxy));
   WrapperPrivate* private_data = new WrapperPrivate(wrappable, wrapper_proxy);
-  JSObject* target_object = js::GetProxyTargetObject(wrapper_proxy);
+  JS::RootedObject target_object(context,
+                                 js::GetProxyTargetObject(wrapper_proxy));
   JS_SetPrivate(target_object, private_data);
   DCHECK_EQ(JS_GetPrivate(target_object), private_data);
 }
@@ -114,6 +116,8 @@
   DCHECK(js::IsProxy(wrapper_proxy));
 }
 
+WrapperPrivate::~WrapperPrivate() { wrapper_proxy_ = NULL; }
+
 }  // namespace mozjs
 }  // namespace script
 }  // namespace cobalt
diff --git a/src/cobalt/script/mozjs/wrapper_private.h b/src/cobalt/script/mozjs/wrapper_private.h
index 9bb4219..e80ec75 100644
--- a/src/cobalt/script/mozjs/wrapper_private.h
+++ b/src/cobalt/script/mozjs/wrapper_private.h
@@ -47,7 +47,7 @@
   void RemoveReferencedObject(JS::HandleObject referee);
 
   // Create a new WrapperPrivate instance and associate it with the wrapper.
-  static void AddPrivateData(JS::HandleObject wrapper_proxy,
+  static void AddPrivateData(JSContext* context, JS::HandleObject wrapper_proxy,
                              const scoped_refptr<Wrappable>& wrappable);
 
   // Get the WrapperPrivate associated with the given Wrappable. A new JSObject
@@ -78,6 +78,7 @@
   typedef ScopedVector<JS::Heap<JSObject*> > ReferencedObjectVector;
   WrapperPrivate(const scoped_refptr<Wrappable>& wrappable,
                  JS::HandleObject wrapper_proxy);
+  ~WrapperPrivate();
 
   scoped_refptr<Wrappable> wrappable_;
   JS::Heap<JSObject*> wrapper_proxy_;
diff --git a/src/cobalt/webdriver/window_driver.cc b/src/cobalt/webdriver/window_driver.cc
index cb14bb9..b896311 100644
--- a/src/cobalt/webdriver/window_driver.cc
+++ b/src/cobalt/webdriver/window_driver.cc
@@ -164,7 +164,13 @@
       get_global_object_proxy_(get_global_object_proxy_function),
       window_message_loop_(message_loop),
       element_driver_map_deleter_(&element_drivers_),
-      next_element_id_(0) {}
+      next_element_id_(0) {
+  // The WindowDriver may have been created on some arbitrary thread (i.e. the
+  // thread that owns the Window). Detach the thread checker so it can be
+  // re-bound to the next thread that calls a webdriver API, which should be
+  // the WebDriver thread.
+  thread_checker_.DetachFromThread();
+}
 
 WindowDriver::~WindowDriver() {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/src/codereview.settings b/src/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/glimp/codereview.settings b/src/glimp/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/glimp/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/glimp/gles/pixel_format.cc b/src/glimp/gles/pixel_format.cc
index 5c0f76b..ac1672e 100644
--- a/src/glimp/gles/pixel_format.cc
+++ b/src/glimp/gles/pixel_format.cc
@@ -36,6 +36,14 @@
 int BytesPerPixel(PixelFormat format) {
   SB_COMPILE_ASSERT(SB_ARRAY_SIZE(kBytesPerPixel) == kPixelFormatNumFormats,
                     kBytesPerPixel_has_entries_for_each_enum_PixelFormat);
+  if (kPixelFormatInvalid == format) {
+    return 0;  // Invalid formats have 0 bytes per pixel.
+  }
+
+  if (format < 0 || format >= kPixelFormatNumFormats) {
+    SB_DCHECK(false) << "Invalid PixelFormat: " << format;
+    return 0;
+  }
   return kBytesPerPixel[format];
 }
 
diff --git a/src/googleurl/codereview.settings b/src/googleurl/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/googleurl/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/media/base/sbplayer_pipeline.cc b/src/media/base/sbplayer_pipeline.cc
index 5a9ce70..7248c25 100644
--- a/src/media/base/sbplayer_pipeline.cc
+++ b/src/media/base/sbplayer_pipeline.cc
@@ -649,7 +649,7 @@
   bool is_encrypted = IsEncrypted(stream);
   SbDrmSampleInfo drm_info;
 
-  if (is_encrypted) {
+  if (is_encrypted && !buffer->IsEndOfStream()) {
     FillDrmSampleInfo(buffer, &drm_info);
   }
 
diff --git a/src/media/base/shell_video_frame_provider.cc b/src/media/base/shell_video_frame_provider.cc
index e4910d2..589f886 100644
--- a/src/media/base/shell_video_frame_provider.cc
+++ b/src/media/base/shell_video_frame_provider.cc
@@ -22,9 +22,8 @@
 
 ShellVideoFrameProvider::ShellVideoFrameProvider(
     scoped_refptr<VideoFrame> punch_out)
-    : punch_out_(punch_out), has_consumed_frames_(false) {
+    : punch_out_(punch_out), has_consumed_frames_(false), dropped_frames_(0) {
 #if !defined(__LB_SHELL__FOR_RELEASE__)
-  dropped_frames_ = 0;
   max_delay_in_microseconds_ = 0;
 #endif  // !defined(__LB_SHELL__FOR_RELEASE__)
 }
@@ -67,24 +66,26 @@
         frame_time + kEpsilonInMicroseconds >= media_time.InMicroseconds())
       break;
 
-#if !defined(__LB_SHELL__FOR_RELEASE__)
-    const bool kLogFrameDrops ALLOW_UNUSED = false;
     if (current_frame_ != frames_[0]) {
       ++dropped_frames_;
+
+#if !defined(__LB_SHELL__FOR_RELEASE__)
       if (media_time.InMicroseconds() - frame_time > max_delay_in_microseconds_)
         max_delay_in_microseconds_ = media_time.InMicroseconds() - frame_time;
+      const bool kLogFrameDrops ALLOW_UNUSED = false;
       LOG_IF(WARNING, kLogFrameDrops)
           << "dropped one frame with timestamp "
           << frames_[0]->GetTimestamp().InMicroseconds() << " at media time "
           << media_time.InMicroseconds() << " total dropped " << dropped_frames_
           << " frames with a max delay of " << max_delay_in_microseconds_
           << " ms";
-    }
 #endif  // !defined(__LB_SHELL__FOR_RELEASE__)
+    }
 
     if (frames_.size() == 1) {
       current_frame_ = frames_[0];
     }
+
     frames_.erase(frames_.begin());
     has_consumed_frames_ = true;
   }
@@ -108,6 +109,7 @@
   base::AutoLock auto_lock(frames_lock_);
   frames_.clear();
   current_frame_ = NULL;
+  dropped_frames_ = 0;
 }
 
 size_t ShellVideoFrameProvider::GetNumOfFramesCached() const {
@@ -127,4 +129,11 @@
   return previous_value;
 }
 
+int ShellVideoFrameProvider::ResetAndReturnDroppedFrames() {
+  base::AutoLock auto_lock(frames_lock_);
+  int dropped_frames = dropped_frames_;
+  dropped_frames_ = 0;
+  return dropped_frames;
+}
+
 }  // namespace media
diff --git a/src/media/base/shell_video_frame_provider.h b/src/media/base/shell_video_frame_provider.h
index a26a2db..47ab8da 100644
--- a/src/media/base/shell_video_frame_provider.h
+++ b/src/media/base/shell_video_frame_provider.h
@@ -64,6 +64,9 @@
   // queue since the last time this was called.
   bool QueryAndResetHasConsumedFrames();
 
+  // Return the value of |dropped_frames_| and reset it to 0.
+  int ResetAndReturnDroppedFrames();
+
  private:
   base::TimeDelta GetMediaTime_Locked() const;
 
@@ -74,9 +77,9 @@
   std::vector<scoped_refptr<VideoFrame> > frames_;
   scoped_refptr<VideoFrame> current_frame_;
   bool has_consumed_frames_;
+  int dropped_frames_;
 
 #if !defined(__LB_SHELL__FOR_RELEASE__)
-  int dropped_frames_;
   int max_delay_in_microseconds_;
 #endif  // !defined(__LB_SHELL__FOR_RELEASE__)
 
diff --git a/src/media/filters/shell_demuxer.cc b/src/media/filters/shell_demuxer.cc
index 3da9455..6671985 100644
--- a/src/media/filters/shell_demuxer.cc
+++ b/src/media/filters/shell_demuxer.cc
@@ -232,27 +232,33 @@
       base::Bind(&ShellDemuxer::ParseConfigDone, this, status_cb));
 }
 
-bool ShellDemuxer::ParseConfigBlocking(const PipelineStatusCB& status_cb) {
+PipelineStatus ShellDemuxer::ParseConfigBlocking(
+    const PipelineStatusCB& status_cb) {
   DCHECK(blocking_thread_.message_loop_proxy()->BelongsToCurrentThread());
   DCHECK(!parser_);
 
   // construct stream parser with error callback
-  parser_ = ShellParser::Construct(reader_, status_cb);
+  PipelineStatus status = ShellParser::Construct(reader_, &parser_);
   // if we can't construct a parser for this stream it's a fatal error, return
   // false so ParseConfigDone will notify the caller to Initialize() via
   // status_cb.
-  if (!parser_) {
-    return false;
+  if (!parser_ || status != PIPELINE_OK) {
+    DCHECK(!parser_);
+    DCHECK_NE(status, PIPELINE_OK);
+    if (status == PIPELINE_OK) {
+      status = DEMUXER_ERROR_COULD_NOT_PARSE;
+    }
+    return status;
   }
 
   // instruct the parser to extract audio and video config from the file
   if (!parser_->ParseConfig()) {
-    return false;
+    return DEMUXER_ERROR_COULD_NOT_PARSE;
   }
 
   // make sure we got a valid and complete configuration
   if (!parser_->IsConfigComplete()) {
-    return false;
+    return DEMUXER_ERROR_COULD_NOT_PARSE;
   }
 
   // IsConfigComplete() should guarantee we know the duration
@@ -265,18 +271,19 @@
   }
 
   // successful parse of config data, inform the nonblocking demuxer thread
-  return true;
+  DCHECK_EQ(status, PIPELINE_OK);
+  return PIPELINE_OK;
 }
 
 void ShellDemuxer::ParseConfigDone(const PipelineStatusCB& status_cb,
-                                   bool result) {
+                                   PipelineStatus status) {
   DCHECK(MessageLoopBelongsToCurrentThread());
   // if the blocking parser thread cannot parse config we're done.
-  if (!result) {
-    status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE);
+  if (status != PIPELINE_OK) {
+    status_cb.Run(status);
     return;
   }
-
+  DCHECK(parser_);
   // start downloading data
   Request(DemuxerStream::AUDIO);
 
diff --git a/src/media/filters/shell_demuxer.h b/src/media/filters/shell_demuxer.h
index c49c28e..886f7fc 100644
--- a/src/media/filters/shell_demuxer.h
+++ b/src/media/filters/shell_demuxer.h
@@ -121,14 +121,15 @@
   void BufferAllocated(scoped_refptr<DecoderBuffer> buffer);
 
  private:
-  void ParseConfigDone(const PipelineStatusCB& status_cb, bool result);
+  void ParseConfigDone(const PipelineStatusCB& status_cb,
+                       PipelineStatus status);
   void DataSourceStopped(const base::Closure& callback);
 
   // methods that perform blocking I/O, and are therefore run on the
   // blocking_thread_
   // download enough of the stream to parse the configuration. returns
   // false on error.
-  bool ParseConfigBlocking(const PipelineStatusCB& status_cb);
+  PipelineStatus ParseConfigBlocking(const PipelineStatusCB& status_cb);
   void RequestTask(DemuxerStream::Type type);
   void DownloadTask(scoped_refptr<DecoderBuffer> buffer);
   void IssueNextRequestTask();
diff --git a/src/media/filters/shell_flv_parser.cc b/src/media/filters/shell_flv_parser.cc
index 5d517ad..4492a49 100644
--- a/src/media/filters/shell_flv_parser.cc
+++ b/src/media/filters/shell_flv_parser.cc
@@ -70,28 +70,33 @@
 static const int kAMF0NumberLength = 9;
 
 // static
-scoped_refptr<ShellParser> ShellFLVParser::Construct(
+PipelineStatus ShellFLVParser::Construct(
     scoped_refptr<ShellDataSourceReader> reader,
     const uint8* construction_header,
-    const PipelineStatusCB& status_cb) {
+    scoped_refptr<ShellParser>* parser) {
+  DCHECK(parser);
+  *parser = NULL;
+
   // look for "FLV" string at top of file, mask off LSB
   uint32 FLV = endian_util::load_uint32_big_endian(construction_header) >> 8;
   if (FLV != kFLV) {
-    return NULL;
+    // Not an flv.
+    return DEMUXER_ERROR_COULD_NOT_PARSE;
   }
   // Check for availability of both an audio and video stream. Audio stream is
   // third bit, video stream is first bit in 5th byte of file header
   if ((construction_header[4] & 0x05) != 0x05) {
-    status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
-    return NULL;
+    return DEMUXER_ERROR_NO_SUPPORTED_STREAMS;
   }
   // offset of first data tag in stream is next 4 bytes
   uint32 data_offset =
       endian_util::load_uint32_big_endian(construction_header + 5);
   // add four bytes to skip over PreviousTagSize0
   data_offset += 4;
-  // construct and return an FLV parser
-  return scoped_refptr<ShellParser>(new ShellFLVParser(reader, data_offset));
+
+  // construct an FLV parser
+  *parser = new ShellFLVParser(reader, data_offset);
+  return PIPELINE_OK;
 }
 
 ShellFLVParser::ShellFLVParser(scoped_refptr<ShellDataSourceReader> reader,
diff --git a/src/media/filters/shell_flv_parser.h b/src/media/filters/shell_flv_parser.h
index 992bee9..1f512c0 100644
--- a/src/media/filters/shell_flv_parser.h
+++ b/src/media/filters/shell_flv_parser.h
@@ -28,12 +28,12 @@
 class ShellFLVParser : public ShellAVCParser {
  public:
   // Attempts to make sense of the provided bytes of the top of a file as an
-  // flv, and if it does make sense returns a ShellFLVParser initialized with
-  // some basic state. If it doesn't make sense this returns NULL.
-  static scoped_refptr<ShellParser> Construct(
-      scoped_refptr<ShellDataSourceReader> reader,
-      const uint8* construction_header,
-      const PipelineStatusCB& status_cb);
+  // flv, and if it does make sense returns PIPELINE_OK and |*parser| contains a
+  // ShellFLVParser initialized with some basic state.  If it doesn't make sense
+  // this returns an error status and |*parser| contains NULL.
+  static PipelineStatus Construct(scoped_refptr<ShellDataSourceReader> reader,
+                                  const uint8* construction_header,
+                                  scoped_refptr<ShellParser>* parser);
   ShellFLVParser(scoped_refptr<ShellDataSourceReader> reader,
                  uint32 tag_start_offset);
   virtual ~ShellFLVParser();
diff --git a/src/media/filters/shell_mp4_parser.cc b/src/media/filters/shell_mp4_parser.cc
index 20ea082..0360858 100644
--- a/src/media/filters/shell_mp4_parser.cc
+++ b/src/media/filters/shell_mp4_parser.cc
@@ -72,34 +72,36 @@
 static const int kMapTableAtomCacheEntries_ctts = 51543 / kEntrySize_ctts;
 
 // static
-scoped_refptr<ShellParser> ShellMP4Parser::Construct(
+PipelineStatus ShellMP4Parser::Construct(
     scoped_refptr<ShellDataSourceReader> reader,
     const uint8* construction_header,
-    const PipelineStatusCB& status_cb) {
+    scoped_refptr<ShellParser>* parser) {
+  DCHECK(parser);
+  *parser = NULL;
+
   // detect mp4 stream by looking for ftyp atom at top of file
   uint32 ftyp = endian_util::load_uint32_big_endian(construction_header + 4);
   if (ftyp != kAtomType_ftyp) {
     // not an mp4
-    return NULL;
+    return DEMUXER_ERROR_COULD_NOT_PARSE;
   }
 
   // first 4 bytes will be the size of the ftyp atom
   uint32 ftyp_atom_size =
       endian_util::load_uint32_big_endian(construction_header);
   if (ftyp_atom_size < kAtomMinSize) {
-    status_cb.Run(DEMUXER_ERROR_COULD_NOT_PARSE);
-    return NULL;
+    return DEMUXER_ERROR_COULD_NOT_PARSE;
   }
 
-  // construct and return new mp4 parser
-  return scoped_refptr<ShellParser>(new ShellMP4Parser(reader, ftyp_atom_size));
+  // construct new mp4 parser
+  *parser = new ShellMP4Parser(reader, ftyp_atom_size);
+  return PIPELINE_OK;
 }
 
 ShellMP4Parser::ShellMP4Parser(scoped_refptr<ShellDataSourceReader> reader,
                                uint32 ftyp_atom_size)
     : ShellAVCParser(reader),
-      atom_offset_(ftyp_atom_size)  // start at next atom, skipping over ftyp
-      ,
+      atom_offset_(ftyp_atom_size),  // start at next atom, skipping over ftyp
       current_trak_is_video_(false),
       current_trak_is_audio_(false),
       current_trak_time_scale_(0),
diff --git a/src/media/filters/shell_mp4_parser.h b/src/media/filters/shell_mp4_parser.h
index a890c2c..bf7ea68 100644
--- a/src/media/filters/shell_mp4_parser.h
+++ b/src/media/filters/shell_mp4_parser.h
@@ -67,13 +67,13 @@
 
 class ShellMP4Parser : public ShellAVCParser {
  public:
-  // attempts to make sense of the provided bytes of the top of a file as an
-  // mp4, and if it does make sense returns a ShellMP4Parser initialized with
-  // some basic state. If it doesn't make sense this returns NULL
-  static scoped_refptr<ShellParser> Construct(
-      scoped_refptr<ShellDataSourceReader> reader,
-      const uint8* construction_header,
-      const PipelineStatusCB& status_cb);
+  // Attempts to make sense of the provided bytes of the top of a file as an
+  // flv, and if it does make sense returns PIPELINE_OK and |*parser| contains a
+  // ShellMP4Parser initialized with some basic state.  If it doesn't make sense
+  // this returns an error status and |*parser| contains NULL.
+  static PipelineStatus Construct(scoped_refptr<ShellDataSourceReader> reader,
+                                  const uint8* construction_header,
+                                  scoped_refptr<ShellParser>* parser);
   ShellMP4Parser(scoped_refptr<ShellDataSourceReader> reader,
                  uint32 ftyp_atom_size);
   virtual ~ShellMP4Parser();
diff --git a/src/media/filters/shell_parser.cc b/src/media/filters/shell_parser.cc
index b8b5c1c..f1d4958 100644
--- a/src/media/filters/shell_parser.cc
+++ b/src/media/filters/shell_parser.cc
@@ -16,6 +16,7 @@
 
 #include "media/filters/shell_parser.h"
 
+#include "base/logging.h"
 #include "media/filters/shell_flv_parser.h"
 #include "media/filters/shell_mp4_parser.h"
 
@@ -27,33 +28,27 @@
 const int ShellParser::kInitialHeaderSize = 9;
 
 // static
-scoped_refptr<ShellParser> ShellParser::Construct(
+PipelineStatus ShellParser::Construct(
     scoped_refptr<ShellDataSourceReader> reader,
-    const PipelineStatusCB& status_cb) {
-  scoped_refptr<ShellParser> parser;
+    scoped_refptr<ShellParser>* parser) {
+  DCHECK(parser);
+  *parser = NULL;
 
   // download first 16 bytes of stream to determine file type and extract basic
   // container-specific stream configuration information
   uint8 header[kInitialHeaderSize];
   int bytes_read = reader->BlockingRead(0, kInitialHeaderSize, header);
   if (bytes_read != kInitialHeaderSize) {
-    status_cb.Run(DEMUXER_ERROR_COULD_NOT_OPEN);
-    return NULL;
+    return DEMUXER_ERROR_COULD_NOT_PARSE;
   }
 
   // attempt to construct mp4 parser from this header
-  parser = ShellMP4Parser::Construct(reader, header, status_cb);
+  PipelineStatus status = ShellMP4Parser::Construct(reader, header, parser);
+  if (status == PIPELINE_OK) {
+    return status;
+  }
   // ok, attempt FLV
-  if (!parser) {
-    parser = ShellFLVParser::Construct(reader, header, status_cb);
-  }
-  // no additional supported container formats, set error and return
-  if (!parser) {
-    status_cb.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
-    return NULL;
-  }
-
-  return parser;
+  return ShellFLVParser::Construct(reader, header, parser);
 }
 
 ShellParser::ShellParser(scoped_refptr<ShellDataSourceReader> reader)
diff --git a/src/media/filters/shell_parser.h b/src/media/filters/shell_parser.h
index 057cbae..6d349b0 100644
--- a/src/media/filters/shell_parser.h
+++ b/src/media/filters/shell_parser.h
@@ -32,10 +32,10 @@
 class ShellParser : public base::RefCountedThreadSafe<ShellParser> {
  public:
   static const int kInitialHeaderSize;
-  // Determine stream type, construct appropriate parser object, and return.
-  static scoped_refptr<ShellParser> Construct(
-      scoped_refptr<ShellDataSourceReader> reader,
-      const PipelineStatusCB& status_cb);
+  // Determine stream type, construct appropriate parser object, and returns
+  // PIPELINE_OK on success or error code.
+  static PipelineStatus Construct(scoped_refptr<ShellDataSourceReader> reader,
+                                  scoped_refptr<ShellParser>* parser);
   explicit ShellParser(scoped_refptr<ShellDataSourceReader> reader);
 
   // Seek through the file looking for audio and video configuration info,
diff --git a/src/media/filters/video_renderer_base.cc b/src/media/filters/video_renderer_base.cc
index f1fa6fc..80d1f3d 100644
--- a/src/media/filters/video_renderer_base.cc
+++ b/src/media/filters/video_renderer_base.cc
@@ -300,14 +300,17 @@
   uint32 frames_dropped = 0;
 
   for (;;) {
-    if (frames_dropped > 0) {
 #if defined(__LB_SHELL__) || defined(COBALT)
+    frames_dropped =
+        static_cast<uint32>(frame_provider_->ResetAndReturnDroppedFrames());
+    if (frames_dropped > 0) {
       SCOPED_MEDIA_STATISTICS(STAT_TYPE_VIDEO_FRAME_DROP);
+    }
 #endif  // defined(__LB_SHELL__) || defined(COBALT)
+    if (frames_dropped > 0) {
       PipelineStatistics statistics;
       statistics.video_frames_dropped = frames_dropped;
       statistics_cb_.Run(statistics);
-
       frames_dropped = 0;
     }
 
diff --git a/src/nb/codereview.settings b/src/nb/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/nb/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/nb/memory_pool.cc b/src/nb/memory_pool.cc
index a420420..840042c 100644
--- a/src/nb/memory_pool.cc
+++ b/src/nb/memory_pool.cc
@@ -20,13 +20,22 @@
 
 namespace nb {
 
-MemoryPool::MemoryPool(void* buffer, std::size_t size, bool thread_safe)
+MemoryPool::MemoryPool(void* buffer,
+                       std::size_t size,
+                       bool thread_safe,
+                       bool verify_full_capacity)
     : no_free_allocator_(buffer, size),
       reuse_allocator_(
           scoped_ptr<Allocator>(new ReuseAllocator(&no_free_allocator_)),
           thread_safe) {
   SB_DCHECK(buffer);
   SB_DCHECK(size != 0U);
+
+  if (verify_full_capacity) {
+    void* p = Allocate(size);
+    SB_DCHECK(p);
+    Free(p);
+  }
 }
 
 void MemoryPool::PrintAllocations() const {
diff --git a/src/nb/memory_pool.h b/src/nb/memory_pool.h
index c6245b9..cef03db 100644
--- a/src/nb/memory_pool.h
+++ b/src/nb/memory_pool.h
@@ -29,7 +29,22 @@
 // as necessary.
 class MemoryPool : public Allocator {
  public:
-  MemoryPool(void* buffer, std::size_t size, bool thread_safe);
+  // When |verify_full_capacity| is true, the ctor tries to allocate the whole
+  // budget and free it immediately.  This can:
+  // 1. Ensure the |size| is accurate after accounting for all implicit
+  //    alignment enforced by the underlying allocators.
+  // 2. The |reuse_allocator_| contains a free block of the whole budget.  As
+  //    the |reuse_allocator_| doesn't support extending of free block, an
+  //    allocation that is larger than the both biggest free block in the
+  //    |reuse_allocator_| and the remaining memory inside the
+  //    |no_free_allocator_| will fail even if the combination of both can
+  //    fulfill the allocation.
+  // Note that when |verify_full_capacity| is true, GetHighWaterMark() always
+  // return the budget, which makes memory usage tracking useless.
+  MemoryPool(void* buffer,
+             std::size_t size,
+             bool thread_safe,
+             bool verify_full_capacity = false);
 
   void* Allocate(std::size_t size) { return reuse_allocator_.Allocate(size); }
   void* Allocate(std::size_t size, std::size_t alignment) {
diff --git a/src/nb/reuse_allocator.cc b/src/nb/reuse_allocator.cc
index 8fc07cf..61a40a6 100644
--- a/src/nb/reuse_allocator.cc
+++ b/src/nb/reuse_allocator.cc
@@ -98,7 +98,7 @@
 }
 
 void* ReuseAllocator::Allocate(std::size_t size) {
-  return Allocate(size, 0);
+  return Allocate(size, 1);
 }
 
 void* ReuseAllocator::AllocateForAlignment(std::size_t size,
@@ -107,6 +107,10 @@
 }
 
 void* ReuseAllocator::Allocate(std::size_t size, std::size_t alignment) {
+  if (alignment == 0) {
+    alignment = 1;
+  }
+
   // Try to satisfy request from free list.
   // First look for a block that is appropriately aligned.
   // If we can't, look for a block that is big enough that we can
diff --git a/src/starboard/audio_sink.h b/src/starboard/audio_sink.h
index efedf24..59f507b 100644
--- a/src/starboard/audio_sink.h
+++ b/src/starboard/audio_sink.h
@@ -42,6 +42,14 @@
 // audio frame buffer passed to SbAudioSinkCreate as |frame_buffers|.  As
 // |frame_buffers| is a circular buffer, |offset_in_frames| can be used to
 // calculate the number of continuous frames towards the end of the buffer.
+// The audio sink can play the frames only when |is_playing| is true.  It should
+// pause the playback when |is_playing| is false.
+// The audio sink may cache certain amount of audio frames before start
+// playback.  It will start playback immediately when |is_eos_reached| is true
+// even if the amount of cached audio frames are not enough as no more frames
+// will be appended into the buffer when |is_eos_reached| is true.
+// It is possible for a host to set |is_eos_reached| to false after setting it
+// to true, usually this is caused by a seek.
 // All parameters except |context| cannot be NULL.
 // Note that this function only reports the status of the source, it doesn't
 // remove audio data from the source frame buffer.
diff --git a/src/starboard/codereview.settings b/src/starboard/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/starboard/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h
index a106891..cff8fa8 100644
--- a/src/starboard/configuration.h
+++ b/src/starboard/configuration.h
@@ -58,7 +58,8 @@
 #define SB_IS(SB_FEATURE) (defined(SB_IS_##SB_FEATURE) && SB_IS_##SB_FEATURE)
 
 // Determines at compile-time whether this platform has a quirk.
-#define SB_HAS_QUIRK(SB_FEATURE) (defined(SB_HAS_QUIRK_##SB_FEATURE) && SB_HAS_QUIRK_##SB_FEATURE)
+#define SB_HAS_QUIRK(SB_FEATURE) \
+  (defined(SB_HAS_QUIRK_##SB_FEATURE) && SB_HAS_QUIRK_##SB_FEATURE)
 
 // Determines at compile-time if this platform implements a given Starboard API
 // version number (or above).
@@ -335,10 +336,6 @@
 #error "Your platform must define SB_MAX_THREAD_NAME_LENGTH."
 #endif
 
-#if !SB_HAS(DECODER) && !SB_HAS(PLAYER)
-#error "Your platform must have either a decoder or a player (or both)."
-#endif
-
 #if SB_HAS(PLAYER)
 #if !SB_IS(PLAYER_COMPOSITED) && !SB_IS(PLAYER_PUNCHED_OUT) && \
     !SB_IS(PLAYER_PRODUCING_TEXTURE)
@@ -356,17 +353,15 @@
     SB_IS(PLAYER_PRODUCING_TEXTURE)
 #error "Your player can't have a composition method if it doesn't exist."
 #endif
-
-#if !SB_HAS(DECODER)
-#error "Your platform must have either a decoder or a player."
-#endif
 #endif  // SB_HAS(PLAYER)
 
-#if (SB_HAS(MANY_CORES) &&                                       \
-     (SB_HAS(2_CORES) || SB_HAS(4_CORES) || SB_HAS(6_CORES))) || \
-    (SB_HAS(2_CORES) && (SB_HAS(4_CORES) || SB_HAS(6_CORES))) || \
+#if (SB_HAS(MANY_CORES) && (SB_HAS(1_CORE) || SB_HAS(2_CORES) ||    \
+                            SB_HAS(4_CORES) || SB_HAS(6_CORES))) || \
+    (SB_HAS(1_CORE) &&                                              \
+     (SB_HAS(2_CORES) || SB_HAS(4_CORES) || SB_HAS(6_CORES))) ||    \
+    (SB_HAS(2_CORES) && (SB_HAS(4_CORES) || SB_HAS(6_CORES))) ||    \
     (SB_HAS(4_CORES) && SB_HAS(6_CORES))
-#error "Only one of SB_HAS_{MANY, 2, 4, 6}_CORES can be defined per platform."
+#error "Only one SB_HAS_{MANY, 1, 2, 4, 6}_CORE[S] can be defined per platform."
 #endif
 
 #if !defined(SB_PREFERRED_RGBA_BYTE_ORDER)
diff --git a/src/starboard/event.h b/src/starboard/event.h
index c9f5614..5c1db49 100644
--- a/src/starboard/event.h
+++ b/src/starboard/event.h
@@ -78,6 +78,19 @@
   // No data argument.
   kSbEventTypeVerticalSync,
 
+  // The platform has detected a network disconnection. The platform should make
+  // a best effort to send an event of this type when the network disconnects,
+  // but there are likely to be cases where the platform cannot detect the
+  // disconnection (e.g. if the connection is via a powered hub which becomes
+  // disconnected), so the current network state cannot always be inferred from
+  // the sequence of Connect/Disconnect events.
+  kSbEventTypeNetworkDisconnect,
+
+  // The platform has detected a network connection. This event may be sent at
+  // application start-up, and should always be sent if the network reconnects
+  // since a disconnection event was sent.
+  kSbEventTypeNetworkConnect,
+
   // An event type reserved for scheduled callbacks. It will only be sent in
   // response to an application call to SbEventSchedule(), and it will call the
   // callback directly, so SbEventHandle should never receive this event
diff --git a/src/starboard/linux/shared/configuration_public.h b/src/starboard/linux/shared/configuration_public.h
index 4a161d9..624909f 100644
--- a/src/starboard/linux/shared/configuration_public.h
+++ b/src/starboard/linux/shared/configuration_public.h
@@ -234,18 +234,12 @@
 
 // --- Media Configuration ---------------------------------------------------
 
-// Specifies whether this platform has support for direct access to a decoder
-// for at least H.264/AAC. The decoder is likely to be faster-than-realtime, and
-// it is up to the client to retain decoded frames and display them synchronized
-// with the audio. The decoder must be wired up to the DRM system such that it
-// accepts encrypted samples.
-#define SB_HAS_DECODER 0
-
-// Specifies whether this platform has support for a decrypting elementary
-// stream player for at least AES128-CTR/H.264/AAC. A player is responsible for
-// ingesting an audio and video elementary stream, optionally-encrypted, and
-// ultimately producing synchronized audio/video. If a player is defined, it
-// must choose one of the supported composition methods below.
+// Specifies whether this platform has support for a possibly-decrypting
+// elementary stream player for at least H.264/AAC (and AES-128-CTR, if
+// decrypting). A player is responsible for ingesting an audio and video
+// elementary stream, optionally-encrypted, and ultimately producing
+// synchronized audio/video. If a player is defined, it must choose one of the
+// supported composition methods below.
 #define SB_HAS_PLAYER 1
 
 // Specifies whether this platform's player will produce an OpenGL texture that
diff --git a/src/starboard/linux/x64directfb/starboard_platform.gyp b/src/starboard/linux/x64directfb/starboard_platform.gyp
index 279c8d9..e692647 100644
--- a/src/starboard/linux/x64directfb/starboard_platform.gyp
+++ b/src/starboard/linux/x64directfb/starboard_platform.gyp
@@ -150,8 +150,6 @@
         '<(DEPTH)/starboard/shared/nouser/user_get_property.cc',
         '<(DEPTH)/starboard/shared/nouser/user_get_signed_in.cc',
         '<(DEPTH)/starboard/shared/nouser/user_internal.cc',
-        '<(DEPTH)/starboard/shared/nouser/user_is_age_restricted.cc',
-        '<(DEPTH)/starboard/shared/nouser/user_start_sign_in.cc',
         '<(DEPTH)/starboard/shared/posix/directory_create.cc',
         '<(DEPTH)/starboard/shared/posix/file_can_open.cc',
         '<(DEPTH)/starboard/shared/posix/file_close.cc',
@@ -301,6 +299,7 @@
         '<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
         '<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
         '<(DEPTH)/starboard/shared/stub/system_clear_platform_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
         '<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
       ],
       'include_dirs': [
diff --git a/src/starboard/linux/x64x11/configuration_public.h b/src/starboard/linux/x64x11/configuration_public.h
index f11107c..2291350 100644
--- a/src/starboard/linux/x64x11/configuration_public.h
+++ b/src/starboard/linux/x64x11/configuration_public.h
@@ -83,6 +83,9 @@
 // wildly varying number of cores.
 #define SB_HAS_MANY_CORES 1
 
+// Whether the current platform is expected to have exactly 1 core.
+#define SB_HAS_1_CORE 0
+
 // Whether the current platform is expected to have exactly 2 cores.
 #define SB_HAS_2_CORES 0
 
diff --git a/src/starboard/linux/x64x11/starboard_platform.gyp b/src/starboard/linux/x64x11/starboard_platform.gyp
index 46ea9aa..1609af2 100644
--- a/src/starboard/linux/x64x11/starboard_platform.gyp
+++ b/src/starboard/linux/x64x11/starboard_platform.gyp
@@ -113,8 +113,6 @@
         '<(DEPTH)/starboard/shared/nouser/user_get_property.cc',
         '<(DEPTH)/starboard/shared/nouser/user_get_signed_in.cc',
         '<(DEPTH)/starboard/shared/nouser/user_internal.cc',
-        '<(DEPTH)/starboard/shared/nouser/user_is_age_restricted.cc',
-        '<(DEPTH)/starboard/shared/nouser/user_start_sign_in.cc',
         '<(DEPTH)/starboard/shared/posix/directory_create.cc',
         '<(DEPTH)/starboard/shared/posix/file_can_open.cc',
         '<(DEPTH)/starboard/shared/posix/file_close.cc',
@@ -262,6 +260,7 @@
         '<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
         '<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
         '<(DEPTH)/starboard/shared/stub/system_clear_platform_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
         '<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
         '<(DEPTH)/starboard/shared/x11/application_x11.cc',
         '<(DEPTH)/starboard/shared/x11/window_create.cc',
diff --git a/src/starboard/log.h b/src/starboard/log.h
index 5f3aa9f..3693925 100644
--- a/src/starboard/log.h
+++ b/src/starboard/log.h
@@ -141,6 +141,7 @@
 const SbLogPriority SB_LOG_WARNING = kSbLogPriorityWarning;
 const SbLogPriority SB_LOG_ERROR = kSbLogPriorityError;
 const SbLogPriority SB_LOG_FATAL = kSbLogPriorityFatal;
+const SbLogPriority SB_LOG_0 = SB_LOG_ERROR;
 
 class SB_EXPORT LogMessage {
  public:
@@ -185,6 +186,10 @@
   ::starboard::logging::LogMessage(__FILE__, __LINE__, \
                                    ::starboard::logging::SB_LOG_FATAL)
 
+// Compatibility with base/logging.h which defines ERROR to be 0 to workaround
+// some system header defines that do the same thing.
+#define SB_LOG_MESSAGE_0 SB_LOG_MESSAGE_ERROR
+
 #define SB_LOG_STREAM(severity) SB_LOG_MESSAGE_##severity.stream()
 #define SB_LAZY_STREAM(stream, condition) \
   !(condition) ? (void)0 : ::starboard::logging::LogMessageVoidify() & (stream)
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp
index 0835148..3761520 100644
--- a/src/starboard/nplb/nplb.gyp
+++ b/src/starboard/nplb/nplb.gyp
@@ -190,6 +190,7 @@
         'system_get_stack_test.cc',
         'system_get_total_memory_test.cc',
         'system_has_capability_test.cc',
+        'system_hide_splash_screen_test.cc',
         'system_is_debugger_attached_test.cc',
         'system_sort_test.cc',
         'system_symbolize_test.cc',
diff --git a/src/starboard/nplb/system_hide_splash_screen_test.cc b/src/starboard/nplb/system_hide_splash_screen_test.cc
new file mode 100644
index 0000000..a97392e
--- /dev/null
+++ b/src/starboard/nplb/system_hide_splash_screen_test.cc
@@ -0,0 +1,35 @@
+// 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.
+
+// Here we are not trying to do anything fancy, just to really sanity check that
+// this is hooked up to something.
+
+#include "starboard/system.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+TEST(SbSystemHideSplashScreenTest, SunnyDay) {
+  // Function returns no result, and correct execution cannot be determined
+  // programatically, but we should at least be able to call it twice without
+  // crashing.
+  SbSystemHideSplashScreen();
+  SbSystemHideSplashScreen();
+}
+
+}  // namespace
+}  // namespace nplb
+}  // namespace starboard
diff --git a/src/starboard/raspi/1/configuration_public.h b/src/starboard/raspi/1/configuration_public.h
index df2d8bf..3cedc59 100644
--- a/src/starboard/raspi/1/configuration_public.h
+++ b/src/starboard/raspi/1/configuration_public.h
@@ -71,7 +71,10 @@
 
 // Whether the current platform is expected to have many cores (> 6), or a
 // wildly varying number of cores.
-#define SB_HAS_MANY_CORES 1
+#define SB_HAS_MANY_CORES 0
+
+// Whether the current platform is expected to have exactly 1 core.
+#define SB_HAS_1_CORE 1
 
 // Whether the current platform is expected to have exactly 2 cores.
 #define SB_HAS_2_CORES 0
diff --git a/src/starboard/raspi/1/starboard_platform.gyp b/src/starboard/raspi/1/starboard_platform.gyp
index 1b80d83..7206d0c 100644
--- a/src/starboard/raspi/1/starboard_platform.gyp
+++ b/src/starboard/raspi/1/starboard_platform.gyp
@@ -120,8 +120,6 @@
         '<(DEPTH)/starboard/shared/nouser/user_get_property.cc',
         '<(DEPTH)/starboard/shared/nouser/user_get_signed_in.cc',
         '<(DEPTH)/starboard/shared/nouser/user_internal.cc',
-        '<(DEPTH)/starboard/shared/nouser/user_is_age_restricted.cc',
-        '<(DEPTH)/starboard/shared/nouser/user_start_sign_in.cc',
         '<(DEPTH)/starboard/shared/posix/directory_create.cc',
         '<(DEPTH)/starboard/shared/posix/file_can_open.cc',
         '<(DEPTH)/starboard/shared/posix/file_close.cc',
@@ -269,6 +267,7 @@
         '<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
         '<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
         '<(DEPTH)/starboard/shared/stub/system_clear_platform_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
         '<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
       ],
       'defines': [
diff --git a/src/starboard/raspi/shared/configuration_public.h b/src/starboard/raspi/shared/configuration_public.h
index de26224..b7ba3a6 100644
--- a/src/starboard/raspi/shared/configuration_public.h
+++ b/src/starboard/raspi/shared/configuration_public.h
@@ -229,18 +229,12 @@
 
 // --- Media Configuration ---------------------------------------------------
 
-// Specifies whether this platform has support for direct access to a decoder
-// for at least H.264/AAC. The decoder is likely to be faster-than-realtime, and
-// it is up to the client to retain decoded frames and display them synchronized
-// with the audio. The decoder must be wired up to the DRM system such that it
-// accepts encrypted samples.
-#define SB_HAS_DECODER 0
-
-// Specifies whether this platform has support for a decrypting elementary
-// stream player for at least AES128-CTR/H.264/AAC. A player is responsible for
-// ingesting an audio and video elementary stream, optionally-encrypted, and
-// ultimately producing synchronized audio/video. If a player is defined, it
-// must choose one of the supported composition methods below.
+// Specifies whether this platform has support for a possibly-decrypting
+// elementary stream player for at least H.264/AAC (and AES-128-CTR, if
+// decrypting). A player is responsible for ingesting an audio and video
+// elementary stream, optionally-encrypted, and ultimately producing
+// synchronized audio/video. If a player is defined, it must choose one of the
+// supported composition methods below.
 #define SB_HAS_PLAYER 1
 
 // Specifies whether this platform's player will produce an OpenGL texture that
diff --git a/src/starboard/shared/alsa/alsa_audio_sink_type.cc b/src/starboard/shared/alsa/alsa_audio_sink_type.cc
index 5a89222..8f2ce61 100644
--- a/src/starboard/shared/alsa/alsa_audio_sink_type.cc
+++ b/src/starboard/shared/alsa/alsa_audio_sink_type.cc
@@ -14,10 +14,13 @@
 
 #include "starboard/shared/alsa/alsa_audio_sink_type.h"
 
+#include <alsa/asoundlib.h>
+
 #include <algorithm>
 #include <vector>
 
 #include "starboard/condition_variable.h"
+#include "starboard/memory.h"
 #include "starboard/mutex.h"
 #include "starboard/shared/alsa/alsa_util.h"
 #include "starboard/thread.h"
@@ -49,6 +52,23 @@
 // that is too large can waste some memory as the extra buffer is never used.
 const int kALSABufferSizeInFrames = 8192;
 
+// Helper function to compute the size of the two valid starboard audio sample
+// types.
+size_t GetSampleSize(SbMediaAudioSampleType sample_type) {
+  switch (sample_type) {
+    case kSbMediaAudioSampleTypeFloat32:
+      return sizeof(float);
+    case kSbMediaAudioSampleTypeInt16:
+      return sizeof(int16_t);
+  }
+  SB_NOTREACHED();
+  return 0u;
+}
+
+void* IncrementPointerByBytes(void* pointer, size_t offset) {
+  return static_cast<void*>(static_cast<uint8_t*>(pointer) + offset);
+}
+
 // This class is an ALSA based audio sink with the following features:
 // 1. It doesn't cache any data internally and maintains minimum data inside
 //    the ALSA buffer.  It relies on pulling data from its source in high
@@ -61,6 +81,7 @@
   AlsaAudioSink(Type* type,
                 int channels,
                 int sampling_frequency_hz,
+                SbMediaAudioSampleType sample_type,
                 SbAudioSinkFrameBuffers frame_buffers,
                 int frames_per_channel,
                 SbAudioSinkUpdateSourceStatusFunc update_source_status_func,
@@ -95,6 +116,7 @@
 
   int channels_;
   int sampling_frequency_hz_;
+  SbMediaAudioSampleType sample_type_;
 
   SbThread audio_out_thread_;
   starboard::Mutex mutex_;
@@ -104,9 +126,9 @@
 
   bool destroying_;
 
-  float* frame_buffer_;
+  void* frame_buffer_;
   int frames_per_channel_;
-  std::vector<float> silence_frames_;
+  void* silence_frames_;
 
   void* playback_handle_;
 };
@@ -115,6 +137,7 @@
     Type* type,
     int channels,
     int sampling_frequency_hz,
+    SbMediaAudioSampleType sample_type,
     SbAudioSinkFrameBuffers frame_buffers,
     int frames_per_channel,
     SbAudioSinkUpdateSourceStatusFunc update_source_status_func,
@@ -123,6 +146,7 @@
     : type_(type),
       channels_(channels),
       sampling_frequency_hz_(sampling_frequency_hz),
+      sample_type_(sample_type),
       update_source_status_func_(update_source_status_func),
       consume_frame_func_(consume_frame_func),
       context_(context),
@@ -131,19 +155,23 @@
       time_to_wait_(kFramesPerRequest * kSbTimeSecond / sampling_frequency_hz /
                     2),
       destroying_(false),
-      frame_buffer_(reinterpret_cast<float*>(frame_buffers[0])),
+      frame_buffer_(frame_buffers[0]),
       frames_per_channel_(frames_per_channel),
-      silence_frames_(channels * kFramesPerRequest),
+      silence_frames_(new uint8_t[channels * kFramesPerRequest *
+                                  GetSampleSize(sample_type)]),
       playback_handle_(NULL) {
   SB_DCHECK(update_source_status_func_);
   SB_DCHECK(consume_frame_func_);
   SB_DCHECK(frame_buffer_);
+  SB_DCHECK(SbAudioSinkIsAudioSampleTypeSupported(sample_type_));
 
   ScopedLock lock(mutex_);
   audio_out_thread_ =
       SbThreadCreate(0, kSbThreadPriorityRealTime, kSbThreadNoAffinity, true,
                      "alsa_audio_out", &AlsaAudioSink::ThreadEntryPoint, this);
   SB_DCHECK(SbThreadIsValid(audio_out_thread_));
+  SbMemorySet(silence_frames_, 0,
+              channels * kFramesPerRequest * GetSampleSize(sample_type));
   creation_signal_.Wait();
 }
 
@@ -153,6 +181,8 @@
     destroying_ = true;
   }
   SbThreadJoin(audio_out_thread_, NULL);
+
+  delete[] static_cast<uint8_t*>(silence_frames_);
 }
 
 // static
@@ -165,9 +195,13 @@
 }
 
 void AlsaAudioSink::AudioThreadFunc() {
+  snd_pcm_format_t alsa_sample_type =
+      sample_type_ == kSbMediaAudioSampleTypeFloat32 ? SND_PCM_FORMAT_FLOAT_LE
+                                                     : SND_PCM_FORMAT_S16;
+
   playback_handle_ = starboard::shared::alsa::AlsaOpenPlaybackDevice(
       channels_, sampling_frequency_hz_, kFramesPerRequest,
-      kALSABufferSizeInFrames);
+      kALSABufferSizeInFrames, alsa_sample_type);
   creation_signal_.Signal();
   if (!playback_handle_) {
     return;
@@ -206,7 +240,7 @@
     }
     int delayed_frame = AlsaGetBufferedFrames(playback_handle_);
     if (delayed_frame < kMinimumFramesInALSA) {
-      AlsaWriteFrames(playback_handle_, &silence_frames_[0], kFramesPerRequest);
+      AlsaWriteFrames(playback_handle_, silence_frames_, kFramesPerRequest);
     } else {
       SbThreadSleep(time_to_wait_);
     }
@@ -255,9 +289,11 @@
 
   int frames_to_buffer_end = frames_per_channel_ - offset_in_frames;
   if (frames_to_write > frames_to_buffer_end) {
-    int consumed = AlsaWriteFrames(playback_handle_,
-                                   frame_buffer_ + offset_in_frames * channels_,
-                                   frames_to_buffer_end);
+    int consumed = AlsaWriteFrames(
+        playback_handle_,
+        IncrementPointerByBytes(frame_buffer_, offset_in_frames * channels_ *
+                                                   GetSampleSize(sample_type_)),
+        frames_to_buffer_end);
     consume_frame_func_(consumed, context_);
     if (consumed != frames_to_buffer_end) {
       return;
@@ -267,9 +303,11 @@
     offset_in_frames = 0;
   }
 
-  int consumed = AlsaWriteFrames(playback_handle_,
-                                 frame_buffer_ + offset_in_frames * channels_,
-                                 frames_to_write);
+  int consumed = AlsaWriteFrames(
+      playback_handle_,
+      IncrementPointerByBytes(frame_buffer_, offset_in_frames * channels_ *
+                                                 GetSampleSize(sample_type_)),
+      frames_to_write);
   consume_frame_func_(consumed, context_);
 }
 
@@ -286,8 +324,9 @@
     SbAudioSinkConsumeFramesFunc consume_frames_func,
     void* context) {
   AlsaAudioSink* audio_sink = new AlsaAudioSink(
-      this, channels, sampling_frequency_hz, frame_buffers, frames_per_channel,
-      update_source_status_func, consume_frames_func, context);
+      this, channels, sampling_frequency_hz, audio_sample_type, frame_buffers,
+      frames_per_channel, update_source_status_func, consume_frames_func,
+      context);
   if (!audio_sink->is_valid()) {
     delete audio_sink;
     return kSbAudioSinkInvalid;
diff --git a/src/starboard/shared/alsa/alsa_util.cc b/src/starboard/shared/alsa/alsa_util.cc
index 6638e81..c713015 100644
--- a/src/starboard/shared/alsa/alsa_util.cc
+++ b/src/starboard/shared/alsa/alsa_util.cc
@@ -92,7 +92,11 @@
 void* AlsaOpenPlaybackDevice(int channel,
                              int sample_rate,
                              int frames_per_request,
-                             int buffer_size_in_frames) {
+                             int buffer_size_in_frames,
+                             snd_pcm_format_t sample_type) {
+  SB_DCHECK(sample_type == SND_PCM_FORMAT_FLOAT_LE ||
+            sample_type == SND_PCM_FORMAT_S16);
+
   PcmHandle playback_handle;
   int error =
       snd_pcm_open(&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
@@ -111,8 +115,7 @@
                                        SND_PCM_ACCESS_RW_INTERLEAVED);
   ALSA_CHECK(error, snd_pcm_hw_params_set_access, NULL);
 
-  error = snd_pcm_hw_params_set_format(playback_handle, hw_params,
-                                       SND_PCM_FORMAT_FLOAT_LE);
+  error = snd_pcm_hw_params_set_format(playback_handle, hw_params, sample_type);
   ALSA_CHECK(error, snd_pcm_hw_params_set_format, NULL);
 
   error =
@@ -159,7 +162,7 @@
 }
 
 int AlsaWriteFrames(void* playback_handle,
-                    const float* buffer,
+                    const void* buffer,
                     int frames_to_write) {
   if (frames_to_write == 0) {
     return 0;
diff --git a/src/starboard/shared/alsa/alsa_util.h b/src/starboard/shared/alsa/alsa_util.h
index 9cfe472..bbbe04f 100644
--- a/src/starboard/shared/alsa/alsa_util.h
+++ b/src/starboard/shared/alsa/alsa_util.h
@@ -15,6 +15,8 @@
 #ifndef STARBOARD_SHARED_ALSA_ALSA_UTIL_H_
 #define STARBOARD_SHARED_ALSA_ALSA_UTIL_H_
 
+#include <alsa/asoundlib.h>
+
 #include "starboard/shared/internal_only.h"
 
 namespace starboard {
@@ -26,10 +28,11 @@
 void* AlsaOpenPlaybackDevice(int channel,
                              int sample_rate,
                              int frames_per_request,
-                             int buffer_size_in_frames);
+                             int buffer_size_in_frames,
+                             snd_pcm_format_t sample_type);
 bool AlsaStartPlay(void* playback_handle);
 int AlsaWriteFrames(void* playback_handle,
-                    const float* buffer,
+                    const void* buffer,
                     int frames_to_write);
 int AlsaGetBufferedFrames(void* playback_handle);
 void AlsaCloseDevice(void* playback_handle);
diff --git a/src/starboard/shared/linux/page_internal.cc b/src/starboard/shared/linux/page_internal.cc
index 5aec2ed..8b84135 100644
--- a/src/starboard/shared/linux/page_internal.cc
+++ b/src/starboard/shared/linux/page_internal.cc
@@ -44,10 +44,12 @@
     mmap_protect |= PROT_WRITE;
     flag_set = true;
   }
+#if SB_CAN(MAP_EXECUTABLE_MEMORY)
   if (sb_flags & kSbMemoryMapProtectExec) {
     mmap_protect |= PROT_EXEC;
     flag_set = true;
   }
+#endif
   if (!flag_set) {
     mmap_protect = PROT_NONE;
   }
diff --git a/src/starboard/shared/pthread/thread_create.cc b/src/starboard/shared/pthread/thread_create.cc
index 813d3ac..70a1fdb 100644
--- a/src/starboard/shared/pthread/thread_create.cc
+++ b/src/starboard/shared/pthread/thread_create.cc
@@ -63,6 +63,14 @@
     return kSbThreadInvalid;
   }
 
+#if defined(ADDRESS_SANITIZER)
+  // Set a big thread stack size when in ADDRESS_SANITIZER mode.
+  // This eliminates buffer overflows for deeply nested callstacks.
+  if (stack_size == 0) {
+    stack_size = 4096 * 1024;  // 4MB
+  }
+#endif
+
   pthread_attr_t attributes;
   int result = pthread_attr_init(&attributes);
   if (!IsSuccess(result)) {
diff --git a/src/starboard/shared/signal/crash_signals.cc b/src/starboard/shared/signal/crash_signals.cc
index 2ea26a7..5c20870 100644
--- a/src/starboard/shared/signal/crash_signals.cc
+++ b/src/starboard/shared/signal/crash_signals.cc
@@ -61,13 +61,13 @@
 
 void InstallCrashSignalHandlers() {
   for (int i = 0; i < SB_ARRAY_SIZE_INT(kSignalsToTrap); ++i) {
-    ::signal(i, &DumpStackSignalSafe);
+    ::signal(kSignalsToTrap[i], &DumpStackSignalSafe);
   }
 }
 
 void UninstallCrashSignalHandlers() {
   for (int i = 0; i < SB_ARRAY_SIZE_INT(kSignalsToTrap); ++i) {
-    ::signal(i, SIG_DFL);
+    ::signal(kSignalsToTrap[i], SIG_DFL);
   }
 }
 
diff --git a/src/starboard/shared/stub/user_start_sign_in.cc b/src/starboard/shared/stub/system_hide_splash_screen.cc
similarity index 90%
rename from src/starboard/shared/stub/user_start_sign_in.cc
rename to src/starboard/shared/stub/system_hide_splash_screen.cc
index 9a99a99..cccc8d5 100644
--- a/src/starboard/shared/stub/user_start_sign_in.cc
+++ b/src/starboard/shared/stub/system_hide_splash_screen.cc
@@ -12,7 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "starboard/user.h"
+#include "starboard/system.h"
 
-void SbUserStartSignIn() {
-}
+void SbSystemHideSplashScreen() {}
diff --git a/src/starboard/shared/stub/user_is_age_restricted.cc b/src/starboard/shared/stub/user_is_age_restricted.cc
deleted file mode 100644
index a875b2a..0000000
--- a/src/starboard/shared/stub/user_is_age_restricted.cc
+++ /dev/null
@@ -1,19 +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/user.h"
-
-bool SbUserIsAgeRestricted(SbUser /*user*/) {
-  return false;
-}
diff --git a/src/starboard/stub/configuration_public.h b/src/starboard/stub/configuration_public.h
index 744c7d5..af9c671 100644
--- a/src/starboard/stub/configuration_public.h
+++ b/src/starboard/stub/configuration_public.h
@@ -73,6 +73,9 @@
 // wildly varying number of cores.
 #define SB_HAS_MANY_CORES 1
 
+// Whether the current platform is expected to have exactly 1 core.
+#define SB_HAS_1_CORE 0
+
 // Whether the current platform is expected to have exactly 2 cores.
 #define SB_HAS_2_CORES 0
 
@@ -299,18 +302,12 @@
 
 // --- Media Configuration ---------------------------------------------------
 
-// Specifies whether this platform has support for direct access to a decoder
-// for at least H.264/AAC. The decoder is likely to be faster-than-realtime, and
-// it is up to the client to retain decoded frames and display them synchronized
-// with the audio. The decoder must be wired up to the DRM system such that it
-// accepts encrypted samples.
-#define SB_HAS_DECODER 0
-
-// Specifies whether this platform has support for a decrypting elementary
-// stream player for at least AES128-CTR/H.264/AAC. A player is responsible for
-// ingesting an audio and video elementary stream, optionally-encrypted, and
-// ultimately producing synchronized audio/video. If a player is defined, it
-// must choose one of the supported composition methods below.
+// Specifies whether this platform has support for a possibly-decrypting
+// elementary stream player for at least H.264/AAC (and AES-128-CTR, if
+// decrypting). A player is responsible for ingesting an audio and video
+// elementary stream, optionally-encrypted, and ultimately producing
+// synchronized audio/video. If a player is defined, it must choose one of the
+// supported composition methods below.
 #define SB_HAS_PLAYER 1
 
 // Specifies whether this platform's player will produce an OpenGL texture that
diff --git a/src/starboard/stub/starboard_platform.gyp b/src/starboard/stub/starboard_platform.gyp
index 1279317..e871191 100644
--- a/src/starboard/stub/starboard_platform.gyp
+++ b/src/starboard/stub/starboard_platform.gyp
@@ -184,6 +184,7 @@
         '<(DEPTH)/starboard/shared/stub/system_get_stack.cc',
         '<(DEPTH)/starboard/shared/stub/system_get_total_memory.cc',
         '<(DEPTH)/starboard/shared/stub/system_has_capability.cc',
+        '<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
         '<(DEPTH)/starboard/shared/stub/system_is_debugger_attached.cc',
         '<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
         '<(DEPTH)/starboard/shared/stub/system_request_stop.cc',
@@ -212,8 +213,6 @@
         '<(DEPTH)/starboard/shared/stub/user_get_current.cc',
         '<(DEPTH)/starboard/shared/stub/user_get_property.cc',
         '<(DEPTH)/starboard/shared/stub/user_get_signed_in.cc',
-        '<(DEPTH)/starboard/shared/stub/user_is_age_restricted.cc',
-        '<(DEPTH)/starboard/shared/stub/user_start_sign_in.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/system.h b/src/starboard/system.h
index 616d421..5cdad66 100644
--- a/src/starboard/system.h
+++ b/src/starboard/system.h
@@ -365,6 +365,11 @@
                             size_t element_width,
                             SbSystemComparator comparator);
 
+// Hides the system splash screen, on systems that support a splash screen that
+// is displayed while the application is loading. This function may be called
+// from any thread and must be idempotent.
+SB_EXPORT void SbSystemHideSplashScreen();
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/src/starboard/user.h b/src/starboard/user.h
index 9dd1e1a..bf9a5d4 100644
--- a/src/starboard/user.h
+++ b/src/starboard/user.h
@@ -96,10 +96,6 @@
 // will persist for the lifetime of the app.
 SB_EXPORT SbUser SbUserGetCurrent();
 
-// Returns whether |user| is age-restricted according to the platform's age
-// policies.
-SB_EXPORT bool SbUserIsAgeRestricted(SbUser user);
-
 // Gets the size of the value of |property_id| for |user|, INCLUDING the
 // terminating null character. Returns 0 if if |user| is invalid, |property_id|
 // isn't recognized, supported, or set for |user|.
@@ -113,10 +109,6 @@
                                  char* out_value,
                                  int value_size);
 
-// Begins the user sign-in flow for the given platform, which may result in a
-// user changed event being dispatched.
-SB_EXPORT void SbUserStartSignIn();
-
 #if SB_HAS(USER_APPLICATION_LINKING_SUPPORT)
 // Initiates a process to link |user| with a per-application authentication
 // token. On success, |out_token| is populated with the authentication token
diff --git a/src/testing/gmock/codereview.settings b/src/testing/gmock/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/testing/gmock/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/testing/gtest-parallel/LICENSE b/src/testing/gtest-parallel/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/src/testing/gtest-parallel/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/src/testing/gtest-parallel/README.cobalt b/src/testing/gtest-parallel/README.cobalt
new file mode 100644
index 0000000..0d388eb
--- /dev/null
+++ b/src/testing/gtest-parallel/README.cobalt
@@ -0,0 +1,59 @@
+Name: gtest-parallel
+URL: https://github.com/google/gtest-parallel
+Version: 0
+License: Apache 2.0
+Security Critical: no
+
+Description
+    This directory contains the source code of a python project that helps run
+    gtest binaries in parallel using multiple processes.
+
+How to use
+    Pre-reqs: Python (2)
+    1.  ./gtest-parallel <name-of-gtest-binary>
+
+    for additional options, see ./gtest-parallel --help
+
+    If all the tests pass, you will be see one line on the screen get updated.
+    If a test fails, it will print out the test result and scroll a little bit.
+
+    Example: $ ./gtest-parallel ~/cobalt/src/out/linux-x64x11_debug/layout_tests
+    [436/436] BidiLayoutTests/LayoutTest.LayoutTest/1 (1285 ms)
+
+Troubleshooting
+    1.  Make sure that the gtest-parallel script is executable:
+      chmod +x ./gtest-parallel
+
+Source
+1.  a) The external repo was imported into our git server on lbshell-internal,
+       repo name is gtest-parallel
+    b) A new branch was created with the date of last commit
+    c) Then it was pushed to the COBALT branch
+
+    Steps for step 1.b:
+    $ git clone https://lbshell-internal.googlesource.com/testing/gtest-parallel
+    $ cd gtest-parallel/
+    $ git remote add upstream https://github.com/google/gtest-parallel.git
+    $ git fetch upstream
+    $ git checkout -b 20160803 upstream/master
+    $ git push origin
+
+    You will likely need admin permissions on the repo to execute the git push.
+
+2. A patch was applied since gtest now prints some things to stderr instead of
+   stdout.
+
+    $ patch < patches/stderr_out.patch
+
+FAQ
+1.  Do the tests need to be thread safe?
+
+    No, the script first asks the binary for the list of tests, and then splits
+    them across multiple processes.
+
+Patches
+1.  patches/stderr_out.patch
+
+    Starboard redirects some output from stdout to stderr.
+    Therefore, we needed to modify the the gtest-parallel script to parse stderr
+    instead of stdout.
diff --git a/src/testing/gtest-parallel/gtest-parallel b/src/testing/gtest-parallel/gtest-parallel
new file mode 100755
index 0000000..a258a87
--- /dev/null
+++ b/src/testing/gtest-parallel/gtest-parallel
@@ -0,0 +1,411 @@
+#!/usr/bin/env python2
+# Copyright 2013 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.
+import cPickle
+import errno
+import gzip
+import multiprocessing
+import optparse
+import os
+import signal
+import subprocess
+import sys
+import tempfile
+import thread
+import threading
+import time
+import zlib
+
+# An object that catches SIGINT sent to the Python process and notices
+# if processes passed to wait() die by SIGINT (we need to look for
+# both of those cases, because pressing Ctrl+C can result in either
+# the main process or one of the subprocesses getting the signal).
+#
+# Before a SIGINT is seen, wait(p) will simply call p.wait() and
+# return the result. Once a SIGINT has been seen (in the main process
+# or a subprocess, including the one the current call is waiting for),
+# wait(p) will call p.terminate() and raise ProcessWasInterrupted.
+class SigintHandler(object):
+  class ProcessWasInterrupted(Exception): pass
+  sigint_returncodes = {-signal.SIGINT,  # Unix
+                        -1073741510,     # Windows
+                        }
+  def __init__(self):
+    self.__lock = threading.Lock()
+    self.__processes = set()
+    self.__got_sigint = False
+    signal.signal(signal.SIGINT, self.__sigint_handler)
+  def __on_sigint(self):
+    self.__got_sigint = True
+    while self.__processes:
+      try:
+        self.__processes.pop().terminate()
+      except OSError:
+        pass
+  def __sigint_handler(self, signal_num, frame):
+    with self.__lock:
+      self.__on_sigint()
+  def got_sigint(self):
+    with self.__lock:
+      return self.__got_sigint
+  def wait(self, p):
+    with self.__lock:
+      if self.__got_sigint:
+        p.terminate()
+      self.__processes.add(p)
+    code = p.wait()
+    with self.__lock:
+      self.__processes.discard(p)
+      if code in self.sigint_returncodes:
+        self.__on_sigint()
+      if self.__got_sigint:
+        raise self.ProcessWasInterrupted
+    return code
+sigint_handler = SigintHandler()
+
+# Return the width of the terminal, or None if it couldn't be
+# determined (e.g. because we're not being run interactively).
+def term_width(out):
+  if not out.isatty():
+    return None
+  try:
+    p = subprocess.Popen(["stty", "size"],
+                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    (out, err) = p.communicate()
+    if p.returncode != 0 or err:
+      return None
+    return int(out.split()[1])
+  except (IndexError, OSError, ValueError):
+    return None
+
+# Output transient and permanent lines of text. If several transient
+# lines are written in sequence, the new will overwrite the old. We
+# use this to ensure that lots of unimportant info (tests passing)
+# won't drown out important info (tests failing).
+class Outputter(object):
+  def __init__(self, out_file):
+    self.__out_file = out_file
+    self.__previous_line_was_transient = False
+    self.__width = term_width(out_file)  # Line width, or None if not a tty.
+  def transient_line(self, msg):
+    if self.__width is None:
+      self.__out_file.write(msg + "\n")
+    else:
+      self.__out_file.write("\r" + msg[:self.__width].ljust(self.__width))
+      self.__previous_line_was_transient = True
+  def flush_transient_output(self):
+    if self.__previous_line_was_transient:
+      self.__out_file.write("\n")
+      self.__previous_line_was_transient = False
+  def permanent_line(self, msg):
+    self.flush_transient_output()
+    self.__out_file.write(msg + "\n")
+
+stdout_lock = threading.Lock()
+
+class FilterFormat:
+  if sys.stdout.isatty():
+    # stdout needs to be unbuffered since the output is interactive.
+    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+
+  out = Outputter(sys.stdout)
+  total_tests = 0
+  finished_tests = 0
+
+  tests = {}
+  outputs = {}
+  failures = []
+
+  def print_test_status(self, last_finished_test, time_ms):
+    self.out.transient_line("[%d/%d] %s (%d ms)"
+                            % (self.finished_tests, self.total_tests,
+                               last_finished_test, time_ms))
+
+  def handle_meta(self, job_id, args):
+    (command, arg) = args.split(' ', 1)
+    if command == "TEST":
+      (binary, test) = arg.split(' ', 1)
+      self.tests[job_id] = (binary, test.strip())
+    elif command == "EXIT":
+      (exit_code, time_ms) = [int(x) for x in arg.split(' ', 1)]
+      self.finished_tests += 1
+      (binary, test) = self.tests[job_id]
+      self.print_test_status(test, time_ms)
+      if exit_code != 0:
+        self.failures.append(self.tests[job_id])
+        with open(self.outputs[job_id]) as f:
+          for line in f.readlines():
+            self.out.permanent_line(line.rstrip())
+        self.out.permanent_line(
+          "[%d/%d] %s returned/aborted with exit code %d (%d ms)"
+          % (self.finished_tests, self.total_tests, test, exit_code, time_ms))
+    elif command == "TESTCNT":
+      self.total_tests = int(arg.split(' ', 1)[1])
+      self.out.transient_line("[0/%d] Running tests..." % self.total_tests)
+
+  def logfile(self, job_id, name):
+    self.outputs[job_id] = name
+
+  def log(self, line):
+    stdout_lock.acquire()
+    (prefix, output) = line.split(' ', 1)
+
+    assert prefix[-1] == ':'
+    self.handle_meta(int(prefix[:-1]), output)
+    stdout_lock.release()
+
+  def end(self):
+    if self.failures:
+      self.out.permanent_line("FAILED TESTS (%d/%d):"
+                              % (len(self.failures), self.total_tests))
+      for (binary, test) in self.failures:
+        self.out.permanent_line(" " + binary + ": " + test)
+    self.out.flush_transient_output()
+
+class RawFormat:
+  def log(self, line):
+    stdout_lock.acquire()
+    sys.stdout.write(line + "\n")
+    sys.stdout.flush()
+    stdout_lock.release()
+  def logfile(self, job_id, name):
+    with open(name) as f:
+      for line in f.readlines():
+        self.log(str(job_id) + '> ' + line.rstrip())
+  def end(self):
+    pass
+
+# Record of test runtimes. Has built-in locking.
+class TestTimes(object):
+  def __init__(self, save_file):
+    "Create new object seeded with saved test times from the given file."
+    self.__times = {}  # (test binary, test name) -> runtime in ms
+
+    # Protects calls to record_test_time(); other calls are not
+    # expected to be made concurrently.
+    self.__lock = threading.Lock()
+
+    try:
+      with gzip.GzipFile(save_file, "rb") as f:
+        times = cPickle.load(f)
+    except (EOFError, IOError, cPickle.UnpicklingError, zlib.error):
+      # File doesn't exist, isn't readable, is malformed---whatever.
+      # Just ignore it.
+      return
+
+    # Discard saved times if the format isn't right.
+    if type(times) is not dict:
+      return
+    for ((test_binary, test_name), runtime) in times.items():
+      if (type(test_binary) is not str or type(test_name) is not str
+          or type(runtime) not in {int, long, type(None)}):
+        return
+
+    self.__times = times
+
+  def get_test_time(self, binary, testname):
+    """Return the last duration for the given test as an integer number of
+    milliseconds, or None if the test failed or if there's no record for it."""
+    return self.__times.get((binary, testname), None)
+
+  def record_test_time(self, binary, testname, runtime_ms):
+    """Record that the given test ran in the specified number of
+    milliseconds. If the test failed, runtime_ms should be None."""
+    with self.__lock:
+      self.__times[(binary, testname)] = runtime_ms
+
+  def write_to_file(self, save_file):
+    "Write all the times to file."
+    try:
+      with open(save_file, "wb") as f:
+        with gzip.GzipFile("", "wb", 9, f) as gzf:
+          cPickle.dump(self.__times, gzf, cPickle.HIGHEST_PROTOCOL)
+    except IOError:
+      pass  # ignore errors---saving the times isn't that important
+
+# Remove additional arguments (anything after --).
+additional_args = []
+
+for i in range(len(sys.argv)):
+  if sys.argv[i] == '--':
+    additional_args = sys.argv[i+1:]
+    sys.argv = sys.argv[:i]
+    break
+
+parser = optparse.OptionParser(
+    usage = 'usage: %prog [options] binary [binary ...] -- [additional args]')
+
+parser.add_option('-d', '--output_dir', type='string',
+                  default=os.path.join(tempfile.gettempdir(), "gtest-parallel"),
+                  help='output directory for test logs')
+parser.add_option('-r', '--repeat', type='int', default=1,
+                  help='repeat tests')
+parser.add_option('--failed', action='store_true', default=False,
+                  help='run only failed and new tests')
+parser.add_option('-w', '--workers', type='int',
+                  default=multiprocessing.cpu_count(),
+                  help='number of workers to spawn')
+parser.add_option('--gtest_color', type='string', default='yes',
+                  help='color output')
+parser.add_option('--gtest_filter', type='string', default='',
+                  help='test filter')
+parser.add_option('--gtest_also_run_disabled_tests', action='store_true',
+                  default=False, help='run disabled tests too')
+parser.add_option('--format', type='string', default='filter',
+                  help='output format (raw,filter)')
+parser.add_option('--print_test_times', action='store_true', default=False,
+                  help='When done, list the run time of each test')
+
+(options, binaries) = parser.parse_args()
+
+if binaries == []:
+  parser.print_usage()
+  sys.exit(1)
+
+logger = RawFormat()
+if options.format == 'raw':
+  pass
+elif options.format == 'filter':
+  logger = FilterFormat()
+else:
+  sys.exit("Unknown output format: " + options.format)
+
+# Find tests.
+save_file = os.path.join(os.path.expanduser("~"), ".gtest-parallel-times")
+times = TestTimes(save_file)
+tests = []
+for test_binary in binaries:
+  command = [test_binary]
+  if options.gtest_also_run_disabled_tests:
+    command += ['--gtest_also_run_disabled_tests']
+
+  list_command = list(command)
+  if options.gtest_filter != '':
+    list_command += ['--gtest_filter=' + options.gtest_filter]
+
+  try:
+    test_list = subprocess.Popen(list_command + ['--gtest_list_tests'],
+                                 stderr=subprocess.PIPE).communicate()[1]
+  except OSError as e:
+    sys.exit("%s: %s" % (test_binary, str(e)))
+
+  command += additional_args
+
+  test_group = ''
+  for line in test_list.split('\n'):
+    if not line.strip():
+      continue
+    if line[0] != " ":
+      # Remove comments for typed tests and strip whitespace.
+      test_group = line.split('#')[0].strip()
+      continue
+    # Remove comments for parameterized tests and strip whitespace.
+    line = line.split('#')[0].strip()
+    if not line:
+      continue
+
+    test = test_group + line
+    if not options.gtest_also_run_disabled_tests and 'DISABLED_' in test:
+      continue
+    tests.append((times.get_test_time(test_binary, test),
+                  test_binary, test, command))
+
+if options.failed:
+  # The first element of each entry is the runtime of the most recent
+  # run if it was successful, or None if the test is new or the most
+  # recent run failed.
+  tests = [x for x in tests if x[0] is None]
+
+# Sort tests by falling runtime (with None, which is what we get for
+# new and failing tests, being considered larger than any real
+# runtime).
+tests.sort(reverse=True, key=lambda x: ((1 if x[0] is None else 0), x))
+
+# Repeat tests (-r flag).
+tests *= options.repeat
+test_lock = threading.Lock()
+job_id = 0
+logger.log(str(-1) + ': TESTCNT ' + ' ' + str(len(tests)))
+
+exit_code = 0
+
+# Create directory for test log output.
+try:
+  os.makedirs(options.output_dir)
+except OSError as e:
+  # Ignore errors if this directory already exists.
+  if e.errno != errno.EEXIST or not os.path.isdir(options.output_dir):
+    raise e
+# Remove files from old test runs.
+for logfile in os.listdir(options.output_dir):
+  os.remove(os.path.join(options.output_dir, logfile))
+
+# Run the specified job. Return the elapsed time in milliseconds if
+# the job succeeds, or None if the job fails. (This ensures that
+# failing tests will run first the next time.)
+def run_job((command, job_id, test)):
+  begin = time.time()
+
+  with tempfile.NamedTemporaryFile(dir=options.output_dir, delete=False) as log:
+    sub = subprocess.Popen(command + ['--gtest_filter=' + test] +
+                             ['--gtest_color=' + options.gtest_color],
+                           stdout=log.file,
+                           stderr=log.file)
+    try:
+      code = sigint_handler.wait(sub)
+    except sigint_handler.ProcessWasInterrupted:
+      thread.exit()
+    runtime_ms = int(1000 * (time.time() - begin))
+    logger.logfile(job_id, log.name)
+
+  logger.log("%s: EXIT %s %d" % (job_id, code, runtime_ms))
+  if code == 0:
+    return runtime_ms
+  global exit_code
+  exit_code = code
+  return None
+
+def worker():
+  global job_id
+  while True:
+    job = None
+    test_lock.acquire()
+    if job_id < len(tests):
+      (_, test_binary, test, command) = tests[job_id]
+      logger.log(str(job_id) + ': TEST ' + test_binary + ' ' + test)
+      job = (command, job_id, test)
+    job_id += 1
+    test_lock.release()
+    if job is None:
+      return
+    times.record_test_time(test_binary, test, run_job(job))
+
+def start_daemon(func):
+  t = threading.Thread(target=func)
+  t.daemon = True
+  t.start()
+  return t
+
+workers = [start_daemon(worker) for i in range(options.workers)]
+
+[t.join() for t in workers]
+logger.end()
+times.write_to_file(save_file)
+if options.print_test_times:
+  ts = sorted((times.get_test_time(test_binary, test), test_binary, test)
+              for (_, test_binary, test, _) in tests
+              if times.get_test_time(test_binary, test) is not None)
+  for (time_ms, test_binary, test) in ts:
+    print "%8s %s" % ("%dms" % time_ms, test)
+sys.exit(-signal.SIGINT if sigint_handler.got_sigint() else exit_code)
diff --git a/src/testing/gtest-parallel/patches/stderr_out.patch b/src/testing/gtest-parallel/patches/stderr_out.patch
new file mode 100644
index 0000000..ddaf9df
--- /dev/null
+++ b/src/testing/gtest-parallel/patches/stderr_out.patch
@@ -0,0 +1,19 @@
+commit 0dec4f46db1b072591cb6703c68a2ebb0279026d
+Author: Navreet Gill <navreetgill@google.com>
+Date:   Wed Aug 24 11:32:47 2016 -0700
+
+    test
+
+diff --git a/gtest-parallel b/gtest-parallel
+index 4e80928..a258a87 100755
+--- a/gtest-parallel
++++ b/gtest-parallel
+@@ -296,7 +296,7 @@ for test_binary in binaries:
+ 
+   try:
+     test_list = subprocess.Popen(list_command + ['--gtest_list_tests'],
+-                                 stdout=subprocess.PIPE).communicate()[0]
++                                 stderr=subprocess.PIPE).communicate()[1]
+   except OSError as e:
+     sys.exit("%s: %s" % (test_binary, str(e)))
+ 
diff --git a/src/testing/gtest/codereview.settings b/src/testing/gtest/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/testing/gtest/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/WebKit/codereview.settings b/src/third_party/WebKit/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/WebKit/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/angle/codereview.settings b/src/third_party/angle/codereview.settings
deleted file mode 100644
index 1295fd9..0000000
--- a/src/third_party/angle/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.

-GERRIT_HOST: lbshell-internal-review.googlesource.com

-GERRIT_AUTODETECT_BRANCH: true

-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com

diff --git a/src/third_party/dlmalloc/codereview.settings b/src/third_party/dlmalloc/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/dlmalloc/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/freetype2/codereview.settings b/src/third_party/freetype2/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/freetype2/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/icu/codereview.settings b/src/third_party/icu/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/icu/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/libvpx/codereview.settings b/src/third_party/libvpx/codereview.settings
deleted file mode 100644
index d7c8d39..0000000
--- a/src/third_party/libvpx/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: chromium-review.googlesource.com
-GERRIT_PORT: 29418
-CODE_REVIEW_SERVER: chromium-review.googlesource.com
diff --git a/src/third_party/mozjs/codereview.settings b/src/third_party/mozjs/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/mozjs/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/mozjs/js/src/assembler/wtf/Platform.h b/src/third_party/mozjs/js/src/assembler/wtf/Platform.h
index 2e440e3..05b1155 100644
--- a/src/third_party/mozjs/js/src/assembler/wtf/Platform.h
+++ b/src/third_party/mozjs/js/src/assembler/wtf/Platform.h
@@ -1033,14 +1033,6 @@
 #define ENABLE_REPAINT_THROTTLING 0
 #endif
 
-#if defined(WTF_OS_STARBOARD)
-#if SB_CAN(MAP_EXECUTABLE_MEMORY)
-#define ENABLE_JIT 1
-#else
-#define ENABLE_JIT 0
-#endif
-#endif
-
 /* Disable the JIT on versions of GCC prior to 4.1 */
 #if !defined(ENABLE_JIT) && WTF_COMPILER_GCC && !GCC_VERSION_AT_LEAST(4, 1, 0)
 #define ENABLE_JIT 0
@@ -1050,7 +1042,7 @@
 #if !defined(ENABLE_JIT) \
     && (WTF_CPU_X86 || WTF_CPU_X86_64 || WTF_CPU_ARM || WTF_CPU_SPARC32 || WTF_CPU_MIPS) \
     && (WTF_OS_DARWIN || !WTF_COMPILER_GCC || GCC_VERSION_AT_LEAST(4, 1, 0)) \
-    && !WTF_OS_WINCE
+    && !WTF_OS_WINCE && !defined(WTF_OS_STARBOARD)
 #define ENABLE_JIT 1
 #endif
 
diff --git a/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp b/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp
index 294a955..ab8ea02 100644
--- a/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp
+++ b/src/third_party/mozjs/js/src/jit/CodeGenerator.cpp
@@ -715,6 +715,12 @@
 }
 
 bool
+CodeGenerator::visitMop(LMop *lir)
+{
+    return true;
+}
+
+bool
 CodeGenerator::visitOsiPoint(LOsiPoint *lir)
 {
     // Note: markOsiPoint ensures enough space exists between the last
@@ -4254,6 +4260,13 @@
             masm.add32(Imm32(min), temp);
             if (!bailoutIf(Assembler::Overflow, lir->snapshot()))
                 return false;
+        }
+
+        masm.cmp32(temp, Imm32(0));
+        if (!bailoutIf(Assembler::LessThan, lir->snapshot()))
+            return false;
+
+        if (min != 0) {
             int32_t diff;
             if (SafeSub(max, min, &diff))
                 max = diff;
@@ -4261,9 +4274,6 @@
                 masm.sub32(Imm32(min), temp);
         }
 
-        masm.cmp32(temp, Imm32(0));
-        if (!bailoutIf(Assembler::LessThan, lir->snapshot()))
-            return false;
     }
 
     // Compute the maximum possible index. No overflow check is needed when
diff --git a/src/third_party/mozjs/js/src/jit/CodeGenerator.h b/src/third_party/mozjs/js/src/jit/CodeGenerator.h
index 873d7f2..94854d4 100644
--- a/src/third_party/mozjs/js/src/jit/CodeGenerator.h
+++ b/src/third_party/mozjs/js/src/jit/CodeGenerator.h
@@ -51,6 +51,7 @@
 
     bool visitLabel(LLabel *lir);
     bool visitNop(LNop *lir);
+    bool visitMop(LMop *lir);
     bool visitOsiPoint(LOsiPoint *lir);
     bool visitGoto(LGoto *lir);
     bool visitTableSwitch(LTableSwitch *ins);
diff --git a/src/third_party/mozjs/js/src/jit/IonCaches.cpp b/src/third_party/mozjs/js/src/jit/IonCaches.cpp
index 30d3711..f833d0f 100644
--- a/src/third_party/mozjs/js/src/jit/IonCaches.cpp
+++ b/src/third_party/mozjs/js/src/jit/IonCaches.cpp
@@ -2522,6 +2522,9 @@
     cache.getScriptedLocation(&script, &pc);
     RootedValue lval(cx, ObjectValue(*obj));
 
+    // Override the return value if the script is invalidated (bug 728188).
+    AutoDetectInvalidation adi(cx, res.address(), ion);
+
     if (cache.isDisabled()) {
         if (!GetElementOperation(cx, JSOp(*pc), &lval, idval, res))
             return false;
@@ -2529,9 +2532,7 @@
         return true;
     }
 
-    // Override the return value if we are invalidated (bug 728188).
-    AutoFlushCache afc ("GetElementCache");
-    AutoDetectInvalidation adi(cx, res.address(), ion);
+    AutoFlushCache afc("GetElementCache");
 
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, idval, &id))
diff --git a/src/third_party/mozjs/js/src/jit/LIR-Common.h b/src/third_party/mozjs/js/src/jit/LIR-Common.h
index 5a87e04..fb43cfc 100644
--- a/src/third_party/mozjs/js/src/jit/LIR-Common.h
+++ b/src/third_party/mozjs/js/src/jit/LIR-Common.h
@@ -46,6 +46,12 @@
     LIR_HEADER(Nop)
 };
 
+class LMop : public LInstructionHelper<0, 0, 0>
+{
+  public:
+    LIR_HEADER(Mop)
+};
+
 // An LOsiPoint captures a snapshot after a call and ensures enough space to
 // patch in a call to the invalidation mechanism.
 //
diff --git a/src/third_party/mozjs/js/src/jit/LOpcodes.h b/src/third_party/mozjs/js/src/jit/LOpcodes.h
index 1520829..dfbd53a 100644
--- a/src/third_party/mozjs/js/src/jit/LOpcodes.h
+++ b/src/third_party/mozjs/js/src/jit/LOpcodes.h
@@ -10,6 +10,7 @@
 #define LIR_COMMON_OPCODE_LIST(_)   \
     _(Label)                        \
     _(Nop)                          \
+    _(Mop)                          \
     _(OsiPoint)                     \
     _(MoveGroup)                    \
     _(Integer)                      \
diff --git a/src/third_party/mozjs/js/src/jit/Lowering.cpp b/src/third_party/mozjs/js/src/jit/Lowering.cpp
index fd1dc57..19e7425 100644
--- a/src/third_party/mozjs/js/src/jit/Lowering.cpp
+++ b/src/third_party/mozjs/js/src/jit/Lowering.cpp
@@ -2836,13 +2836,25 @@
     ins->setInWorklistUnchecked();
 #endif
 
+    // If we added a Nop for this instruction, we'll also add a Mop, so that
+    // that live-ranges for fixed register defs, which with LSRA extend through
+    // the Nop so that they can extend through the OsiPoint don't, with their
+    // one-extra extension, extend into a position where they use the input
+    // move group for the following instruction.
+    bool needsMop = !current->instructions().empty() && current->rbegin()->isNop();
+
     // If no safepoint was created, there's no need for an OSI point.
     if (LOsiPoint *osiPoint = popOsiPoint()) {
         if (!add(osiPoint))
             return false;
     }
 
-    return true;
+    if (needsMop) {
+        if (!add(new LMop()))
+            return false;
+    }
+
+     return true;
 }
 
 bool
diff --git a/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp b/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp
index fd68f91..c8cbc20 100644
--- a/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp
+++ b/src/third_party/mozjs/js/src/jit/RangeAnalysis.cpp
@@ -339,7 +339,9 @@
     // Instead, we should use it to eliminate the dead block.
     // (Bug 765127)
     if (r->upper_ < r->lower_) {
-        *emptyRange = true;
+        // If both ranges can be NaN, the result can still be NaN.
+        if (!lhs->isInfinite() || !rhs->isInfinite())
+            *emptyRange = true;
         r->makeRangeInfinite();
     }
 
diff --git a/src/third_party/mozjs/js/src/jit/arm/MacroAssembler-arm.h b/src/third_party/mozjs/js/src/jit/arm/MacroAssembler-arm.h
index 04d68af..c46883a 100644
--- a/src/third_party/mozjs/js/src/jit/arm/MacroAssembler-arm.h
+++ b/src/third_party/mozjs/js/src/jit/arm/MacroAssembler-arm.h
@@ -763,8 +763,9 @@
         if (lhs.getTag() == Operand::OP2) {
             branch32(cond, lhs.toReg(), rhs, label);
         } else {
-            ma_ldr(lhs, ScratchRegister);
-            branch32(cond, ScratchRegister, rhs, label);
+          // branch32 will use ScratchRegister.
+          ma_ldr(lhs, secondScratchReg_);
+          branch32(cond, secondScratchReg_, rhs, label);
         }
     }
     void branch32(Condition cond, const Address &lhs, Register rhs, Label *label) {
@@ -772,8 +773,9 @@
         branch32(cond, ScratchRegister, rhs, label);
     }
     void branch32(Condition cond, const Address &lhs, Imm32 rhs, Label *label) {
-        load32(lhs, ScratchRegister);
-        branch32(cond, ScratchRegister, rhs, label);
+      // branch32 will use ScratchRegister.
+      load32(lhs, secondScratchReg_);
+      branch32(cond, secondScratchReg_, rhs, label);
     }
     void branchPtr(Condition cond, const Address &lhs, Register rhs, Label *label) {
         branch32(cond, lhs, rhs, label);
@@ -856,8 +858,9 @@
         ma_b(label, cond);
     }
     void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) {
-        ma_ldr(Operand(address.base, address.offset), ScratchRegister);
-        branchTest32(cond, ScratchRegister, imm, label);
+      // branchTest32 will use ScratchRegister.
+      load32(address, secondScratchReg_);
+      branchTest32(cond, secondScratchReg_, imm, label);
     }
     void branchTestPtr(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
         branchTest32(cond, lhs, rhs, label);
diff --git a/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h b/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
index ec0886c..eed3ffd 100644
--- a/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/src/third_party/mozjs/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -216,8 +216,6 @@
         isBranch[idx >> 3] |= 1 << (idx & 0x7);
     }
     bool isNextBranch() {
-        if (this->nodeSize == InstBaseSize)
-            return false;
         int idx = this->nodeSize / InstBaseSize;
         return (isBranch[idx >> 3] >> (idx & 0x7)) & 1;
     }
diff --git a/src/third_party/mozjs/js/src/jsbool.cpp b/src/third_party/mozjs/js/src/jsbool.cpp
index 3b97d25..1df3511 100644
--- a/src/third_party/mozjs/js/src/jsbool.cpp
+++ b/src/third_party/mozjs/js/src/jsbool.cpp
@@ -200,7 +200,8 @@
 bool
 js::BooleanGetPrimitiveValueSlow(HandleObject wrappedBool, JSContext *cx)
 {
-    JSObject *obj = GetProxyTargetObject(wrappedBool);
-    JS_ASSERT(obj);
+    JSObject *obj = CheckedUnwrap(wrappedBool);
+    if (!obj || !obj->is<BooleanObject>())
+        return false;
     return obj->as<BooleanObject>().unbox();
 }
diff --git a/src/third_party/mozjs/js/src/jsobj.cpp b/src/third_party/mozjs/js/src/jsobj.cpp
index d922358..c8fc252 100644
--- a/src/third_party/mozjs/js/src/jsobj.cpp
+++ b/src/third_party/mozjs/js/src/jsobj.cpp
@@ -279,11 +279,18 @@
     if (pobj->isNative()) {
         desc->attrs = GetShapeAttributes(shape);
         if (desc->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
+            MOZ_ASSERT(desc.isShared());
             doGet = false;
             if (desc->attrs & JSPROP_GETTER)
                 desc->getter = CastAsPropertyOp(shape->getterObject());
             if (desc->attrs & JSPROP_SETTER)
                 desc->setter = CastAsStrictPropertyOp(shape->setterObject());
+        } else {
+             // This is either a straight-up data property or (rarely) a
+             // property with a JSPropertyOp getter/setter. The latter must be
+             // reported to the caller as a plain data property, so don't
+             // populate desc.getter/setter, and mask away the SHARED bit.
+             desc->attrs &= ~JSPROP_SHARED;
         }
     } else {
         if (!JSObject::getGenericAttributes(cx, pobj, id, &desc->attrs))
@@ -5337,4 +5344,3 @@
 #endif
     }
 }
-
diff --git a/src/third_party/mozjs/js/src/jsproxy.cpp b/src/third_party/mozjs/js/src/jsproxy.cpp
index 2dbad14..eddf34f 100644
--- a/src/third_party/mozjs/js/src/jsproxy.cpp
+++ b/src/third_party/mozjs/js/src/jsproxy.cpp
@@ -2328,7 +2328,9 @@
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
     if (!policy.allowed())
         return policy.returnValue();
-    return handler->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
+    bool ok = handler->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
+    MOZ_ASSERT_IF(ok && desc.isShared(), desc.hasGetterOrSetterObject());
+    return ok;
 }
 
 bool
diff --git a/src/third_party/mozjs/mozjs.gyp b/src/third_party/mozjs/mozjs.gyp
index c3ed096..c646032 100644
--- a/src/third_party/mozjs/mozjs.gyp
+++ b/src/third_party/mozjs/mozjs.gyp
@@ -17,10 +17,11 @@
   ],
   'variables': {
     'common_jit_defines': [
+      'ENABLE_JIT=1',
+      'ENABLE_YARR_JIT=1',
       'JS_ION=1',
       'JS_METHODJIT=1',
       'JS_METHODJIT_TYPED_ARRAY=1',
-      'ENABLE_YARR_JIT=1',
     ],
   },
   'target_defaults': {
@@ -47,20 +48,22 @@
         'defines': [
           'JS_CPU_X64=1',
           'JS_PUNBOX64=1',
-          '<@(common_jit_defines)',
         ],
       }],
       [ 'target_arch == "x86"', {
         'defines': [
           'JS_CPU_X86=1',
           'JS_NUNBOX32=1',
-          '<@(common_jit_defines)',
         ],
       }],
       [ 'target_arch == "arm"', {
         'defines': [
           'JS_CPU_ARM=1',
           'JS_NUNBOX32=1',
+        ],
+      }],
+      [ 'cobalt_enable_jit == 1', {
+        'defines': [
           '<@(common_jit_defines)',
         ],
       }],
@@ -98,7 +101,7 @@
         'js-confdefs.h',
       ],
       'conditions': [
-        [ 'target_arch == "x64"', {
+        [ 'target_arch == "x64" and cobalt_enable_jit == 1', {
           'sources': [
             'js/src/assembler/assembler/MacroAssemblerX86Common.cpp',
             'js/src/jit/shared/Assembler-x86-shared.cpp',
@@ -119,7 +122,7 @@
             '<@(mozjs_jit_sources)',
           ],
         }],
-        [ 'target_arch == "x86"', {
+        [ 'target_arch == "x86" and cobalt_enable_jit == 1', {
           'sources': [
             'js/src/assembler/assembler/MacroAssemblerX86Common.cpp',
             'js/src/jit/shared/Assembler-x86-shared.cpp',
@@ -140,7 +143,7 @@
             '<@(mozjs_jit_sources)',
           ],
         }],
-        [ 'target_arch == "arm"', {
+        [ 'target_arch == "arm" and cobalt_enable_jit == 1', {
           'sources': [
             'js/src/assembler/assembler/ARMAssembler.cpp',
             'js/src/assembler/assembler/MacroAssemblerARM.cpp',
diff --git a/src/third_party/openssl/README.chromium b/src/third_party/openssl/README.chromium
index fbae0aa..6c8889b 100644
--- a/src/third_party/openssl/README.chromium
+++ b/src/third_party/openssl/README.chromium
@@ -1,6 +1,6 @@
 Name: openssl
 URL: http://openssl.org/source/
-Version: 1.0.1c
+Version: 1.0.1p
 License: BSDish
 License File: openssl/LICENSE
 License Android Compatible: yes
diff --git a/src/third_party/openssl/codereview.settings b/src/third_party/openssl/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/openssl/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/third_party/ots/codereview.settings b/src/third_party/ots/codereview.settings
deleted file mode 100644
index acbc431..0000000
--- a/src/third_party/ots/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
\ No newline at end of file
diff --git a/src/third_party/ots/include/opentype-sanitiser.h b/src/third_party/ots/include/opentype-sanitiser.h
index fc76b90..1380ac7 100644
--- a/src/third_party/ots/include/opentype-sanitiser.h
+++ b/src/third_party/ots/include/opentype-sanitiser.h
@@ -82,8 +82,10 @@
     }
 
     while (length >= 4) {
-      chksum_ += ntohl(*reinterpret_cast<const uint32_t*>(
-          reinterpret_cast<const uint8_t*>(data) + offset));
+      uint32_t tmp;
+      std::memcpy(&tmp, reinterpret_cast<const uint8_t *>(data) + offset,
+        sizeof(uint32_t));
+      chksum_ += ntohl(tmp);
       length -= 4;
       offset += 4;
     }
diff --git a/src/third_party/skia/codereview.settings b/src/third_party/skia/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/third_party/skia/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com
diff --git a/src/tools/gyp/codereview.settings b/src/tools/gyp/codereview.settings
deleted file mode 100644
index a4b341a..0000000
--- a/src/tools/gyp/codereview.settings
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is used by gcl to get repository specific information.
-GERRIT_HOST: lbshell-internal-review.googlesource.com
-GERRIT_AUTODETECT_BRANCH: true
-CODE_REVIEW_SERVER: lbshell-internal-review.googlesource.com