Import 2.10943 2016-09-14
diff --git a/src/cobalt/audio/audio_device.cc b/src/cobalt/audio/audio_device.cc
index 5f8d205..74d4c2d 100644
--- a/src/cobalt/audio/audio_device.cc
+++ b/src/cobalt/audio/audio_device.cc
@@ -66,8 +66,11 @@
 
 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]";
+  if (!(-1.0 <= sample && sample <= 1.0)) {
+    DLOG(WARNING) <<
+      "Sample of type float32 must lie on interval [-1.0, 1.0], got: " <<
+      sample << ".";
+  }
   return static_cast<int16>(sample * kMaxInt16AsFloat32);
 }
 
diff --git a/src/cobalt/base/address_sanitizer.h b/src/cobalt/base/address_sanitizer.h
new file mode 100644
index 0000000..e443cc9
--- /dev/null
+++ b/src/cobalt/base/address_sanitizer.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_BASE_ADDRESS_SANITIZER_H_
+#define COBALT_BASE_ADDRESS_SANITIZER_H_
+
+namespace base {
+
+// ASAN requires much larger stack sizes.  The value |kAsanAdditionalStackSize|
+// can be added to thread stack sizes if stack overflow issues are encountered
+// due to ASAN being active.
+#if defined(ADDRESS_SANITIZER)
+const size_t kAsanAdditionalStackSize = 4 * 1024 * 1024;
+#else
+const size_t kAsanAdditionalStackSize = 0;
+#endif  // defined(ADDRESS_SANITIZER)
+
+}  // namespace base
+
+#endif  // COBALT_BASE_ADDRESS_SANITIZER_H_
diff --git a/src/cobalt/base/base.gyp b/src/cobalt/base/base.gyp
index 6dc3864..a2f0dda 100644
--- a/src/cobalt/base/base.gyp
+++ b/src/cobalt/base/base.gyp
@@ -21,6 +21,7 @@
       'product_name': 'cobalt_base',
       'type': 'static_library',
       'sources': [
+        'address_sanitizer.h',
         'clock.h',
         'cobalt_paths.h',
         'compiler.h',
diff --git a/src/cobalt/bindings/generated/jsc/testing/JSCGarbageCollectionTestInterface.cc b/src/cobalt/bindings/generated/jsc/testing/JSCGarbageCollectionTestInterface.cc
new file mode 100644
index 0000000..1be5fcd
--- /dev/null
+++ b/src/cobalt/bindings/generated/jsc/testing/JSCGarbageCollectionTestInterface.cc
@@ -0,0 +1,706 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY!
+// Auto-generated from template: bindings/javascriptcore/templates/interface.cc.template
+
+// clang-format off
+
+#include "third_party/WebKit/Source/JavaScriptCore/config.h"
+
+#include "JSCGarbageCollectionTestInterface.h"
+
+#include "base/debug/trace_event.h"
+#include "cobalt/base/polymorphic_downcast.h"
+#include "cobalt/script/global_object_proxy.h"
+#include "cobalt/script/opaque_handle.h"
+#include "cobalt/script/script_object.h"
+
+#include "cobalt/script/javascriptcore/constructor_base.h"
+#include "cobalt/script/javascriptcore/conversion_helpers.h"
+#include "cobalt/script/javascriptcore/prototype_base.h"
+#include "cobalt/script/javascriptcore/jsc_callback_function.h"
+#include "cobalt/script/javascriptcore/jsc_callback_interface_holder.h"
+#include "cobalt/script/javascriptcore/jsc_exception_state.h"
+#include "cobalt/script/javascriptcore/jsc_global_object.h"
+#include "cobalt/script/javascriptcore/jsc_global_object_proxy.h"
+#include "cobalt/script/javascriptcore/jsc_object_handle.h"
+#include "cobalt/script/javascriptcore/jsc_object_handle_holder.h"
+#include "cobalt/script/javascriptcore/type_traits.h"
+#include "cobalt/script/javascriptcore/util/binding_helpers.h"
+#include "cobalt/script/javascriptcore/util/exception_helpers.h"
+#include "third_party/WebKit/Source/JavaScriptCore/interpreter/Interpreter.h"
+#include "third_party/WebKit/Source/JavaScriptCore/runtime/Error.h"
+#include "third_party/WebKit/Source/JavaScriptCore/runtime/FunctionPrototype.h"
+#include "third_party/WebKit/Source/JavaScriptCore/runtime/Identifier.h"
+#include "third_party/WebKit/Source/JavaScriptCore/runtime/JSFunction.h"
+#include "third_party/WebKit/Source/JavaScriptCore/runtime/JSGlobalObject.h"
+#include "third_party/WebKit/Source/JavaScriptCore/runtime/ObjectPrototype.h"
+
+namespace {
+using cobalt::bindings::testing::GarbageCollectionTestInterface;
+using cobalt::bindings::testing::JSCGarbageCollectionTestInterface;
+using cobalt::script::CallbackInterfaceTraits;
+using cobalt::script::GlobalObjectProxy;
+using cobalt::script::OpaqueHandle;
+using cobalt::script::OpaqueHandleHolder;
+using cobalt::script::ScriptObject;
+using cobalt::script::Wrappable;
+
+using cobalt::script::javascriptcore::kConversionFlagNullable;
+using cobalt::script::javascriptcore::kConversionFlagRestricted;
+using cobalt::script::javascriptcore::kConversionFlagTreatNullAsEmptyString;
+using cobalt::script::javascriptcore::kConversionFlagTreatUndefinedAsEmptyString;
+using cobalt::script::javascriptcore::kNoConversionFlags;
+using cobalt::script::javascriptcore::ConstructorBase;
+using cobalt::script::javascriptcore::GetWrappableOrSetException;
+using cobalt::script::javascriptcore::FromJSValue;
+using cobalt::script::javascriptcore::FromWTFString;
+using cobalt::script::javascriptcore::JSCCallbackFunction;
+using cobalt::script::javascriptcore::JSCCallbackFunctionHolder;
+using cobalt::script::javascriptcore::JSCCallbackInterfaceHolder;
+using cobalt::script::javascriptcore::JSCEngine;
+using cobalt::script::javascriptcore::JSCExceptionState;
+using cobalt::script::javascriptcore::JSCObjectHandle;
+using cobalt::script::javascriptcore::JSCObjectHandleHolder;
+using cobalt::script::javascriptcore::JSCGlobalObject;
+using cobalt::script::javascriptcore::JSCGlobalObjectProxy;
+using cobalt::script::javascriptcore::JSObjectToWrappable;
+using cobalt::script::javascriptcore::ScriptObjectRegistry;
+using cobalt::script::javascriptcore::ToJSValue;
+using cobalt::script::javascriptcore::ToWTFString;
+using cobalt::script::javascriptcore::TypeTraits;
+using cobalt::script::javascriptcore::PrototypeBase;
+using cobalt::script::javascriptcore::ThreadLocalHashTable;
+using cobalt::script::javascriptcore::WrapperBase;
+using cobalt::script::javascriptcore::util::HasPropertyOnPrototype;
+using cobalt::script::javascriptcore::util::GetStackTrace;
+}  // namespace
+
+namespace cobalt {
+namespace bindings {
+namespace testing {
+
+namespace {
+JSC::EncodedJSValue constructorJSGarbageCollectionTestInterface(JSC::ExecState*);
+
+// These are declared unconditionally, but only defined if needed by the
+// interface.
+JSC::JSValue NamedPropertyGetter(JSC::ExecState* exec_state,
+    JSC::JSValue slot_base, JSC::PropertyName property_name);
+void NamedPropertySetter(JSC::JSCell* cell, JSC::ExecState* exec_state,
+    JSC::PropertyName property_name, JSC::JSValue jsc_value);
+bool NamedPropertyDeleter(JSC::JSCell* cell, JSC::ExecState* exec_state,
+    JSC::PropertyName property_name);
+bool QueryNamedProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
+    JSC::PropertyName property_name);
+JSC::JSValue OnGetMissingProperty(JSC::ExecState* exec_state,
+    JSC::JSValue slot_base, JSC::PropertyName property_name);
+bool OnSetMissingProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
+    JSC::PropertyName property_name, JSC::JSValue value);
+
+const bool s_has_named_getter = false;
+const bool s_has_named_setter = false;
+#if !defined(COBALT_BUILD_TYPE_GOLD)
+const bool s_use_debug_missing_property_handler = true;
+#else
+const bool s_use_debug_missing_property_handler = false;
+#endif
+}  // namespace
+
+// Class that defines a JS Object representing this interface's Interface Object
+// https://www.w3.org/TR/WebIDL/#interface-object
+class JSCGarbageCollectionTestInterface::InterfaceObject : public ConstructorBase {
+ public:
+  // Get the Interface Object. Will create a new Interface Object if necessary,
+  // otherwise it will return the cached one.
+  static JSC::JSObject* GetInstance(JSC::ExecState* exec);
+  DECLARE_CLASSINFO();
+
+  // Needed when JSC::OverridesGetOwnPropertySlot StructureFlag is set
+  // Must be public so that it can be accessible from getStaticValueSlot<>.
+  static bool getOwnPropertySlot(JSC::JSCell* cell, JSC::ExecState* exec,
+                                 JSC::PropertyName property_name,
+                                 JSC::PropertySlot& slot) {
+    InterfaceObject* this_object = JSC::jsCast<InterfaceObject*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(this_object, &s_info);
+
+    // Same process as JSC::getStaticPropertySlot<>, which is defined in Lookup.h
+    // Since JSFunction::getOwnPropertySlot is protected, we can't call it from
+    // the helper function.
+    const JSC::HashEntry* entry =
+        GetPropertyTable(exec)->entry(exec, property_name);
+
+    if (!entry) // not found, forward to parent
+      return Base::getOwnPropertySlot(this_object, exec, property_name, slot);
+
+    if (entry->attributes() & JSC::Function)
+        return setUpStaticFunctionSlot(exec, entry, this_object, property_name, slot);
+
+    slot.setCacheableCustom(this_object, entry->propertyGetter());
+    return true;
+  }
+
+  // static override. Needed to support setting a property.
+  static void put(JSC::JSCell* cell, JSC::ExecState* exec_state,
+                  JSC::PropertyName property_name, JSC::JSValue value,
+                  JSC::PutPropertySlot& slot) {
+    InterfaceObject* this_object = JSC::jsCast<InterfaceObject*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(this_object, &s_info);
+    bool found_property = JSC::lookupPut<InterfaceObject>(
+        exec_state, property_name, value, GetPropertyTable(exec_state),
+        this_object, slot.isStrictMode());
+    DLOG_IF(INFO, !found_property) << "Did not find property named " <<
+        WTF::String(property_name.publicName()).utf8().data() <<
+        " to set on interface object for JSCGarbageCollectionTestInterface";
+    if (!found_property) {
+      BaseClass::put(cell, exec_state, property_name, value, slot);
+    }
+  }
+
+  // static override. This prevents this object from being called as a normal
+  // function, throwing a TypeError if the user attempts to do so.
+  static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&) {
+    return JSC::CallTypeNone;
+  }
+
+
+ private:
+  typedef ConstructorBase BaseClass;
+
+  static const unsigned StructureFlags =
+      JSC::ImplementsHasInstance |
+      JSC::OverridesGetOwnPropertySlot |
+      BaseClass::StructureFlags;
+
+  InterfaceObject(JSC::ExecState* exec_state, JSC::JSGlobalObject* global_object, JSC::Structure* structure)
+      : BaseClass(exec_state, global_object, structure) { }
+  void finishCreation(JSC::ExecState* exec_state,
+                      JSC::NativeExecutable* native_executable, int length,
+                      const String& name);
+
+  static const JSC::HashTable* GetPropertyTable(JSC::ExecState* exec_state);
+
+  static const JSC::HashTableValue property_table_values[];
+  static const JSC::HashTable property_table_prototype;
+};
+
+const JSC::HashTableValue JSCGarbageCollectionTestInterface::InterfaceObject::property_table_values[] = {
+    // static functions will also go here.
+    { 0, 0, 0, 0, static_cast<JSC::Intrinsic>(0) }
+};  // JSCGarbageCollectionTestInterface::InterfaceObject::property_table_values
+
+// static
+const JSC::HashTable
+JSCGarbageCollectionTestInterface::InterfaceObject::property_table_prototype = {
+    // Sizes will be calculated based on the number of static functions as well.
+    2,  // compactSize
+    1,  // compactSizeMask
+    property_table_values,
+    NULL  // table allocated at runtime
+};  // JSCGarbageCollectionTestInterface::InterfaceObject::property_table_prototype
+
+// static
+const JSC::HashTable*
+JSCGarbageCollectionTestInterface::InterfaceObject::GetPropertyTable(
+    JSC::ExecState* exec_state) {
+  return ThreadLocalHashTable::GetInstance()->GetHashTable(
+      JSCGarbageCollectionTestInterface::InterfaceObject::s_classinfo(),
+      property_table_prototype);
+}
+
+const JSC::ClassInfo JSCGarbageCollectionTestInterface::InterfaceObject::s_info = {
+    "GarbageCollectionTestInterfaceConstructor",  // className
+    BaseClass::s_classinfo(),  // parentClass
+    NULL,  // static hash-table of properties (not used)
+    GetPropertyTable,  // function pointer to get hash-table of properties
+    CREATE_METHOD_TABLE(JSCGarbageCollectionTestInterface::InterfaceObject)
+};  // JSCGarbageCollectionTestInterface::InterfaceObject::s_info
+
+void JSCGarbageCollectionTestInterface::InterfaceObject::finishCreation(
+    JSC::ExecState* exec_state, JSC::NativeExecutable* native_executable,
+    int length, const String& name) {
+  BaseClass::finishCreation(exec_state, native_executable, length, name);
+  ASSERT(inherits(&s_info));
+  // Add a 'prototype' property whose value is the prototype object.
+  putDirect(exec_state->globalData(),
+            exec_state->propertyNames().prototype,
+            JSCGarbageCollectionTestInterface::GetPrototype(exec_state->lexicalGlobalObject()),
+            JSC::DontDelete | JSC::ReadOnly | JSC::DontEnum);
+  DCHECK(hasOwnProperty(exec_state, JSC::Identifier(exec_state, "prototype")));
+}
+
+// static
+JSC::JSObject* JSCGarbageCollectionTestInterface::InterfaceObject::GetInstance(
+    JSC::ExecState* exec_state) {
+  JSCGlobalObject* global_object =
+      static_cast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
+  ASSERT_GC_OBJECT_INHERITS(global_object, JSCGlobalObject::s_classinfo());
+
+  // Try to get the cached interface object, and create a new one if needed.
+  JSC::JSObject* interface_object = global_object->object_cache()->GetCachedConstructor(&s_info);
+  if (interface_object == NULL) {
+    JSC::JSGlobalData& global_data = global_object->globalData();
+    JSC::JSObject* parent_prototype = global_object->functionPrototype();
+    JSC::TypeInfo type_info(JSC::ObjectType, StructureFlags);
+    JSC::Structure* structure = JSC::Structure::create(
+        global_data,
+        global_object,
+        JSC::JSValue(parent_prototype),
+        type_info,
+        &s_info);
+
+    const int kNumArguments = 0;
+    JSC::NativeExecutable* executable = global_data.getHostFunction(NULL, &constructorJSGarbageCollectionTestInterface);
+
+    // Create the new interface object.
+    InterfaceObject* new_interface_object =
+        new (NotNull, JSC::allocateCell<InterfaceObject>(global_data.heap))
+        InterfaceObject(exec_state, global_object, structure);
+    new_interface_object->finishCreation(exec_state, executable, kNumArguments, "GarbageCollectionTestInterface");
+    // Add the interface object to the cache.
+    global_object->object_cache()->CacheConstructor(&s_info, new_interface_object);
+    interface_object = new_interface_object;
+  }
+  DCHECK_EQ(global_object->object_cache()->GetCachedConstructor(&s_info), interface_object);
+  return interface_object;
+}
+
+// End of JSCGarbageCollectionTestInterface::InterfaceObject class
+
+// Class that defines a JS Object representing this interface's prototype
+class JSCGarbageCollectionTestInterface::Prototype : public PrototypeBase {
+ public:
+  // Get the prototype. Will create a new prototype if necessary, otherwise it
+  // will return a cached prototype.
+  static JSC::JSObject* GetInstance(JSC::JSGlobalObject* global_object);
+  DECLARE_CLASSINFO();
+
+  // Needed when JSC::OverridesGetOwnPropertySlot StructureFlag is set
+  // Must be public so that it can be accessible from getStaticValueSlot<>.
+  static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*,
+                                 JSC::PropertyName,
+                                 JSC::PropertySlot&);
+
+ private:
+  typedef PrototypeBase BaseClass;
+
+  static const unsigned StructureFlags =
+      JSC::OverridesGetOwnPropertySlot |
+      BaseClass::StructureFlags;
+
+  Prototype(JSC::JSGlobalObject* global_object, JSC::Structure* structure)
+      : BaseClass(global_object, structure) { }
+
+  static JSC::JSValue GetConstructor(JSC::ExecState* exec_state,
+      JSC::JSValue slot_base,
+      JSC::PropertyName property_name);
+  static const JSC::HashTable* GetPropertyTable(JSC::ExecState* exec_state);
+
+  static const JSC::HashTableValue property_table_values[];
+  static const JSC::HashTable property_table_prototype;
+};
+
+const JSC::HashTableValue JSCGarbageCollectionTestInterface::Prototype::property_table_values[] = {
+    { "constructor",
+        JSC::DontDelete | JSC::DontEnum,
+        reinterpret_cast<intptr_t>(JSCGarbageCollectionTestInterface::Prototype::GetConstructor),
+        static_cast<intptr_t>(0),
+        JSC::NoIntrinsic
+    },
+    { 0, 0, 0, 0, static_cast<JSC::Intrinsic>(0) }
+};  // JSCGarbageCollectionTestInterface::Prototype::property_table_values
+
+// static
+const JSC::HashTable JSCGarbageCollectionTestInterface::Prototype::property_table_prototype = {
+    4,  // compactSize
+    3,  // compactSizeMask
+    property_table_values,
+    NULL  // table allocated at runtime
+};  // JSCGarbageCollectionTestInterface::Prototype::property_table_prototype
+
+// static
+const JSC::HashTable* JSCGarbageCollectionTestInterface::Prototype::GetPropertyTable(
+    JSC::ExecState* exec_state) {
+  return ThreadLocalHashTable::GetInstance()->GetHashTable(
+      JSCGarbageCollectionTestInterface::Prototype::s_classinfo(), property_table_prototype);
+}
+
+const JSC::ClassInfo JSCGarbageCollectionTestInterface::Prototype::s_info = {
+    "GarbageCollectionTestInterfacePrototype",  // className
+    BaseClass::s_classinfo(),  // parentClass
+    NULL,  // static hash-table of properties (not used)
+    GetPropertyTable,  // function pointer to get hash-table of properties
+    CREATE_METHOD_TABLE(JSCGarbageCollectionTestInterface::Prototype)
+};  // JSCGarbageCollectionTestInterface::Prototype::s_info
+
+// Look up property slot for querying property values.
+bool JSCGarbageCollectionTestInterface::Prototype::getOwnPropertySlot(JSC::JSCell* cell,
+    JSC::ExecState* exec, JSC::PropertyName property_name,
+    JSC::PropertySlot& slot) {
+  Prototype* this_object = JSC::jsCast<Prototype*>(cell);
+  ASSERT_GC_OBJECT_INHERITS(this_object, &s_info);
+  return JSC::getStaticPropertySlot<Prototype, JSC::JSObject>(
+      exec, GetPropertyTable(exec), this_object, property_name, slot);
+}
+
+// static
+JSC::JSObject* JSCGarbageCollectionTestInterface::Prototype::GetInstance(
+    JSC::JSGlobalObject* base_global_object) {
+  JSCGlobalObject* global_object =
+      static_cast<JSCGlobalObject*>(base_global_object);
+  ASSERT_GC_OBJECT_INHERITS(global_object, JSCGlobalObject::s_classinfo());
+
+  // Try to get the cached prototype, and create a new one if needed.
+  JSC::JSObject* prototype = global_object->object_cache()->GetCachedPrototype(&s_info);
+  if (prototype == NULL) {
+    JSC::JSGlobalData& global_data = global_object->globalData();
+    JSC::JSLockHolder lock(&global_data);
+
+    JSC::JSObject* parent_prototype = global_object->objectPrototype();
+    JSC::TypeInfo type_info(JSC::ObjectType, StructureFlags);
+    JSC::Structure* structure = JSC::Structure::create(
+        global_data,
+        global_object,
+        JSC::JSValue(parent_prototype),
+        type_info,
+        &s_info);
+
+    // Create the new prototype object.
+    Prototype* new_prototype =
+        new (NotNull, JSC::allocateCell<Prototype>(
+            global_data.heap))
+        Prototype(global_object, structure);
+    new_prototype->finishCreation(global_data);
+    // Add the prototype to the cache.
+    global_object->object_cache()->CachePrototype(&s_info, new_prototype);
+    prototype = new_prototype;
+  }
+  DCHECK_EQ(global_object->object_cache()->GetCachedPrototype(&s_info), prototype);
+  return prototype;
+}
+
+// End of JSCGarbageCollectionTestInterface::Prototype class
+
+const JSC::HashTableValue JSCGarbageCollectionTestInterface::property_table_values[] = {
+    { 0, 0, 0, 0, static_cast<JSC::Intrinsic>(0) }
+};  // JSCGarbageCollectionTestInterface::property_table_values
+
+// static
+const JSC::HashTable JSCGarbageCollectionTestInterface::property_table_prototype = {
+    2,  // compactSize
+    1,  // compactSizeMask
+    property_table_values,
+    NULL  // table allocated at runtime
+};  // JSCGarbageCollectionTestInterface::property_table_prototype
+
+// static
+const JSC::HashTable* JSCGarbageCollectionTestInterface::GetPropertyTable(
+    JSC::ExecState* exec_state) {
+  return ThreadLocalHashTable::GetInstance()->GetHashTable(
+      JSCGarbageCollectionTestInterface::s_classinfo(), property_table_prototype);
+}
+
+#ifdef __LB_SHELL__FORCE_LOGGING__
+base::LazyInstance<JSCGarbageCollectionTestInterface::NonTrivialStaticFields>
+    JSCGarbageCollectionTestInterface::non_trivial_static_fields = LAZY_INSTANCE_INITIALIZER;
+#endif  // __LB_SHELL__FORCE_LOGGING__
+
+const JSC::ClassInfo JSCGarbageCollectionTestInterface::s_info = {
+    "GarbageCollectionTestInterface",  // className
+    BaseClass::s_classinfo(),  // parentClass
+    NULL,  // static hash-table of properties (not used)
+    GetPropertyTable,  // function pointer to get hash-table of properties
+    CREATE_METHOD_TABLE(JSCGarbageCollectionTestInterface)
+};  // JSCGarbageCollectionTestInterface::s_info
+
+// static
+JSC::JSObject* JSCGarbageCollectionTestInterface::GetPrototype(
+    JSC::JSGlobalObject* global_object) {
+  return Prototype::GetInstance(global_object);
+}
+
+// static
+JSC::JSObject* JSCGarbageCollectionTestInterface::GetConstructor(
+    JSC::ExecState* exec_state) {
+  return InterfaceObject::GetInstance(exec_state);
+}
+
+// static
+JSC::JSValue JSCGarbageCollectionTestInterface::Prototype::GetConstructor(
+      JSC::ExecState* exec_state,
+      JSC::JSValue slot_base,
+      JSC::PropertyName property_name) {
+  return JSC::JSValue(InterfaceObject::GetInstance(exec_state));
+}
+
+// static
+JSC::JSObject* JSCGarbageCollectionTestInterface::Create(
+    JSCGlobalObject* global_object,
+    const scoped_refptr<Wrappable>& wrappable) {
+  if (!(wrappable->GetWrappableType() == GarbageCollectionTestInterface::GarbageCollectionTestInterfaceWrappableType())) {
+    NOTREACHED() << "Type of wrappable does not match GarbageCollectionTestInterface::GarbageCollectionTestInterfaceWrappableType()";
+    return NULL;
+  }
+  GarbageCollectionTestInterface* impl_ptr =
+      base::polymorphic_downcast<GarbageCollectionTestInterface*>(wrappable.get());
+
+  JSC::JSGlobalData& global_data = global_object->globalData();
+
+  // Get or Create the prototype object for this interface.
+  JSC::JSObject* prototype = Prototype::GetInstance(global_object);
+  DCHECK(prototype);
+
+  JSC::JSLockHolder lock(global_data);
+  // Create a JSC::Structure object for this instance.
+  JSC::TypeInfo type_info(JSC::ObjectType, StructureFlags);
+  JSC::Structure* structure = JSC::Structure::create(
+      global_data,
+      global_object,
+      JSC::JSValue(prototype),
+      type_info,
+      &s_info);
+
+  // Instantiate a new garbage-collected wrapper object.
+  JSCGarbageCollectionTestInterface* wrapper =
+      new (NotNull, JSC::allocateCell<JSCGarbageCollectionTestInterface>(global_data.heap))
+      JSCGarbageCollectionTestInterface(
+          &global_data,
+          structure,
+          global_object->script_object_registry(),
+          make_scoped_refptr(impl_ptr));
+  wrapper->finishCreation(global_data);
+  return wrapper;
+}
+JSCGarbageCollectionTestInterface::JSCGarbageCollectionTestInterface(
+    JSC::JSGlobalData* global_data,
+    JSC::Structure* structure,
+    ScriptObjectRegistry* script_object_registry,
+    const scoped_refptr<GarbageCollectionTestInterface>& impl)
+    : BaseClass(global_data, structure, script_object_registry, impl) {
+}
+
+void JSCGarbageCollectionTestInterface::finishCreation(JSC::JSGlobalData& global_data) {
+  BaseClass::finishCreation(global_data);
+  DCHECK(inherits(&s_info));
+}
+
+JSCGarbageCollectionTestInterface::~JSCGarbageCollectionTestInterface() {
+  // Empty destructor
+}
+
+// Look up property slot for querying property values.
+bool JSCGarbageCollectionTestInterface::getOwnPropertySlot(JSC::JSCell* cell,
+    JSC::ExecState* exec, JSC::PropertyName property_name,
+    JSC::PropertySlot& slot) {
+  JSCGarbageCollectionTestInterface* this_object = JSC::jsCast<JSCGarbageCollectionTestInterface*>(cell);
+  ASSERT_GC_OBJECT_INHERITS(this_object, &s_info);
+  bool found_property_slot = JSC::getStaticValueSlot<JSCGarbageCollectionTestInterface, BaseClass>(
+      exec, GetPropertyTable(exec), this_object, property_name, slot);
+  if (s_has_named_getter || s_use_debug_missing_property_handler) {
+    bool found_property_on_prototype_chain = false;
+    if (!found_property_slot && cell->isObject()) {
+      JSC::JSValue prototype_value = JSC::asObject(cell)->prototype();
+      if (prototype_value.isObject()) {
+        JSC::JSObject* prototype = JSC::asObject(prototype_value);
+        found_property_on_prototype_chain =
+            prototype->hasProperty(exec, property_name);
+      }
+    }
+    if (s_has_named_getter) {
+      if (!found_property_slot && !found_property_on_prototype_chain) {
+        if (QueryNamedProperty(this_object, exec, property_name)) {
+          slot.setCustom(cell, &NamedPropertyGetter);
+          found_property_slot = true;
+        }
+      }
+    }
+    if (s_use_debug_missing_property_handler) {
+      // The property was not found as an own-property, nor was it found on the
+      // prototype chain, so set the missing property handler to be called
+      // when getting this property value.
+      if (!found_property_slot && !found_property_on_prototype_chain) {
+        slot.setCustom(cell, &OnGetMissingProperty);
+        found_property_slot = true;
+      }
+    }
+  }
+  return found_property_slot;
+}
+
+// Look up property slot and put the |value|.
+void JSCGarbageCollectionTestInterface::put(JSC::JSCell* cell, JSC::ExecState* exec,
+    JSC::PropertyName property_name, JSC::JSValue value,
+    JSC::PutPropertySlot& slot) {
+  JSCGarbageCollectionTestInterface* this_object = JSC::jsCast<JSCGarbageCollectionTestInterface*>(cell);
+  ASSERT_GC_OBJECT_INHERITS(this_object, &s_info);
+  bool property_handled = false;
+  if (s_has_named_setter || s_use_debug_missing_property_handler) {
+    // Need to look up the property manually.
+    bool has_property = HasOwnPropertyOrPrototypeProperty(
+        cell, exec, property_name);
+
+    if (s_has_named_setter) {
+      // We didn't find the property on the object or prototype chain, so
+      // set or create a new named property.
+      if (!has_property) {
+        std::string property_name_utf8 = FromWTFString(property_name.publicName());
+        NamedPropertySetter(cell, exec, property_name, value);
+        property_handled = true;
+      }
+    }
+    if (s_use_debug_missing_property_handler) {
+      if (!has_property && !property_handled) {
+        property_handled = OnSetMissingProperty(cell, exec, property_name, value);
+      }
+    }
+#ifdef __LB_SHELL__FORCE_LOGGING__
+    std::string property_name_utf8 = FromWTFString(property_name.publicName());
+
+    base::AutoLock lock(non_trivial_static_fields.Get().lock_);
+    base::hash_set<std::string>& properties_warned_about =
+        non_trivial_static_fields.Get().properties_warned_about;
+
+    if (properties_warned_about.find(property_name_utf8) ==
+        properties_warned_about.end()) {
+      properties_warned_about.insert(property_name_utf8);
+      WTF::String class_name = cell->className();
+      DLOG_IF(WARNING, !has_property) << "Did not find property named " <<
+              property_name_utf8 << " to set on wrapper for "
+              << FromWTFString(class_name)
+              << std::endl << StackTraceToString(GetStackTrace(exec, 32))
+              << std::endl;
+    }
+#endif  // __LB_SHELL__FORCE_LOGGING__
+  }
+
+  if (!property_handled) {
+    JSC::lookupPut<JSCGarbageCollectionTestInterface, BaseClass>(
+        exec, property_name, value, GetPropertyTable(exec), this_object, slot);
+  }
+}
+
+bool JSCGarbageCollectionTestInterface::HasOwnPropertyOrPrototypeProperty(
+    JSC::JSCell* cell, JSC::ExecState* exec_state,
+    JSC::PropertyName property_name) {
+  JSCGarbageCollectionTestInterface* this_object = JSC::jsCast<JSCGarbageCollectionTestInterface*>(cell);
+  JSC::PropertySlot lookup_slot;
+  bool has_property = JSC::getStaticPropertySlot<JSCGarbageCollectionTestInterface, BaseClass>(
+      exec_state, GetPropertyTable(exec_state), this_object, property_name,
+      lookup_slot);
+  return has_property || HasPropertyOnPrototype(exec_state, cell, property_name);
+}
+
+namespace {
+
+JSC::EncodedJSValue constructorJSGarbageCollectionTestInterface(JSC::ExecState* exec_state) {
+  JSCGlobalObject* global_object =
+      JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
+  JSCExceptionState exception_state(global_object);
+    scoped_refptr<GarbageCollectionTestInterface> new_object =
+        new GarbageCollectionTestInterface();
+    return JSC::JSValue::encode(ToJSValue(global_object, new_object));
+
+}
+JSC::JSValue NamedPropertyGetter(JSC::ExecState* exec_state,
+    JSC::JSValue slot_base, JSC::PropertyName property_name) {
+  NOTREACHED();
+  return JSC::jsUndefined();
+}
+bool QueryNamedProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
+    JSC::PropertyName property_name) {
+  NOTREACHED();
+  return false;
+}
+void NamedPropertySetter(JSC::JSCell* cell, JSC::ExecState* exec_state,
+    JSC::PropertyName property_name, JSC::JSValue jsc_value) {
+  NOTREACHED();
+}
+
+bool NamedPropertyDeleter(JSC::JSCell* cell, JSC::ExecState* exec_state,
+    JSC::PropertyName property_name) {
+  return false;
+}
+
+#if !defined(COBALT_BUILD_TYPE_GOLD)
+JSC::JSValue OnGetMissingProperty(JSC::ExecState* exec_state,
+    JSC::JSValue slot_base, JSC::PropertyName property_name) {
+  JSCGlobalObject* global_object =
+      JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
+  JSC::JSValue callable = global_object->get(
+      exec_state, JSC::Identifier(exec_state, "__onGetMissingProperty"));
+  if (!callable.isUndefined()) {
+    JSC::CallData call_data;
+    JSC::CallType call_type = JSC::getCallData(callable, call_data);
+    if (call_type != JSC::CallTypeNone) {
+      // The function called __onGetMissingProperty exists, so call this and
+      // return the result as the value for this property.
+      JSC::MarkedArgumentBuffer args;
+      args.append(slot_base);
+      args.append(JSC::JSValue(
+              JSC::JSString::create(
+                  global_object->globalData(), property_name.publicName())));
+      JSC::JSValue retval = JSC::call(
+          exec_state, callable, call_type, call_data, global_object, args);
+      return retval;
+    }
+  }
+  return JSC::jsUndefined();
+}
+
+bool OnSetMissingProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
+    JSC::PropertyName property_name, JSC::JSValue value) {
+  JSCGlobalObject* global_object =
+      JSC::jsCast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
+  JSC::JSValue callable = global_object->get(
+      exec_state, JSC::Identifier(exec_state, "__onSetMissingProperty"));
+  if (!callable.isUndefined()) {
+    JSC::CallData call_data;
+    JSC::CallType call_type = JSC::getCallData(callable, call_data);
+    if (call_type != JSC::CallTypeNone) {
+      // The function called __onSetMissingProperty exists, so call this with
+      // the value to be set. The missing property handler returns true if it
+      // has handled the setting of this property.
+      JSC::MarkedArgumentBuffer args;
+      args.append(cell);
+      args.append(JSC::JSValue(
+              JSC::JSString::create(
+                  global_object->globalData(), property_name.publicName())));
+      args.append(value);
+      JSC::JSValue retval = JSC::call(
+          exec_state, callable, call_type, call_data, global_object, args);
+      return retval.toBoolean(exec_state);
+    }
+  }
+  return false;
+}
+#else
+JSC::JSValue OnGetMissingProperty(JSC::ExecState* exec_state,
+    JSC::JSValue slot_base, JSC::PropertyName property_name) {
+  NOTREACHED();
+  return JSC::jsUndefined();
+}
+bool OnSetMissingProperty(JSC::JSCell* cell, JSC::ExecState* exec_state,
+    JSC::PropertyName property_name, JSC::JSValue value) {
+  NOTREACHED();
+  return false;
+}
+#endif
+}  // namespace
+
+}  // namespace testing
+}  // namespace bindings
+}  // namespace cobalt
diff --git a/src/cobalt/bindings/generated/jsc/testing/JSCGarbageCollectionTestInterface.h b/src/cobalt/bindings/generated/jsc/testing/JSCGarbageCollectionTestInterface.h
new file mode 100644
index 0000000..96ab43e
--- /dev/null
+++ b/src/cobalt/bindings/generated/jsc/testing/JSCGarbageCollectionTestInterface.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.
+ */
+
+// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY!
+// Auto-generated from template: bindings/javascriptcore/templates/interface.h.template
+
+// clang-format off
+
+#ifndef JSCGarbageCollectionTestInterface_h
+#define JSCGarbageCollectionTestInterface_h
+
+#include "base/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+#include "cobalt/base/polymorphic_downcast.h"
+#include "cobalt/script/wrappable.h"
+#include "cobalt/bindings/testing/garbage_collection_test_interface.h"
+
+#include "base/threading/thread_local_storage.h"
+#include "cobalt/script/javascriptcore/jsc_global_object.h"
+#include "cobalt/script/javascriptcore/script_object_registry.h"
+#include "cobalt/script/javascriptcore/thread_local_hash_table.h"
+#include "cobalt/script/javascriptcore/wrapper_base.h"
+#include "cobalt/script/javascriptcore/wrapper_factory.h"
+#include "third_party/WebKit/Source/JavaScriptCore/config.h"
+#include "third_party/WebKit/Source/JavaScriptCore/runtime/ClassInfo.h"
+#include "third_party/WebKit/Source/JavaScriptCore/runtime/JSObject.h"
+#include "third_party/WebKit/Source/JavaScriptCore/runtime/Lookup.h"
+
+namespace cobalt {
+namespace bindings {
+namespace testing {
+
+class JSCGarbageCollectionTestInterface
+    : public script::javascriptcore::InterfaceBase {
+  typedef script::javascriptcore::InterfaceBase BaseClass;
+ public:
+
+  // Get the prototype object for this wrapper class.
+  static JSC::JSObject* GetPrototype(JSC::JSGlobalObject* global_object);
+
+  // Get the interface object for this wrapper class.
+  static JSC::JSObject* GetConstructor(JSC::ExecState* exec_state);
+
+  // JavaScriptCore functions and members
+
+  DECLARE_CLASSINFO();
+
+  // Needed when JSC::OverridesGetOwnPropertySlot StructureFlag is set
+  // Must be public so that it can be accessible from getStaticValueSlot<>.
+  static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*,
+                                 JSC::PropertyName,
+                                 JSC::PropertySlot&);
+
+  // static override. Needed to support setting a property.
+  static void put(JSC::JSCell*, JSC::ExecState*, JSC::PropertyName,
+                  JSC::JSValue, JSC::PutPropertySlot&);
+
+  // static override. This function will be called after a new object has
+  // been created.
+  void finishCreation(JSC::JSGlobalData& global_data);
+
+  static script::javascriptcore::WrapperFactory::CreateWrapperFunction
+      GetCreateWrapperFunction() {
+    return base::Bind(&Create);
+  }
+
+ private:
+  // Create a new wrapper for |wrappable|, which will be cast to GarbageCollectionTestInterface.
+  static JSC::JSObject* Create(
+      script::javascriptcore::JSCGlobalObject* global_object,
+      const scoped_refptr<script::Wrappable>& wrappable);
+
+ protected:
+
+  static const unsigned StructureFlags =
+      JSC::OverridesGetOwnPropertySlot |
+      BaseClass::StructureFlags;
+
+  JSCGarbageCollectionTestInterface(
+      JSC::JSGlobalData* global_data,
+      JSC::Structure* structure,
+      script::javascriptcore::ScriptObjectRegistry* script_object_registry,
+      const scoped_refptr<GarbageCollectionTestInterface>& impl);
+  ~JSCGarbageCollectionTestInterface();
+
+ private:
+  class InterfaceObject;
+  class Prototype;
+
+  static const JSC::HashTableValue property_table_values[];
+  static const JSC::HashTable property_table_prototype;
+  static base::LazyInstance<
+      cobalt::script::javascriptcore::ThreadLocalHashTable>
+          thread_local_property_table;
+
+  static const JSC::HashTable* GetPropertyTable(JSC::ExecState* exec_state);
+
+  static bool HasOwnPropertyOrPrototypeProperty(JSC::JSCell* cell,
+      JSC::ExecState* exec_state, JSC::PropertyName property_name);
+
+#ifdef __LB_SHELL__FORCE_LOGGING__
+  struct NonTrivialStaticFields {
+    // TODO: Only log attempts of usage of unsupported Web APIs.
+    base::hash_set<std::string> properties_warned_about;
+    base::Lock lock_;
+  };
+  static base::LazyInstance<NonTrivialStaticFields> non_trivial_static_fields;
+#endif  // __LB_SHELL__FORCE_LOGGING__
+};
+
+}  // namespace bindings
+}  // namespace testing
+}  // namespace cobalt
+
+#endif  // JSCGarbageCollectionTestInterface_h
diff --git a/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc b/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc
index 1fb9cf2..45c9bf3 100644
--- a/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc
+++ b/src/cobalt/bindings/generated/jsc/testing/JSCWindow.cc
@@ -48,6 +48,7 @@
 #include "JSCExceptionObjectInterface.h"
 #include "JSCExceptionsInterface.h"
 #include "JSCExtendedIDLAttributesInterface.h"
+#include "JSCGarbageCollectionTestInterface.h"
 #include "JSCGetOpaqueRootInterface.h"
 #include "JSCGlobalInterfaceParent.h"
 #include "JSCImplementedInterface.h"
@@ -92,6 +93,7 @@
 #include "cobalt/bindings/testing/exception_object_interface.h"
 #include "cobalt/bindings/testing/exceptions_interface.h"
 #include "cobalt/bindings/testing/extended_idl_attributes_interface.h"
+#include "cobalt/bindings/testing/garbage_collection_test_interface.h"
 #include "cobalt/bindings/testing/get_opaque_root_interface.h"
 #include "cobalt/bindings/testing/global_interface_parent.h"
 #include "cobalt/bindings/testing/implemented_interface.h"
@@ -165,6 +167,7 @@
 using cobalt::bindings::testing::ExceptionObjectInterface;
 using cobalt::bindings::testing::ExceptionsInterface;
 using cobalt::bindings::testing::ExtendedIDLAttributesInterface;
+using cobalt::bindings::testing::GarbageCollectionTestInterface;
 using cobalt::bindings::testing::GetOpaqueRootInterface;
 using cobalt::bindings::testing::GlobalInterfaceParent;
 using cobalt::bindings::testing::ImplementedInterface;
@@ -194,6 +197,7 @@
 using cobalt::bindings::testing::JSCExceptionObjectInterface;
 using cobalt::bindings::testing::JSCExceptionsInterface;
 using cobalt::bindings::testing::JSCExtendedIDLAttributesInterface;
+using cobalt::bindings::testing::JSCGarbageCollectionTestInterface;
 using cobalt::bindings::testing::JSCGetOpaqueRootInterface;
 using cobalt::bindings::testing::JSCGlobalInterfaceParent;
 using cobalt::bindings::testing::JSCImplementedInterface;
@@ -770,6 +774,10 @@
       JSCExtendedIDLAttributesInterface::s_classinfo(),
       JSCExtendedIDLAttributesInterface::GetCreateWrapperFunction());
   wrapper_factory->RegisterWrappableType(
+      GarbageCollectionTestInterface::GarbageCollectionTestInterfaceWrappableType(),
+      JSCGarbageCollectionTestInterface::s_classinfo(),
+      JSCGarbageCollectionTestInterface::GetCreateWrapperFunction());
+  wrapper_factory->RegisterWrappableType(
       GetOpaqueRootInterface::GetOpaqueRootInterfaceWrappableType(),
       JSCGetOpaqueRootInterface::s_classinfo(),
       JSCGetOpaqueRootInterface::GetCreateWrapperFunction());
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
index e0895ab..190790f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsBooleanTypeTestInterface.cc
@@ -254,8 +254,7 @@
       wrapper_private->wrappable<BooleanTypeTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
index 90f8065..60f4a71 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackFunctionInterface.cc
@@ -302,8 +302,7 @@
       wrapper_private->wrappable<CallbackFunctionInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -349,8 +348,7 @@
       wrapper_private->wrappable<CallbackFunctionInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -396,8 +394,7 @@
       wrapper_private->wrappable<CallbackFunctionInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -443,8 +440,7 @@
       wrapper_private->wrappable<CallbackFunctionInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -490,8 +486,7 @@
       wrapper_private->wrappable<CallbackFunctionInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
index 7f68bd2..a827b91 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsCallbackInterfaceInterface.cc
@@ -258,8 +258,7 @@
       wrapper_private->wrappable<CallbackInterfaceInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
index 1ce35d8..4a0d825 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorInterface.cc
@@ -389,8 +389,7 @@
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -443,8 +442,7 @@
   // http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
   // 4. If S is empty, then throw a TypeError.
   MozjsExceptionState exception_state(context);
-  exception_state.SetSimpleException(
-      script::ExceptionState::kTypeError, "Invalid number of arguments.");
+  exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
   return false;
 }
 }  // namespace
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
index fcb47c4..c10d31d 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsConstructorWithArgumentsInterface.cc
@@ -457,8 +457,7 @@
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   const size_t kMinArguments = 2;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
index eda9b8c..0831779 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsDerivedGetterSetterInterface.cc
@@ -458,8 +458,7 @@
       wrapper_private->wrappable<DerivedGetterSetterInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -511,8 +510,7 @@
       wrapper_private->wrappable<DerivedGetterSetterInterface>().get();
   const size_t kMinArguments = 2;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
index f9cf774..6810f89 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsEnumerationInterface.cc
@@ -496,9 +496,7 @@
     *out_enum = EnumerationInterface::kGamma;
   } else {
     // 2. If S is not one of E's enumeration values, then throw a TypeError.
-    exception_state->
-        SetSimpleException(ExceptionState::kTypeError,
-                           "Cannot convert JavaScript value to Enum.");
+    exception_state->SetSimpleException(cobalt::script::kConvertToEnumFailed);
     return;
   }
 }
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc
new file mode 100644
index 0000000..98eff0f
--- /dev/null
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY!
+// Auto-generated from template: bindings/mozjs/templates/interface.cc.template
+
+// clang-format off
+
+#include "MozjsGarbageCollectionTestInterface.h"
+
+#include "base/debug/trace_event.h"
+#include "cobalt/base/polymorphic_downcast.h"
+#include "cobalt/script/global_object_proxy.h"
+#include "cobalt/script/opaque_handle.h"
+#include "cobalt/script/script_object.h"
+
+#include "base/lazy_instance.h"
+#include "cobalt/script/mozjs/callback_function_conversion.h"
+#include "cobalt/script/exception_state.h"
+#include "cobalt/script/mozjs/conversion_helpers.h"
+#include "cobalt/script/mozjs/mozjs_exception_state.h"
+#include "cobalt/script/mozjs/mozjs_callback_function.h"
+#include "cobalt/script/mozjs/mozjs_global_object_proxy.h"
+#include "cobalt/script/mozjs/mozjs_object_handle.h"
+#include "cobalt/script/mozjs/mozjs_property_enumerator.h"
+#include "cobalt/script/mozjs/mozjs_user_object_holder.h"
+#include "cobalt/script/mozjs/proxy_handler.h"
+#include "cobalt/script/mozjs/type_traits.h"
+#include "cobalt/script/mozjs/wrapper_factory.h"
+#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/jsfriendapi.h"
+
+namespace {
+using cobalt::bindings::testing::GarbageCollectionTestInterface;
+using cobalt::bindings::testing::MozjsGarbageCollectionTestInterface;
+using cobalt::script::CallbackInterfaceTraits;
+using cobalt::script::GlobalObjectProxy;
+using cobalt::script::OpaqueHandle;
+using cobalt::script::OpaqueHandleHolder;
+using cobalt::script::ScriptObject;
+using cobalt::script::Wrappable;
+
+using cobalt::script::CallbackFunction;
+using cobalt::script::CallbackInterfaceTraits;
+using cobalt::script::ExceptionState;
+using cobalt::script::mozjs::FromJSValue;
+using cobalt::script::mozjs::kConversionFlagNullable;
+using cobalt::script::mozjs::kConversionFlagRestricted;
+using cobalt::script::mozjs::kConversionFlagTreatNullAsEmptyString;
+using cobalt::script::mozjs::kConversionFlagTreatUndefinedAsEmptyString;
+using cobalt::script::mozjs::kNoConversionFlags;
+using cobalt::script::mozjs::InterfaceData;
+using cobalt::script::mozjs::MozjsCallbackFunction;
+using cobalt::script::mozjs::MozjsExceptionState;
+using cobalt::script::mozjs::MozjsGlobalObjectProxy;
+using cobalt::script::mozjs::MozjsUserObjectHolder;
+using cobalt::script::mozjs::MozjsPropertyEnumerator;
+using cobalt::script::mozjs::ProxyHandler;
+using cobalt::script::mozjs::ToJSValue;
+using cobalt::script::mozjs::TypeTraits;
+using cobalt::script::mozjs::WrapperPrivate;
+using cobalt::script::mozjs::WrapperFactory;
+using cobalt::script::Wrappable;
+}  // namespace
+
+namespace cobalt {
+namespace bindings {
+namespace testing {
+
+namespace {
+
+class MozjsGarbageCollectionTestInterfaceHandler : public ProxyHandler {
+ public:
+  MozjsGarbageCollectionTestInterfaceHandler()
+      : ProxyHandler(indexed_property_hooks, named_property_hooks) {}
+
+ private:
+  static NamedPropertyHooks named_property_hooks;
+  static IndexedPropertyHooks indexed_property_hooks;
+};
+
+ProxyHandler::NamedPropertyHooks
+MozjsGarbageCollectionTestInterfaceHandler::named_property_hooks = {
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
+ProxyHandler::IndexedPropertyHooks
+MozjsGarbageCollectionTestInterfaceHandler::indexed_property_hooks = {
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+};
+
+static base::LazyInstance<MozjsGarbageCollectionTestInterfaceHandler>
+    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, MozjsGarbageCollectionTestInterface::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();
+  memset(&interface_data->instance_class_definition, 0,
+         sizeof(interface_data->instance_class_definition));
+  memset(&interface_data->prototype_class_definition, 0,
+         sizeof(interface_data->prototype_class_definition));
+  memset(&interface_data->interface_object_class_definition, 0,
+         sizeof(interface_data->interface_object_class_definition));
+
+  JSClass* instance_class = &interface_data->instance_class_definition;
+  const int kGlobalFlags = 0;
+  instance_class->name = "GarbageCollectionTestInterface";
+  instance_class->flags = kGlobalFlags | JSCLASS_HAS_PRIVATE;
+  instance_class->addProperty = JS_PropertyStub;
+  instance_class->delProperty = JS_DeletePropertyStub;
+  instance_class->getProperty = JS_PropertyStub;
+  instance_class->setProperty = JS_StrictPropertyStub;
+  instance_class->enumerate = JS_EnumerateStub;
+  instance_class->resolve = JS_ResolveStub;
+  instance_class->convert = JS_ConvertStub;
+  // Function to be called before on object of this class is garbage collected.
+  instance_class->finalize = &WrapperPrivate::Finalizer;
+  // Called to trace objects that can be referenced from this object.
+  instance_class->trace = &WrapperPrivate::Trace;
+
+  JSClass* prototype_class = &interface_data->prototype_class_definition;
+  prototype_class->name = "GarbageCollectionTestInterfacePrototype";
+  prototype_class->flags = 0;
+  prototype_class->addProperty = JS_PropertyStub;
+  prototype_class->delProperty = JS_DeletePropertyStub;
+  prototype_class->getProperty = JS_PropertyStub;
+  prototype_class->setProperty = JS_StrictPropertyStub;
+  prototype_class->enumerate = JS_EnumerateStub;
+  prototype_class->resolve = JS_ResolveStub;
+  prototype_class->convert = JS_ConvertStub;
+
+  JSClass* interface_object_class =
+      &interface_data->interface_object_class_definition;
+  interface_object_class->name = "GarbageCollectionTestInterfaceConstructor";
+  interface_object_class->flags = 0;
+  interface_object_class->addProperty = JS_PropertyStub;
+  interface_object_class->delProperty = JS_DeletePropertyStub;
+  interface_object_class->getProperty = JS_PropertyStub;
+  interface_object_class->setProperty = JS_StrictPropertyStub;
+  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;
+}
+
+
+const JSPropertySpec prototype_properties[] = {
+  JS_PS_END
+};
+
+const JSFunctionSpec prototype_functions[] = {
+  JS_FS_END
+};
+
+const JSPropertySpec interface_object_properties[] = {
+  JS_PS_END
+};
+
+const JSFunctionSpec interface_object_functions[] = {
+  JS_FS_END
+};
+
+const JSPropertySpec own_properties[] = {
+  JS_PS_END
+};
+
+void InitializePrototypeAndInterfaceObject(
+    InterfaceData* interface_data, JSContext* context,
+    JS::HandleObject global_object) {
+  DCHECK(!interface_data->prototype);
+  DCHECK(!interface_data->interface_object);
+  DCHECK(JS_IsGlobalObject(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);
+  bool success = JS_DefineProperties(
+      context, interface_data->prototype, prototype_properties);
+  DCHECK(success);
+  success = JS_DefineFunctions(
+      context, interface_data->prototype, prototype_functions);
+  DCHECK(success);
+
+  JS::RootedObject function_prototype(
+      context, JS_GetFunctionPrototype(context, global_object));
+  DCHECK(function_prototype);
+  // Create the Interface object.
+  interface_data->interface_object = JS_NewObjectWithGivenProto(
+      context, &interface_data->interface_object_class_definition,
+      function_prototype, NULL);
+
+  // Add the InterfaceObject.name property.
+  JS::RootedObject rooted_interface_object(
+      context, interface_data->interface_object);
+  JS::RootedValue name_value(context);
+  const char name[] =
+      "GarbageCollectionTestInterface";
+  name_value.setString(JS_NewStringCopyZ(context, name));
+  success =
+      JS_DefineProperty(context, rooted_interface_object, "name", name_value,
+                        JS_PropertyStub, JS_StrictPropertyStub,
+                        JSPROP_READONLY);
+  DCHECK(success);
+
+  // Add the InterfaceObject.length property. It is set to the length of the
+  // shortest argument list of all overload constructors.
+  JS::RootedValue length_value(context);
+  length_value.setInt32(0);
+  success =
+      JS_DefineProperty(context, rooted_interface_object, "length",
+                        length_value, JS_PropertyStub, JS_StrictPropertyStub,
+                        JSPROP_READONLY);
+  DCHECK(success);
+
+  // Define interface object properties (including constants).
+  success = JS_DefineProperties(context, rooted_interface_object,
+                                interface_object_properties);
+  DCHECK(success);
+  // Define interface object functions (static).
+  success = JS_DefineFunctions(context, rooted_interface_object,
+                               interface_object_functions);
+  DCHECK(success);
+
+
+  // Set the Prototype.constructor and Constructor.prototype properties.
+  DCHECK(interface_data->interface_object);
+  DCHECK(interface_data->prototype);
+  JS::RootedObject rooted_prototype(context, interface_data->prototype);
+  success = JS_LinkConstructorAndPrototype(
+      context,
+      rooted_interface_object,
+      rooted_prototype);
+  DCHECK(success);
+}
+
+InterfaceData* GetInterfaceData(JSContext* context) {
+  MozjsGlobalObjectProxy* global_object_proxy =
+      static_cast<MozjsGlobalObjectProxy*>(JS_GetContextPrivate(context));
+  // Use the address of the properties definition for this interface as a
+  // unique key for looking up the InterfaceData for this interface.
+  intptr_t key = reinterpret_cast<intptr_t>(&own_properties);
+  InterfaceData* interface_data = global_object_proxy->GetInterfaceData(key);
+  if (!interface_data) {
+    interface_data = CreateCachedInterfaceData();
+    DCHECK(interface_data);
+    global_object_proxy->CacheInterfaceData(key, interface_data);
+    DCHECK_EQ(interface_data, global_object_proxy->GetInterfaceData(key));
+  }
+  return interface_data;
+}
+
+}  // namespace
+
+// static
+JSObject* MozjsGarbageCollectionTestInterface::CreateProxy(
+    JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
+  DCHECK(global_object);
+
+  InterfaceData* interface_data = GetInterfaceData(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));
+  DCHECK(new_object);
+  JS::RootedObject proxy(context,
+      ProxyHandler::NewProxy(context, new_object, prototype, NULL,
+                             proxy_handler.Pointer()));
+  WrapperPrivate::AddPrivateData(context, proxy, wrappable);
+  return proxy;
+}
+
+//static
+const JSClass* MozjsGarbageCollectionTestInterface::PrototypeClass(
+      JSContext* context) {
+  DCHECK(MozjsGlobalObjectProxy::GetFromContext(context));
+  JS::RootedObject global_object(
+      context,
+      MozjsGlobalObjectProxy::GetFromContext(context)->global_object());
+  DCHECK(global_object);
+
+  JS::RootedObject prototype(context, GetPrototype(context, global_object));
+  JSClass* proto_class = JS_GetClass(*prototype.address());
+  return proto_class;
+}
+
+// static
+JSObject* MozjsGarbageCollectionTestInterface::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, global_object);
+  }
+  DCHECK(interface_data->prototype);
+  return interface_data->prototype;
+}
+
+// static
+JSObject* MozjsGarbageCollectionTestInterface::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, global_object);
+  }
+  DCHECK(interface_data->interface_object);
+  return interface_data->interface_object;
+}
+
+
+namespace {
+JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp) {
+  MozjsExceptionState exception_state(context);
+  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+
+  scoped_refptr<GarbageCollectionTestInterface> new_object =
+      new GarbageCollectionTestInterface();
+  JS::RootedValue result_value(context);
+  ToJSValue(context, new_object, &result_value);
+  DCHECK(result_value.isObject());
+  JS::RootedObject result_object(context, JSVAL_TO_OBJECT(result_value));
+  args.rval().setObject(*result_object);
+  return true;
+}
+}  // namespace
+
+
+}  // namespace testing
+}  // namespace bindings
+}  // namespace cobalt
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.h b/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.h
new file mode 100644
index 0000000..9cd73f4
--- /dev/null
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY!
+// Auto-generated from template: bindings/mozjs/templates/interface.h.template
+
+// clang-format off
+
+#ifndef MozjsGarbageCollectionTestInterface_h
+#define MozjsGarbageCollectionTestInterface_h
+
+#include "base/hash_tables.h"
+#include "base/lazy_instance.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+#include "cobalt/base/polymorphic_downcast.h"
+#include "cobalt/script/wrappable.h"
+#include "cobalt/bindings/testing/garbage_collection_test_interface.h"
+
+#include "third_party/mozjs/js/src/jsapi.h"
+
+namespace cobalt {
+namespace bindings {
+namespace testing {
+
+class MozjsGarbageCollectionTestInterface {
+ public:
+  static JSObject* CreateProxy(JSContext* context,
+      const scoped_refptr<script::Wrappable>& wrappable);
+  static const JSClass* PrototypeClass(JSContext* context);
+  static JSObject* GetPrototype(JSContext* context,
+                                JS::HandleObject global_object);
+  static JSObject* GetInterfaceObject(JSContext* context,
+                                      JS::HandleObject global_object);
+};
+
+}  // namespace bindings
+}  // namespace testing
+}  // namespace cobalt
+
+#endif  // MozjsGarbageCollectionTestInterface_h
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
index b950039..b998abc 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsIndexedGetterInterface.cc
@@ -338,8 +338,7 @@
       wrapper_private->wrappable<IndexedGetterInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -385,8 +384,7 @@
       wrapper_private->wrappable<IndexedGetterInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -438,8 +436,7 @@
       wrapper_private->wrappable<IndexedGetterInterface>().get();
   const size_t kMinArguments = 2;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
index f0e1c02..90f7900 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedGetterInterface.cc
@@ -316,8 +316,7 @@
       wrapper_private->wrappable<NamedGetterInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -363,8 +362,7 @@
       wrapper_private->wrappable<NamedGetterInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -416,8 +414,7 @@
       wrapper_private->wrappable<NamedGetterInterface>().get();
   const size_t kMinArguments = 2;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
index bca075c..da310df 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNamedIndexedGetterInterface.cc
@@ -458,8 +458,7 @@
       wrapper_private->wrappable<NamedIndexedGetterInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -511,8 +510,7 @@
       wrapper_private->wrappable<NamedIndexedGetterInterface>().get();
   const size_t kMinArguments = 2;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -570,8 +568,7 @@
       wrapper_private->wrappable<NamedIndexedGetterInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -623,8 +620,7 @@
       wrapper_private->wrappable<NamedIndexedGetterInterface>().get();
   const size_t kMinArguments = 2;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
index 5ac3c47..bd4bfc0 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNullableTypesTestInterface.cc
@@ -390,8 +390,7 @@
       wrapper_private->wrappable<NullableTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -471,8 +470,7 @@
       wrapper_private->wrappable<NullableTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -552,8 +550,7 @@
       wrapper_private->wrappable<NullableTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -633,8 +630,7 @@
       wrapper_private->wrappable<NullableTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
index 4c45a29..d686d2b 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsNumericTypesTestInterface.cc
@@ -650,8 +650,7 @@
       wrapper_private->wrappable<NumericTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -731,8 +730,7 @@
       wrapper_private->wrappable<NumericTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -812,8 +810,7 @@
       wrapper_private->wrappable<NumericTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -859,8 +856,7 @@
       wrapper_private->wrappable<NumericTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -974,8 +970,7 @@
       wrapper_private->wrappable<NumericTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -1055,8 +1050,7 @@
       wrapper_private->wrappable<NumericTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -1136,8 +1130,7 @@
       wrapper_private->wrappable<NumericTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -1217,8 +1210,7 @@
       wrapper_private->wrappable<NumericTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -1264,8 +1256,7 @@
       wrapper_private->wrappable<NumericTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -1379,8 +1370,7 @@
       wrapper_private->wrappable<NumericTypesTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
index 20a6a3c..aac9e9a 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsOperationsTestInterface.cc
@@ -326,8 +326,7 @@
       wrapper_private->wrappable<OperationsTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -511,8 +510,7 @@
       wrapper_private->wrappable<OperationsTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -558,8 +556,7 @@
       wrapper_private->wrappable<OperationsTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -605,8 +602,7 @@
       wrapper_private->wrappable<OperationsTestInterface>().get();
   const size_t kMinArguments = 3;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -676,8 +672,7 @@
       wrapper_private->wrappable<OperationsTestInterface>().get();
   const size_t kMinArguments = 3;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -781,8 +776,7 @@
   // http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
   // 4. If S is empty, then throw a TypeError.
   MozjsExceptionState exception_state(context);
-  exception_state.SetSimpleException(
-      script::ExceptionState::kTypeError, "Invalid number of arguments.");
+  exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
   return false;
 }
 
@@ -810,8 +804,7 @@
       wrapper_private->wrappable<OperationsTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -857,8 +850,7 @@
       wrapper_private->wrappable<OperationsTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -906,8 +898,7 @@
   // http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
   // 4. If S is empty, then throw a TypeError.
   MozjsExceptionState exception_state(context);
-  exception_state.SetSimpleException(
-      script::ExceptionState::kTypeError, "Invalid number of arguments.");
+  exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
   return false;
 }
 
@@ -1103,8 +1094,7 @@
       wrapper_private->wrappable<OperationsTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -1178,8 +1168,7 @@
       wrapper_private->wrappable<OperationsTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -1225,8 +1214,7 @@
       wrapper_private->wrappable<OperationsTestInterface>().get();
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -1256,8 +1244,7 @@
 
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -1287,8 +1274,7 @@
 
   const size_t kMinArguments = 2;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -1349,8 +1335,7 @@
   // http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
   // 4. If S is empty, then throw a TypeError.
   MozjsExceptionState exception_state(context);
-  exception_state.SetSimpleException(
-      script::ExceptionState::kTypeError, "Invalid number of arguments.");
+  exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
   return false;
 }
 
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
index 38b509c..aaf933d 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsSingleOperationInterface.cc
@@ -58,6 +58,7 @@
     bool* had_exception) const {
   bool success = false;
   base::optional<int32_t > cobalt_return_value;
+  JSExceptionState* previous_exception_state = JS_SaveExceptionState(context_);
 
   // This could be set to NULL if it was garbage collected.
   JS::RootedObject implementing_object(context_, implementing_object_.Get());
@@ -100,6 +101,7 @@
   }
 
   *had_exception = !success;
+  JS_RestoreExceptionState(context_, previous_exception_state);
   return cobalt_return_value;
 }
 
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
index fe8a2ad..e913609 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStaticPropertiesInterface.cc
@@ -245,8 +245,7 @@
 
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -276,8 +275,7 @@
 
   const size_t kMinArguments = 1;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -307,8 +305,7 @@
 
   const size_t kMinArguments = 3;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -362,8 +359,7 @@
 
   const size_t kMinArguments = 3;
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
   // Non-optional arguments
@@ -467,8 +463,7 @@
   // http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
   // 4. If S is empty, then throw a TypeError.
   MozjsExceptionState exception_state(context);
-  exception_state.SetSimpleException(
-      script::ExceptionState::kTypeError, "Invalid number of arguments.");
+  exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
   return false;
 }
 
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
index bf5fab5..0646f33 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAnonymousOperationInterface.cc
@@ -206,8 +206,7 @@
   StringifierAnonymousOperationInterface* impl =
       wrapper_private->wrappable<StringifierAnonymousOperationInterface>().get();
   if (!impl) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Stringifier problem.");
+    exception_state.SetSimpleException(cobalt::script::kStringifierProblem);
     NOTREACHED();
     return false;
   }
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
index e7ab56b..552e45b 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierAttributeInterface.cc
@@ -250,8 +250,7 @@
   StringifierAttributeInterface* impl =
       wrapper_private->wrappable<StringifierAttributeInterface>().get();
   if (!impl) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Stringifier problem.");
+    exception_state.SetSimpleException(cobalt::script::kStringifierProblem);
     NOTREACHED();
     return false;
   }
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
index 915226a..db390ad 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsStringifierOperationInterface.cc
@@ -240,8 +240,7 @@
   StringifierOperationInterface* impl =
       wrapper_private->wrappable<StringifierOperationInterface>().get();
   if (!impl) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Stringifier problem.");
+    exception_state.SetSimpleException(cobalt::script::kStringifierProblem);
     NOTREACHED();
     return false;
   }
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
index a2f79de..59ff86f 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsWindow.cc
@@ -46,6 +46,7 @@
 #include "MozjsExceptionObjectInterface.h"
 #include "MozjsExceptionsInterface.h"
 #include "MozjsExtendedIDLAttributesInterface.h"
+#include "MozjsGarbageCollectionTestInterface.h"
 #include "MozjsGetOpaqueRootInterface.h"
 #include "MozjsGlobalInterfaceParent.h"
 #include "MozjsImplementedInterface.h"
@@ -90,6 +91,7 @@
 #include "cobalt/bindings/testing/exception_object_interface.h"
 #include "cobalt/bindings/testing/exceptions_interface.h"
 #include "cobalt/bindings/testing/extended_idl_attributes_interface.h"
+#include "cobalt/bindings/testing/garbage_collection_test_interface.h"
 #include "cobalt/bindings/testing/get_opaque_root_interface.h"
 #include "cobalt/bindings/testing/global_interface_parent.h"
 #include "cobalt/bindings/testing/implemented_interface.h"
@@ -160,6 +162,7 @@
 using cobalt::bindings::testing::ExceptionObjectInterface;
 using cobalt::bindings::testing::ExceptionsInterface;
 using cobalt::bindings::testing::ExtendedIDLAttributesInterface;
+using cobalt::bindings::testing::GarbageCollectionTestInterface;
 using cobalt::bindings::testing::GetOpaqueRootInterface;
 using cobalt::bindings::testing::GlobalInterfaceParent;
 using cobalt::bindings::testing::ImplementedInterface;
@@ -189,6 +192,7 @@
 using cobalt::bindings::testing::MozjsExceptionObjectInterface;
 using cobalt::bindings::testing::MozjsExceptionsInterface;
 using cobalt::bindings::testing::MozjsExtendedIDLAttributesInterface;
+using cobalt::bindings::testing::MozjsGarbageCollectionTestInterface;
 using cobalt::bindings::testing::MozjsGetOpaqueRootInterface;
 using cobalt::bindings::testing::MozjsGlobalInterfaceParent;
 using cobalt::bindings::testing::MozjsImplementedInterface;
@@ -260,6 +264,11 @@
 using cobalt::script::mozjs::WrapperPrivate;
 using cobalt::script::mozjs::WrapperFactory;
 using cobalt::script::Wrappable;
+JSObject* DummyFunctor(
+    JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  NOTREACHED();
+  return NULL;
+}
 }  // namespace
 
 namespace cobalt {
@@ -664,7 +673,6 @@
   global_object_proxy->SetGlobalObjectProxyAndWrapper(proxy, wrappable);
   return proxy;
 }
-
 //static
 const JSClass* MozjsWindow::PrototypeClass(
       JSContext* context) {
@@ -818,6 +826,10 @@
       base::Bind(MozjsExtendedIDLAttributesInterface::CreateProxy),
       base::Bind(MozjsExtendedIDLAttributesInterface::PrototypeClass));
   wrapper_factory->RegisterWrappableType(
+      GarbageCollectionTestInterface::GarbageCollectionTestInterfaceWrappableType(),
+      base::Bind(MozjsGarbageCollectionTestInterface::CreateProxy),
+      base::Bind(MozjsGarbageCollectionTestInterface::PrototypeClass));
+  wrapper_factory->RegisterWrappableType(
       GetOpaqueRootInterface::GetOpaqueRootInterfaceWrappableType(),
       base::Bind(MozjsGetOpaqueRootInterface::CreateProxy),
       base::Bind(MozjsGetOpaqueRootInterface::PrototypeClass));
@@ -905,6 +917,10 @@
       UnionTypesInterface::UnionTypesInterfaceWrappableType(),
       base::Bind(MozjsUnionTypesInterface::CreateProxy),
       base::Bind(MozjsUnionTypesInterface::PrototypeClass));
+  wrapper_factory->RegisterWrappableType(
+      Window::WindowWrappableType(),
+      base::Bind(DummyFunctor),
+      base::Bind(MozjsWindow::PrototypeClass));
 
 }
 
diff --git a/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template b/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
index 3a668f8..f307bbc 100644
--- a/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/callback-interface.cc.template
@@ -56,6 +56,7 @@
 {% if overload.type != 'void' %}
   {{overload.type}} cobalt_return_value;
 {% endif %}
+  JSExceptionState* previous_exception_state = JS_SaveExceptionState(context_);
 
   // This could be set to NULL if it was garbage collected.
   JS::RootedObject implementing_object(context_, implementing_object_.Get());
@@ -102,6 +103,7 @@
   }
 
   *had_exception = !success;
+  JS_RestoreExceptionState(context_, previous_exception_state);
 {% if overload.type != 'void' %}
   return cobalt_return_value;
 {% endif %}
diff --git a/src/cobalt/bindings/mozjs/templates/interface.cc.template b/src/cobalt/bindings/mozjs/templates/interface.cc.template
index 992ad67..4d4cf06 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.cc.template
@@ -85,6 +85,15 @@
 {% endfor %}
 {% endif %}
 {% endblock enumeration_declarations %}
+{% block top_level_unnamed_namespace %}
+{% if is_global_interface %}
+JSObject* DummyFunctor(
+    JSContext* context, const scoped_refptr<Wrappable>& wrappable) {
+  NOTREACHED();
+  return NULL;
+}
+{% endif %}
+{% endblock top_level_unnamed_namespace %}
 
 {% block implementation %}
 namespace {
@@ -505,8 +514,7 @@
   {{impl_class}}* impl =
       wrapper_private->wrappable<{{impl_class}}>().get();
   if (!impl) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Stringifier problem.");
+    exception_state.SetSimpleException(cobalt::script::kStringifierProblem);
     NOTREACHED();
     return false;
   }
@@ -797,7 +805,6 @@
   global_object_proxy->SetGlobalObjectProxyAndWrapper(proxy, wrappable);
   return proxy;
 }
-
 {% else %}
 // static
 JSObject* {{binding_class}}::CreateProxy(
@@ -904,9 +911,13 @@
 {% if interface.conditional %}
 #if defined({{interface.conditional}})
 {% endif %}
-  {# Don't register a create method for the global interface, since we do not
-     create a wrapper for it directly. #}
-  {% if interface.name != impl_class %}
+  {# Pass in a dummy CreateProxy for global interface #}
+  {% if interface.name == impl_class %}
+  wrapper_factory->RegisterWrappableType(
+      {{interface.name}}::{{interface.name}}WrappableType(),
+      base::Bind(DummyFunctor),
+      base::Bind(Mozjs{{interface.name}}::PrototypeClass));
+  {% else %}
   wrapper_factory->RegisterWrappableType(
       {{interface.name}}::{{interface.name}}WrappableType(),
       base::Bind(Mozjs{{interface.name}}::CreateProxy),
@@ -958,9 +969,7 @@
     *out_enum = {{impl_class}}::{{value}};
   }{% endfor %} else {
     // 2. If S is not one of E's enumeration values, then throw a TypeError.
-    exception_state->
-        SetSimpleException(ExceptionState::kTypeError,
-                           "Cannot convert JavaScript value to Enum.");
+    exception_state->SetSimpleException(cobalt::script::kConvertToEnumFailed);
     return;
   }
 }
diff --git a/src/cobalt/bindings/mozjs/templates/macros.cc.template b/src/cobalt/bindings/mozjs/templates/macros.cc.template
index dd3bdca..2eac967 100644
--- a/src/cobalt/bindings/mozjs/templates/macros.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/macros.cc.template
@@ -115,8 +115,7 @@
 {%- if non_optional_arguments|length > 0 %}
   const size_t kMinArguments = {{non_optional_arguments|length}};
   if (args.length() < kMinArguments) {
-    exception_state.SetSimpleException(
-        script::ExceptionState::kTypeError, "Not enough arguments.");
+    exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
     return false;
   }
 {% endif -%}
@@ -388,7 +387,6 @@
   // http://heycam.github.io/webidl/#dfn-overload-resolution-algorithm
   // 4. If S is empty, then throw a TypeError.
   MozjsExceptionState exception_state(context);
-  exception_state.SetSimpleException(
-      script::ExceptionState::kTypeError, "Invalid number of arguments.");
+  exception_state.SetSimpleException(script::kInvalidNumberOfArguments);
   return false;
 {%- endmacro %}
diff --git a/src/cobalt/bindings/templates/interface-base.cc.template b/src/cobalt/bindings/templates/interface-base.cc.template
index 9bc9ea7..5da3faa 100644
--- a/src/cobalt/bindings/templates/interface-base.cc.template
+++ b/src/cobalt/bindings/templates/interface-base.cc.template
@@ -75,6 +75,8 @@
 {% block enumeration_declarations %}
 {% endblock enumeration_declarations %}
 {% endif %}
+{% block top_level_unnamed_namespace %}
+{% endblock top_level_unnamed_namespace %}
 }  // namespace
 
 namespace cobalt {
diff --git a/src/cobalt/bindings/testing/GarbageCollectionTestInterface.idl b/src/cobalt/bindings/testing/GarbageCollectionTestInterface.idl
new file mode 100644
index 0000000..e60c747
--- /dev/null
+++ b/src/cobalt/bindings/testing/GarbageCollectionTestInterface.idl
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+[Constructor]
+interface GarbageCollectionTestInterface {
+};
diff --git a/src/cobalt/bindings/testing/exceptions_bindings_test.cc b/src/cobalt/bindings/testing/exceptions_bindings_test.cc
index 13d6d0e..71ef437 100644
--- a/src/cobalt/bindings/testing/exceptions_bindings_test.cc
+++ b/src/cobalt/bindings/testing/exceptions_bindings_test.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "base/stringprintf.h"
 #include "cobalt/bindings/testing/bindings_test_base.h"
 #include "cobalt/bindings/testing/exception_object_interface.h"
 #include "cobalt/bindings/testing/exceptions_interface.h"
@@ -38,16 +39,13 @@
 
 class SimpleExceptionSetter {
  public:
-  SimpleExceptionSetter(script::ExceptionState::SimpleExceptionType type,
-                        const std::string& message)
-      : type_(type), message_(message) {}
+  explicit SimpleExceptionSetter(script::MessageType type) : type_(type) {}
   void FireException(script::ExceptionState* exception) {
-    exception->SetSimpleException(type_, message_);
+    exception->SetSimpleException(type_);
   }
 
  private:
-  script::ExceptionState::SimpleExceptionType type_;
-  std::string message_;
+  script::MessageType type_;
 };
 
 class ExceptionObjectSetter {
@@ -62,11 +60,20 @@
  private:
   scoped_refptr<script::ScriptException> exception_object_;
 };
+
+std::string GetExceptionMessageString(script::MessageType message_type, ...) {
+  va_list arguments;
+  va_start(arguments, message_type);
+  std::string error_string =
+      base::StringPrintV(GetExceptionMessageFormat(message_type), arguments);
+  va_end(arguments);
+  return error_string;
+}
+
 }  // namespace
 
 TEST_F(ExceptionsBindingsTest, ThrowExceptionFromConstructor) {
-  SimpleExceptionSetter exception_setter(script::ExceptionState::kError,
-                                         "generic error");
+  SimpleExceptionSetter exception_setter(script::kSimpleError);
   EXPECT_CALL(ExceptionsInterface::constructor_implementation_mock.Get(),
               Constructor(_))
       .WillOnce(
@@ -74,23 +81,21 @@
 
   std::string result;
   EXPECT_FALSE(EvaluateScript("var foo = new ExceptionsInterface();", &result));
-  EXPECT_SUBSTRING("Error: generic error", result.c_str());
+  EXPECT_SUBSTRING("Error", result.c_str());
 }
 
 TEST_F(ExceptionsBindingsTest, ThrowExceptionFromOperation) {
-  SimpleExceptionSetter exception_setter(script::ExceptionState::kTypeError,
-                                         "this is a type error");
+  SimpleExceptionSetter exception_setter(script::kSimpleTypeError);
   EXPECT_CALL(test_mock(), FunctionThrowsException(_)).WillOnce(
       Invoke(&exception_setter, &SimpleExceptionSetter::FireException));
 
   std::string result;
   EXPECT_FALSE(EvaluateScript("test.functionThrowsException();", &result));
-  EXPECT_SUBSTRING("TypeError: this is a type error", result.c_str());
+  EXPECT_SUBSTRING("TypeError", result.c_str());
 }
 
 TEST_F(ExceptionsBindingsTest, ThrowExceptionFromGetter) {
-  SimpleExceptionSetter exception_setter(script::ExceptionState::kRangeError,
-                                         "this is a range error");
+  SimpleExceptionSetter exception_setter(script::kSimpleRangeError);
   EXPECT_CALL(test_mock(), attribute_throws_exception(_)).WillOnce(
       DoAll(Invoke(&exception_setter, &SimpleExceptionSetter::FireException),
             Return(false)));
@@ -98,12 +103,11 @@
   std::string result;
   EXPECT_FALSE(
       EvaluateScript("var foo = test.attributeThrowsException;", &result));
-  EXPECT_SUBSTRING("RangeError: this is a range error", result.c_str());
+  EXPECT_SUBSTRING("RangeError", result.c_str());
 }
 
 TEST_F(ExceptionsBindingsTest, ThrowExceptionFromSetter) {
-  SimpleExceptionSetter exception_setter(
-      script::ExceptionState::kReferenceError, "this is a reference error");
+  SimpleExceptionSetter exception_setter(script::kSimpleReferenceError);
   EXPECT_CALL(test_mock(), set_attribute_throws_exception(_, _))
       .WillOnce(WithArg<1>(
           Invoke(&exception_setter, &SimpleExceptionSetter::FireException)));
@@ -111,7 +115,7 @@
   std::string result;
   EXPECT_FALSE(
       EvaluateScript("test.attributeThrowsException = true;", &result));
-  EXPECT_SUBSTRING("ReferenceError: this is a reference error", result.c_str());
+  EXPECT_SUBSTRING("ReferenceError", result.c_str());
 }
 
 TEST_F(ExceptionsBindingsTest, ThrowExceptionObject) {
@@ -144,6 +148,16 @@
   EXPECT_STREQ("the message", result.c_str());
 }
 
+TEST_F(ExceptionsBindingsTest, GetExceptionMessageStringTest) {
+  std::string error_message =
+      GetExceptionMessageString(script::kWrongByteLengthMultiple, 8);
+  EXPECT_STREQ("Byte length should be a multiple of 8.", error_message.c_str());
+  error_message =
+      GetExceptionMessageString(script::kWrongByteOffsetMultiple, 16);
+  EXPECT_STREQ("Byte offset should be a multiple of 16.",
+               error_message.c_str());
+}
+
 }  // namespace testing
 }  // namespace bindings
 }  // namespace cobalt
diff --git a/src/cobalt/bindings/testing/garbage_collection_test.cc b/src/cobalt/bindings/testing/garbage_collection_test.cc
new file mode 100644
index 0000000..b73dce0
--- /dev/null
+++ b/src/cobalt/bindings/testing/garbage_collection_test.cc
@@ -0,0 +1,80 @@
+/*
+ * 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"
+#include "cobalt/bindings/testing/garbage_collection_test_interface.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cobalt {
+namespace bindings {
+namespace testing {
+
+namespace {
+typedef BindingsTestBase GarbageCollectionTest;
+}  // namespace
+
+TEST_F(GarbageCollectionTest, JSObjectHoldsReferenceToPlatformObject) {
+  EXPECT_EQ(GarbageCollectionTestInterface::instances().size(), 0);
+  EXPECT_TRUE(
+      EvaluateScript("var obj = new GarbageCollectionTestInterface();", NULL));
+
+  // Ensure that this is kept alive after GC is run.
+  EXPECT_EQ(GarbageCollectionTestInterface::instances().size(), 1);
+  CollectGarbage();
+  EXPECT_EQ(GarbageCollectionTestInterface::instances().size(), 1);
+
+  // Ensure that this is destroyed when there are no more references to it from
+  // JavaScript.
+  EXPECT_TRUE(EvaluateScript("var obj = undefined;", NULL));
+  CollectGarbage();
+#if !defined(ENGINE_USES_CONSERVATIVE_ROOTING)
+  EXPECT_EQ(GarbageCollectionTestInterface::instances().size(), 0);
+#endif
+}
+
+TEST_F(GarbageCollectionTest, PreventGarbageCollection) {
+  EXPECT_EQ(GarbageCollectionTestInterface::instances().size(), 0);
+  EXPECT_TRUE(
+      EvaluateScript("var obj = new GarbageCollectionTestInterface();", NULL));
+
+  // Keep this instance alive using PreventGarbageCollection
+  ASSERT_EQ(GarbageCollectionTestInterface::instances().size(), 1);
+  global_object_proxy_->PreventGarbageCollection(
+      make_scoped_refptr<script::Wrappable>(
+          GarbageCollectionTestInterface::instances()[0]));
+  // Remove the only reference to this object from JavaScript.
+  EXPECT_TRUE(EvaluateScript("var obj = undefined;", NULL));
+
+  // Ensure that the object is kept alive.
+  CollectGarbage();
+  ASSERT_EQ(GarbageCollectionTestInterface::instances().size(), 1);
+
+  // Allow this object to be garbage collected once more.
+  global_object_proxy_->AllowGarbageCollection(
+      make_scoped_refptr<script::Wrappable>(
+          GarbageCollectionTestInterface::instances()[0]));
+
+  // Ensure that the object is destroyed by garbage collection.
+  CollectGarbage();
+#if !defined(ENGINE_USES_CONSERVATIVE_ROOTING)
+  EXPECT_EQ(GarbageCollectionTestInterface::instances().size(), 0);
+#endif
+}
+
+}  // namespace testing
+}  // namespace bindings
+}  // namespace cobalt
diff --git a/src/cobalt/bindings/testing/garbage_collection_test_interface.cc b/src/cobalt/bindings/testing/garbage_collection_test_interface.cc
new file mode 100644
index 0000000..5b25309
--- /dev/null
+++ b/src/cobalt/bindings/testing/garbage_collection_test_interface.cc
@@ -0,0 +1,51 @@
+/*
+ * 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/garbage_collection_test_interface.h"
+
+#include "base/lazy_instance.h"
+
+namespace cobalt {
+namespace bindings {
+namespace testing {
+namespace {
+base::LazyInstance<
+    GarbageCollectionTestInterface::GarbageCollectionTestInterfaceVector>
+    instances;
+}  // namespace
+
+GarbageCollectionTestInterface::GarbageCollectionTestInterface() {
+  instances().push_back(this);
+}
+
+GarbageCollectionTestInterface::~GarbageCollectionTestInterface() {
+  for (GarbageCollectionTestInterfaceVector::iterator it = instances().begin();
+       it != instances().end(); ++it) {
+    if (*it == this) {
+      instances().erase(it);
+      break;
+    }
+  }
+}
+
+GarbageCollectionTestInterface::GarbageCollectionTestInterfaceVector&
+GarbageCollectionTestInterface::instances() {
+  return ::cobalt::bindings::testing::instances.Get();
+}
+
+}  // namespace testing
+}  // namespace bindings
+}  // namespace cobalt
diff --git a/src/cobalt/bindings/testing/garbage_collection_test_interface.h b/src/cobalt/bindings/testing/garbage_collection_test_interface.h
new file mode 100644
index 0000000..e4c0456
--- /dev/null
+++ b/src/cobalt/bindings/testing/garbage_collection_test_interface.h
@@ -0,0 +1,44 @@
+/*
+ * 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_BINDINGS_TESTING_GARBAGE_COLLECTION_TEST_INTERFACE_H_
+#define COBALT_BINDINGS_TESTING_GARBAGE_COLLECTION_TEST_INTERFACE_H_
+
+#include <vector>
+
+#include "cobalt/script/wrappable.h"
+
+namespace cobalt {
+namespace bindings {
+namespace testing {
+
+class GarbageCollectionTestInterface : public script::Wrappable {
+ public:
+  GarbageCollectionTestInterface();
+  ~GarbageCollectionTestInterface();
+
+  typedef std::vector<GarbageCollectionTestInterface*>
+      GarbageCollectionTestInterfaceVector;
+  static GarbageCollectionTestInterfaceVector& instances();
+
+  DEFINE_WRAPPABLE_TYPE(GarbageCollectionTestInterface);
+};
+
+}  // namespace testing
+}  // namespace bindings
+}  // namespace cobalt
+
+#endif  // COBALT_BINDINGS_TESTING_GARBAGE_COLLECTION_TEST_INTERFACE_H_
diff --git a/src/cobalt/bindings/testing/global_constructors_idls_idl_files_list.tmp b/src/cobalt/bindings/testing/global_constructors_idls_idl_files_list.tmp
index 93f3f87..1f9a3fc 100644
--- a/src/cobalt/bindings/testing/global_constructors_idls_idl_files_list.tmp
+++ b/src/cobalt/bindings/testing/global_constructors_idls_idl_files_list.tmp
@@ -18,6 +18,7 @@
 ExceptionObjectInterface.idl
 ExceptionsInterface.idl
 ExtendedIDLAttributesInterface.idl
+GarbageCollectionTestInterface.idl
 GetOpaqueRootInterface.idl
 GlobalInterfaceParent.idl
 IndexedGetterInterface.idl
diff --git a/src/cobalt/bindings/testing/global_objects_idl_files_list.tmp b/src/cobalt/bindings/testing/global_objects_idl_files_list.tmp
index 7b3f83a..c1c7594 100644
--- a/src/cobalt/bindings/testing/global_objects_idl_files_list.tmp
+++ b/src/cobalt/bindings/testing/global_objects_idl_files_list.tmp
@@ -18,6 +18,7 @@
 ExceptionObjectInterface.idl
 ExceptionsInterface.idl
 ExtendedIDLAttributesInterface.idl
+GarbageCollectionTestInterface.idl
 GetOpaqueRootInterface.idl
 GlobalInterfaceParent.idl
 IndexedGetterInterface.idl
diff --git a/src/cobalt/bindings/testing/interfaces_info_individual_static_idl_files_list.tmp b/src/cobalt/bindings/testing/interfaces_info_individual_static_idl_files_list.tmp
index 5b5baa3..ff5e547 100644
--- a/src/cobalt/bindings/testing/interfaces_info_individual_static_idl_files_list.tmp
+++ b/src/cobalt/bindings/testing/interfaces_info_individual_static_idl_files_list.tmp
@@ -18,6 +18,7 @@
 ExceptionObjectInterface.idl
 ExceptionsInterface.idl
 ExtendedIDLAttributesInterface.idl
+GarbageCollectionTestInterface.idl
 GetOpaqueRootInterface.idl
 GlobalInterfaceParent.idl
 IndexedGetterInterface.idl
diff --git a/src/cobalt/bindings/testing/testing.gyp b/src/cobalt/bindings/testing/testing.gyp
index b820608..0286dcd 100644
--- a/src/cobalt/bindings/testing/testing.gyp
+++ b/src/cobalt/bindings/testing/testing.gyp
@@ -45,6 +45,7 @@
         'ExceptionObjectInterface.idl',
         'ExceptionsInterface.idl',
         'ExtendedIDLAttributesInterface.idl',
+        'GarbageCollectionTestInterface.idl',
         'GetOpaqueRootInterface.idl',
         'GlobalInterfaceParent.idl',
         'IndexedGetterInterface.idl',
@@ -102,6 +103,7 @@
         'constants_interface.cc',
         'constructor_interface.cc',
         'exceptions_interface.cc',
+        'garbage_collection_test_interface.cc',
         'named_constructor_interface.cc',
         'operations_test_interface.cc',
         'put_forwards_interface.cc',
@@ -129,6 +131,7 @@
         'enumeration_bindings_test.cc',
         'exceptions_bindings_test.cc',
         'extended_attributes_test.cc',
+        'garbage_collection_test.cc',
         'getter_setter_test.cc',
         'get_opaque_root_test.cc',
         'global_interface_bindings_test.cc',
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index 9dfbf01..55e33b9 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -119,7 +119,7 @@
       array_buffer_cache_(new dom::ArrayBuffer::Cache(3 * 1024 * 1024)),
 #endif  // defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
       media_module_(media::MediaModule::Create(
-          renderer_module_.render_target()->GetSize(),
+          system_window, renderer_module_.render_target()->GetSize(),
           renderer_module_.pipeline()->GetResourceProvider(),
           options.media_module_options)),
       network_module_(&storage_manager_, system_window->event_dispatcher(),
@@ -174,7 +174,8 @@
   debug_console_.reset(new DebugConsole(
       base::Bind(&BrowserModule::OnDebugConsoleRenderTreeProduced,
                  base::Unretained(this)),
-      media_module_.get(), &network_module_, system_window->GetWindowSize(),
+      media_module_.get(), &network_module_,
+      renderer_module_.render_target()->GetSize(),
       renderer_module_.pipeline()->GetResourceProvider(),
       kLayoutMaxRefreshFrequencyInHz,
       base::Bind(&BrowserModule::GetDebugServer, base::Unretained(this))));
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index 4ae4fb4..742a4d3 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -37,6 +37,7 @@
 #include "cobalt/network/network_module.h"
 #include "cobalt/renderer/renderer_module.h"
 #include "cobalt/storage/storage_manager.h"
+#include "cobalt/system_window/system_window.h"
 #include "cobalt/webdriver/session_driver.h"
 #include "googleurl/src/gurl.h"
 #if defined(ENABLE_DEBUG_CONSOLE)
diff --git a/src/cobalt/browser/debug_console/console_values.js b/src/cobalt/browser/debug_console/console_values.js
index 66e37be..c773ee2 100644
--- a/src/cobalt/browser/debug_console/console_values.js
+++ b/src/cobalt/browser/debug_console/console_values.js
@@ -21,11 +21,18 @@
   // Default key used for auto-save, or if the user doesn't specify another.
   this.DEFAULT_KEY = 'default';
   // Reduced space-separated list of CVal prefixes to display at start-up.
-  this.DEFAULT_ACTIVE_SET = 'Cobalt DevTools Memory';
+  this.DEFAULT_ACTIVE_SET =
+      'Cobalt DevTools Memory.CPU Memory.MainWebModule ' +
+      'Event.Duration.MainWebModule.KeyDown Renderer.Rasterize.Duration';
+
   var names = window.debugHub.getConsoleValueNames();
   this.allCVals = names.split(' ');
-  this.initActiveSet();
-  this.cvalTree = this.buildTree(this.activeCVals);
+  // If true, we will always pull our list of CVals from
+  // this.DEFAULT_ACTIVE_SET.
+  this.useDefaultActiveSet = true;
+
+  // Do a single update to initialize everything.
+  this.update();
 }
 
 // Console value tree node constructor
@@ -152,6 +159,10 @@
 // Updates the complete list of registered CVals.
 // If any active CVals are no longer registered, remove them from the active set.
 ConsoleValues.prototype.updateRegistered = function() {
+  if (this.useDefaultActiveSet) {
+    this.setActiveSetToDefault();
+  }
+
   var names = window.debugHub.getConsoleValueNames();
   this.allCVals = names.split(' ');
   for (var i = 0; i < this.activeCVals.length; i++) {
@@ -176,12 +187,6 @@
   }
 }
 
-// Initializes the active set of CVals from the default.
-ConsoleValues.prototype.initActiveSet = function() {
-  this.activeCVals = [];
-  this.addActive(this.DEFAULT_ACTIVE_SET);
-}
-
 // Lists all registered cvals
 ConsoleValues.prototype.listAll = function() {
   var result = '';
@@ -237,6 +242,13 @@
 
 // Saves the current active set using the web local storage.
 ConsoleValues.prototype.saveActiveSet = function(key) {
+  if (this.useDefaultActiveSet) {
+    // If we are using the default CVals and we go to save our CVal set, lock
+    // it in to the currently displayed list.
+    this.updateRegistered();
+    this.useDefaultActiveSet = false;
+  }
+
   if (!key || !key.length) {
     key = this.DEFAULT_KEY;
   }
@@ -260,6 +272,8 @@
   var longKey = this.KEY_PREFIX + '.' + key;
   var value = window.localStorage.getItem(longKey);
   if (value && value.length > 0) {
+    // If we load CVals from disk, we no longer use the default set.
+    this.useDefaultActiveSet = false;
     this.activeCVals = value.split(' ');
     return 'Loaded CVal display set from "' + longKey + '"';
   } else {
@@ -267,10 +281,22 @@
   }
 }
 
+// Sets the CVal active set to the set of CVals the match the default prefixes.
+// Any of the registered console values that match one of the space-separated
+ConsoleValues.prototype.setActiveSetToDefault = function() {
+  this.activeCVals = [];
+  this.updateActiveSet(this.addSingleActive, this.DEFAULT_ACTIVE_SET);
+}
+
 // Adds one or more CVals to the active list.
 // Any of the registered console values that match one of the space-separated
 // set of prefixes will be added to the active set.
 ConsoleValues.prototype.addActive = function(prefixesToMatch) {
+  if (this.useDefaultActiveSet) {
+    // If we modify our list of CVals, we should no longer rely on the defaults.
+    this.updateRegistered();
+    this.useDefaultActiveSet = false;
+  }
   return this.updateActiveSet(this.addSingleActive, prefixesToMatch);
 }
 
@@ -278,5 +304,10 @@
 // Any of the registered console values that match one of the space-separated
 // set of prefixes will be removed from the active set.
 ConsoleValues.prototype.removeActive = function(prefixesToMatch) {
+  if (this.useDefaultActiveSet) {
+    // If we modify our list of CVals, we should no longer rely on the defaults.
+    this.updateRegistered();
+    this.useDefaultActiveSet = false;
+  }
   return this.updateActiveSet(this.removeSingleActive, prefixesToMatch);
 }
diff --git a/src/cobalt/browser/testdata/media-element-demo/progressive-demo.html b/src/cobalt/browser/testdata/media-element-demo/progressive-demo.html
new file mode 100644
index 0000000..2d10dde2
--- /dev/null
+++ b/src/cobalt/browser/testdata/media-element-demo/progressive-demo.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Progressive Demo</title>
+  <style>
+    body {
+      background-color: rgb(255, 255, 255);
+      color: #0047ab;
+      font-size: 100px;
+    }
+    .small {
+      margin: 100px;
+      border: 10px solid blue;
+      width: 960px;
+      height: 540px;
+    }
+    .big {
+      margin: 10px;
+      border: 10px solid blue;
+      width: 1280px;
+      height: 720px;
+    }
+  </style>
+</head>
+<body>
+  <div>Progressive Demo</div>
+  <video autoplay loop id="v" class="small" src="progressive.mp4"></video>
+  <script>
+    window.setInterval(function() {
+      if (document.getElementById('v').className === 'big')
+        document.getElementById('v').className = 'small';
+      else
+        document.getElementById('v').className = 'big';
+    }, 3000);
+  </script>
+</body>
+</html>
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 073f8b7..0ad6dc9 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -23,6 +23,7 @@
 #include "base/message_loop_proxy.h"
 #include "base/optional.h"
 #include "base/stringprintf.h"
+#include "cobalt/base/address_sanitizer.h"
 #include "cobalt/base/tokens.h"
 #include "cobalt/browser/switches.h"
 #include "cobalt/browser/web_module_stat_tracker.h"
@@ -37,6 +38,10 @@
 
 namespace {
 
+// The maximum number of element depth in the DOM tree. Elements at a level
+// deeper than this could be discarded, and will not be rendered.
+const int kDOMMaxElementDepth = 32;
+
 #if defined(ENABLE_PARTIAL_LAYOUT_CONTROL)
 // Help string for the 'partial_layout' command.
 const char kPartialLayoutCommandShortHelp[] =
@@ -243,6 +248,7 @@
   DCHECK(css_parser_);
 
   dom_parser_.reset(new dom_parser::Parser(
+      kDOMMaxElementDepth,
       base::Bind(&WebModule::Impl::OnError, base::Unretained(this))));
   DCHECK(dom_parser_);
 
@@ -310,7 +316,7 @@
   DCHECK(window_weak_);
 
   environment_settings_.reset(new dom::DOMSettings(
-      fetcher_factory_.get(), data.network_module, window_,
+      kDOMMaxElementDepth, fetcher_factory_.get(), data.network_module, window_,
       media_source_registry_.get(), javascript_engine_.get(),
       global_object_proxy_.get(), data.options.dom_settings_options));
   DCHECK(environment_settings_);
@@ -327,8 +333,8 @@
   layout_manager_.reset(new layout::LayoutManager(
       window_.get(), base::Bind(&WebModule::Impl::OnRenderTreeProduced,
                                 base::Unretained(this)),
-      data.options.layout_trigger, data.layout_refresh_rate,
-      data.network_module->preferred_language(),
+      data.options.layout_trigger, data.dom_max_element_depth,
+      data.layout_refresh_rate, data.network_module->preferred_language(),
       web_module_stat_tracker_->layout_stat_tracker()));
   DCHECK(layout_manager_);
 
@@ -545,22 +551,21 @@
     : thread_(options.name.c_str()) {
   ConstructionData construction_data(
       initial_url, render_tree_produced_callback, error_callback, media_module,
-      network_module, window_dimensions, resource_provider, layout_refresh_rate,
-      options);
+      network_module, window_dimensions, resource_provider, kDOMMaxElementDepth,
+      layout_refresh_rate, options);
+
+#if defined(COBALT_BUILD_TYPE_DEBUG)
+  // Non-optimized builds require a bigger stack size.
+  const size_t kBaseStackSize = 2 * 1024 * 1024;
+#else
+  const size_t kBaseStackSize = 256 * 1024;
+#endif
 
   // Start the dedicated thread and create the internal implementation
   // object on that thread.
-#if defined(ADDRESS_SANITIZER)
-  // ASAN requires a much bigger stack size here.
-  const int kStackSize = 4096 * 1024;
-#elif defined(COBALT_BUILD_TYPE_DEBUG)
-  // Non-optimized builds require a bigger stack size.
-  const int kStackSize = 2 * 1024 * 1024;
-#else
-  const int kStackSize = 256 * 1024;
-#endif
+  size_t stack_size = kBaseStackSize + base::kAsanAdditionalStackSize;
   thread_.StartWithOptions(
-      base::Thread::Options(MessageLoop::TYPE_DEFAULT, kStackSize));
+      base::Thread::Options(MessageLoop::TYPE_DEFAULT, stack_size));
   DCHECK(message_loop());
 
   message_loop()->PostTask(
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index 3aeb2e2..07fc9b4 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -185,7 +185,8 @@
         network::NetworkModule* network_module,
         const math::Size& window_dimensions,
         render_tree::ResourceProvider* resource_provider,
-        float layout_refresh_rate, const Options& options)
+        int dom_max_element_depth, float layout_refresh_rate,
+        const Options& options)
         : initial_url(initial_url),
           render_tree_produced_callback(render_tree_produced_callback),
           error_callback(error_callback),
@@ -193,6 +194,7 @@
           network_module(network_module),
           window_dimensions(window_dimensions),
           resource_provider(resource_provider),
+          dom_max_element_depth(dom_max_element_depth),
           layout_refresh_rate(layout_refresh_rate),
           options(options) {}
 
@@ -203,6 +205,7 @@
     network::NetworkModule* network_module;
     math::Size window_dimensions;
     render_tree::ResourceProvider* resource_provider;
+    int dom_max_element_depth;
     float layout_refresh_rate;
     Options options;
   };
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 2eed42f..7eac871 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-10571
\ No newline at end of file
+10943
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index 04a0d5e..cfbf8bf 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -50,13 +50,17 @@
     # force a stub graphics implementation or software graphics implementation.
     # It can be one of the following options:
     #   'hardware' -- As much hardware acceleration of graphics commands as
-    #                 possible.
+    #                 possible. Required for 360 rendering.
     #   'software' -- Perform most rasterization using the CPU and only interact
     #                 with the GPU to send the final image to the output window.
     #   'stub'     -- Stub graphics rasterization.  A rasterizer object will
     #                 still be available and valid, but it will do nothing.
     'rasterizer_type%': 'hardware',
 
+    # Modify this value to adjust the default rasterizer setting for your
+    # platform.
+    'default_renderer_options_dependency%': '<(DEPTH)/cobalt/renderer/default_options_starboard.gyp:default_options',
+
     # The variables allow changing the target type on platforms where the
     # native code may require an additional packaging step (ex. Android).
     'gtest_target_type%': 'executable',
diff --git a/src/cobalt/cssom/compound_selector.cc b/src/cobalt/cssom/compound_selector.cc
index bc2457c..22efc1d 100644
--- a/src/cobalt/cssom/compound_selector.cc
+++ b/src/cobalt/cssom/compound_selector.cc
@@ -40,7 +40,10 @@
 
 }  // namespace
 
-CompoundSelector::CompoundSelector() : left_combinator_(NULL) {}
+CompoundSelector::CompoundSelector()
+    : left_combinator_(NULL),
+      has_pseudo_element_(false),
+      requires_rule_matching_verification_visit_(false) {}
 
 CompoundSelector::~CompoundSelector() {}
 
@@ -51,6 +54,21 @@
 void CompoundSelector::AppendSelector(
     scoped_ptr<SimpleSelector> simple_selector) {
   specificity_.AddFrom(simple_selector->GetSpecificity());
+  has_pseudo_element_ =
+      has_pseudo_element_ || simple_selector->AsPseudoElement() != NULL;
+
+  // There are two cases where the selectors require a visit:
+  // 1. There are multiple selectors. Gathering only tests against the first
+  //    selector and the later selectors must also be verified to match.
+  // 2. The single selector's AlwaysRequiresRuleMatchingVerificationVisit() call
+  //    returns true. This indicates that being gathered as a candidate is not
+  //    sufficient to prove a match and that additional verification checks are
+  //    required.
+  requires_rule_matching_verification_visit_ =
+      requires_rule_matching_verification_visit_ ||
+      !simple_selectors_.empty() ||
+      simple_selector->AlwaysRequiresRuleMatchingVerificationVisit();
+
   bool should_sort =
       !simple_selectors_.empty() &&
       SimpleSelectorsLessThan(simple_selector.get(), simple_selectors_.back());
diff --git a/src/cobalt/cssom/compound_selector.h b/src/cobalt/cssom/compound_selector.h
index 48e0a6c..b4e1121 100644
--- a/src/cobalt/cssom/compound_selector.h
+++ b/src/cobalt/cssom/compound_selector.h
@@ -53,10 +53,12 @@
   void AppendSelector(scoped_ptr<SimpleSelector> selector);
   const SimpleSelectors& simple_selectors() { return simple_selectors_; }
   PseudoElement* pseudo_element() {
-    for (SimpleSelectors::iterator iter = simple_selectors_.begin();
-         iter != simple_selectors_.end(); ++iter) {
-      if ((*iter)->AsPseudoElement()) {
-        return (*iter)->AsPseudoElement();
+    if (has_pseudo_element_) {
+      for (SimpleSelectors::iterator iter = simple_selectors_.begin();
+           iter != simple_selectors_.end(); ++iter) {
+        if ((*iter)->AsPseudoElement()) {
+          return (*iter)->AsPseudoElement();
+        }
       }
     }
     return NULL;
@@ -70,6 +72,10 @@
   Combinator* right_combinator() { return right_combinator_.get(); }
   void set_right_combinator(scoped_ptr<Combinator> combinator);
 
+  bool requires_rule_matching_verification_visit() const {
+    return requires_rule_matching_verification_visit_;
+  }
+
   bool operator<(const CompoundSelector& that) const {
     if (simple_selectors_.size() < that.simple_selectors_.size()) {
       return true;
@@ -109,6 +115,19 @@
   scoped_ptr<Combinator> right_combinator_;
   SimpleSelectors simple_selectors_;
   Specificity specificity_;
+  bool has_pseudo_element_;
+  // This flag tracks whether or not during rule matching, after the initial
+  // candidate gathering phase, the simple selectors additional checks during
+  // the verification phase to determine a match; otherwise, the act of
+  // being gathered itself proves the match.
+  // There are two cases where the selectors require a visit:
+  // 1. There are multiple selectors. Gathering only tests against the first
+  //    selector and the later selectors must also be verified to match.
+  // 2. The single selector's AlwaysRequiresRuleMatchingVerificationVisit() call
+  //    returns true. This indicates that being gathered as a candidate is not
+  //    sufficient to prove a match and that additional verification checks are
+  //    required.
+  bool requires_rule_matching_verification_visit_;
 
   DISALLOW_COPY_AND_ASSIGN(CompoundSelector);
 };
diff --git a/src/cobalt/cssom/css_style_declaration.cc b/src/cobalt/cssom/css_style_declaration.cc
index 6c170d5..047a0ab 100644
--- a/src/cobalt/cssom/css_style_declaration.cc
+++ b/src/cobalt/cssom/css_style_declaration.cc
@@ -1066,7 +1066,19 @@
 
 std::string CSSStyleDeclaration::GetPropertyValue(
     const std::string& property_name) {
-  return GetDeclaredPropertyValueStringByKey(GetPropertyKey(property_name));
+  PropertyKey key = GetPropertyKey(property_name);
+  if (key > kMaxLonghandPropertyKey) {
+    // Shorthand properties are never directly stored as declared properties,
+    // but are expanded into their longhand property components during parsing.
+    // TODO: Implement serialization of css values, see
+    // https://www.w3.org/TR/cssom-1/#serializing-css-values
+    DCHECK_LE(key, kMaxEveryPropertyKey);
+    DLOG(WARNING) << "Unsupported property query for \"" << property_name
+                  << "\": Returning of property value strings is only "
+                     "supported for longhand properties.";
+    return std::string();
+  }
+  return GetDeclaredPropertyValueStringByKey(key);
 }
 
 void CSSStyleDeclaration::SetPropertyValueStringByKey(
diff --git a/src/cobalt/cssom/not_pseudo_class.h b/src/cobalt/cssom/not_pseudo_class.h
index bfbb661..812c4c6 100644
--- a/src/cobalt/cssom/not_pseudo_class.h
+++ b/src/cobalt/cssom/not_pseudo_class.h
@@ -43,6 +43,10 @@
   void Accept(SelectorVisitor* visitor) OVERRIDE;
 
   // From SimpleSelector.
+  bool AlwaysRequiresRuleMatchingVerificationVisit() const OVERRIDE {
+    return true;
+  }
+
   void IndexSelectorTreeNode(SelectorTree::Node* parent_node,
                              SelectorTree::Node* child_node,
                              CombinatorType combinator) OVERRIDE;
diff --git a/src/cobalt/cssom/selector_tree.h b/src/cobalt/cssom/selector_tree.h
index 8badb33..b7ab626 100644
--- a/src/cobalt/cssom/selector_tree.h
+++ b/src/cobalt/cssom/selector_tree.h
@@ -49,7 +49,7 @@
 
   class Node;
 
-  // This class can be used to store unique Nodes.  It stores the Nodes in its
+  // This class can be used to store Nodes.  It stores the Nodes in its
   // internal buffer whose size can be configured via template parameter.
   // After the internal buffer is used up the extra Nodes will be stored inside
   // the contained std::vector.
@@ -75,13 +75,19 @@
     };
 
     NodeSet() : size_(0) {}
-    void insert(const Node* node) {
-      // Check if we already have it.
-      for (size_t i = 0; i < size_; ++i) {
-        if (GetNode(i) == node) {
-          return;
+    void insert(const Node* node, bool check_for_duplicate = false) {
+      // If |check_for_duplicate| is true, then check if the node is already
+      // contained. In nearly all cases, this check is unnecessary because it is
+      // already known that the node is not a duplicate. As a result, the caller
+      // must explicitly request the check when needed.
+      if (check_for_duplicate) {
+        for (size_t i = 0; i < size_; ++i) {
+          if (GetNode(i) == node) {
+            return;
+          }
         }
       }
+
       if (size_ < InternalCacheSize) {
         nodes_[size_] = node;
       } else {
@@ -90,9 +96,10 @@
       ++size_;
     }
     template <class ConstIterator>
-    void insert(ConstIterator begin, ConstIterator end) {
+    void insert(ConstIterator begin, ConstIterator end,
+                bool check_for_duplicate = false) {
       while (begin != end) {
-        insert(*begin);
+        insert(*begin, check_for_duplicate);
         ++begin;
       }
     }
@@ -149,7 +156,12 @@
 
   typedef std::vector<SimpleSelectorNode> SimpleSelectorNodes;
   typedef std::vector<PseudoClassNode> PseudoClassNodes;
-  typedef std::map<base::Token, SimpleSelectorNodes> SelectorTextToNodesMap;
+  // The vast majority of SelectorTextToNodesMap objects have 4 or fewer
+  // selectors. However, they occasionally can number in the hundreds. Using
+  // a SmallMap with an array size of 4, allows both cases to be handled
+  // quickly.
+  typedef base::SmallMap<base::hash_map<base::Token, SimpleSelectorNodes>, 4>
+      SelectorTextToNodesMap;
 
   class Node {
    public:
@@ -166,6 +178,7 @@
     const PseudoClassNodes& pseudo_class_nodes() const {
       return pseudo_class_nodes_;
     }
+    bool HasAnyPseudoClass() const { return pseudo_class_mask_ != 0; }
     bool HasPseudoClass(PseudoClassType pseudo_class_type,
                         CombinatorType combinator_type) const {
       return (pseudo_class_mask_ &
@@ -180,8 +193,8 @@
           (1u << (pseudo_class_type * kCombinatorCount + combinator_type));
     }
 
-    const SelectorTextToNodesMap& selector_nodes_map() const {
-      return selector_nodes_map_;
+    const SelectorTextToNodesMap* selector_nodes_map() const {
+      return selector_nodes_map_.get();
     }
     bool HasSimpleSelector(SimpleSelectorType simple_selector_type,
                            CombinatorType combinator_type) const {
@@ -191,9 +204,15 @@
     void AppendSimpleSelector(base::Token name,
                               SimpleSelectorType simple_selector_type,
                               CombinatorType combinator_type, Node* node) {
+      // Create the SelectorTextToNodesMap if this is the first simple selector
+      // being appended.
+      if (!selector_nodes_map_) {
+        selector_nodes_map_.reset(new SelectorTextToNodesMap());
+      }
+
       SimpleSelectorNode child_node = {simple_selector_type, combinator_type,
                                        node};
-      selector_nodes_map_[name].push_back(child_node);
+      (*selector_nodes_map_)[name].push_back(child_node);
       selector_mask_ |=
           (1u << (simple_selector_type * kCombinatorCount + combinator_type));
     }
@@ -214,8 +233,9 @@
     // Sum of specificity from root to this node.
     Specificity cumulative_specificity_;
 
-    // Indexes for the children.
-    SelectorTextToNodesMap selector_nodes_map_;
+    // Indexes for the children. This is a scoped_ptr because the majority of
+    // nodes do not contain any children.
+    scoped_ptr<SelectorTextToNodesMap> selector_nodes_map_;
     // Bit mask used to quickly reject a certain selector type and combinator
     // combination.
     uint32 selector_mask_;
diff --git a/src/cobalt/cssom/simple_selector.h b/src/cobalt/cssom/simple_selector.h
index 38d549e..675656d 100644
--- a/src/cobalt/cssom/simple_selector.h
+++ b/src/cobalt/cssom/simple_selector.h
@@ -49,6 +49,10 @@
   // Rest of public methods.
   virtual PseudoElement* AsPseudoElement() { return NULL; }
 
+  virtual bool AlwaysRequiresRuleMatchingVerificationVisit() const {
+    return false;
+  }
+
   // Used to sort simple selectors when normalizing compound selector.
   SimpleSelectorType type() const { return type_; }
 
diff --git a/src/cobalt/dom/data_view.cc b/src/cobalt/dom/data_view.cc
index 5e3a938..55fc772 100644
--- a/src/cobalt/dom/data_view.cc
+++ b/src/cobalt/dom/data_view.cc
@@ -25,9 +25,7 @@
       byte_offset_(0),
       byte_length_(buffer ? buffer->byte_length() : 0) {
   if (!buffer) {
-    exception_state->SetSimpleException(
-        script::ExceptionState::kTypeError,
-        "First argument to DataView constructor must be an ArrayBuffer.");
+    exception_state->SetSimpleException(script::kNotAnArrayBuffer);
   }
 }
 
@@ -37,13 +35,9 @@
       byte_offset_(byte_offset),
       byte_length_(buffer ? buffer->byte_length() - byte_offset : 0) {
   if (!buffer) {
-    exception_state->SetSimpleException(
-        script::ExceptionState::kTypeError,
-        "First argument to DataView constructor must be an ArrayBuffer.");
+    exception_state->SetSimpleException(script::kNotAnArrayBuffer);
   } else if (byte_offset_ > buffer_->byte_length()) {
-    exception_state->SetSimpleException(
-        script::ExceptionState::kRangeError,
-        "Start offset is outside the bounds of the buffer.");
+    exception_state->SetSimpleException(script::kOutsideBounds);
   }
 }
 
@@ -51,16 +45,11 @@
                    uint32 byte_length, script::ExceptionState* exception_state)
     : buffer_(buffer), byte_offset_(byte_offset), byte_length_(byte_length) {
   if (!buffer) {
-    exception_state->SetSimpleException(
-        script::ExceptionState::kTypeError,
-        "First argument to DataView constructor must be an ArrayBuffer.");
+    exception_state->SetSimpleException(script::kNotAnArrayBuffer);
   } else if (byte_offset_ > buffer_->byte_length()) {
-    exception_state->SetSimpleException(
-        script::ExceptionState::kRangeError,
-        "Start offset is outside the bounds of the buffer.");
+    exception_state->SetSimpleException(script::kOutsideBounds);
   } else if (byte_offset_ + byte_length_ > buffer_->byte_length()) {
-    exception_state->SetSimpleException(script::ExceptionState::kRangeError,
-                                        "Invalid data view length.");
+    exception_state->SetSimpleException(script::kInvalidLength);
   }
 }
 
diff --git a/src/cobalt/dom/data_view.h b/src/cobalt/dom/data_view.h
index 8aef023..4e9572e 100644
--- a/src/cobalt/dom/data_view.h
+++ b/src/cobalt/dom/data_view.h
@@ -105,9 +105,7 @@
   ElementType GetElement(uint32 byte_offset, bool little_endian,
                          script::ExceptionState* exception_state) const {
     if (byte_offset + sizeof(ElementType) > byte_length_) {
-      exception_state->SetSimpleException(
-          script::ExceptionState::kRangeError,
-          "Offset is outside the bounds of the DataView.");
+      exception_state->SetSimpleException(script::kOutsideBounds);
       // The return value will be ignored.
       return ElementType();
     }
@@ -121,9 +119,7 @@
   void SetElement(uint32 byte_offset, ElementType value, bool little_endian,
                   script::ExceptionState* exception_state) {
     if (byte_offset + sizeof(ElementType) > byte_length_) {
-      exception_state->SetSimpleException(
-          script::ExceptionState::kRangeError,
-          "Offset is outside the bounds of the DataView.");
+      exception_state->SetSimpleException(script::kOutsideBounds);
       return;
     }
     CopyBytes(reinterpret_cast<uint8*>(&value), sizeof(value), little_endian,
diff --git a/src/cobalt/dom/data_view_test.cc b/src/cobalt/dom/data_view_test.cc
index c1972f3..dd42134 100644
--- a/src/cobalt/dom/data_view_test.cc
+++ b/src/cobalt/dom/data_view_test.cc
@@ -70,25 +70,25 @@
 
 TEST(DataViewTest, ExceptionInConstructors) {
   StrictMock<MockExceptionState> exception_state;
-  script::ExceptionState::SimpleExceptionType exception_type;
+  script::MessageType message_type;
   scoped_refptr<ArrayBuffer> array_buffer = new ArrayBuffer(NULL, 10);
 
-  EXPECT_CALL(exception_state, SetSimpleException(_, _))
-      .WillOnce(SaveArg<0>(&exception_type));
+  EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))
+      .WillOnce(SaveArg<0>(&message_type));
   scoped_refptr<DataView> data_view = new DataView(NULL, &exception_state);
-  EXPECT_EQ(script::ExceptionState::kTypeError, exception_type);
+  EXPECT_EQ(script::kTypeError, GetSimpleExceptionType(message_type));
 
-  EXPECT_CALL(exception_state, SetSimpleException(_, _))
-      .WillOnce(SaveArg<0>(&exception_type));
+  EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))
+      .WillOnce(SaveArg<0>(&message_type));
   data_view = new DataView(array_buffer, array_buffer->byte_length() + 1,
                            &exception_state);
-  EXPECT_EQ(script::ExceptionState::kRangeError, exception_type);
+  EXPECT_EQ(script::kRangeError, GetSimpleExceptionType(message_type));
 
-  EXPECT_CALL(exception_state, SetSimpleException(_, _))
-      .WillOnce(SaveArg<0>(&exception_type));
+  EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))
+      .WillOnce(SaveArg<0>(&message_type));
   data_view = new DataView(array_buffer, 0, array_buffer->byte_length() + 1,
                            &exception_state);
-  EXPECT_EQ(script::ExceptionState::kRangeError, exception_type);
+  EXPECT_EQ(script::kRangeError, GetSimpleExceptionType(message_type));
 }
 
 TEST(DataViewTest, Getters) {
@@ -122,18 +122,18 @@
 
 TEST(DataViewTest, GettersWithException) {
   StrictMock<MockExceptionState> exception_state;
-  script::ExceptionState::SimpleExceptionType exception_type;
+  script::MessageType message_type;
   scoped_refptr<ArrayBuffer> array_buffer = new ArrayBuffer(NULL, 13);
   scoped_refptr<DataView> data_view =
       new DataView(array_buffer, &exception_state);
 
 #define DEFINE_DATA_VIEW_GETTER_WITH_EXCEPTION_TEST(DomType, CppType)          \
   {                                                                            \
-    EXPECT_CALL(exception_state, SetSimpleException(_, _))                     \
-        .WillOnce(SaveArg<0>(&exception_type));                                \
+    EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))                   \
+        .WillOnce(SaveArg<0>(&message_type));                                  \
     data_view->Get##DomType(array_buffer->byte_length() - sizeof(CppType) + 1, \
                             &exception_state);                                 \
-    EXPECT_EQ(script::ExceptionState::kRangeError, exception_type);            \
+    EXPECT_EQ(script::kRangeError, GetSimpleExceptionType(message_type));      \
   }
   DATA_VIEW_ACCESSOR_FOR_EACH(DEFINE_DATA_VIEW_GETTER_WITH_EXCEPTION_TEST)
 #undef DEFINE_DATA_VIEW_GETTER_WITH_EXCEPTION_TEST
@@ -188,18 +188,18 @@
 
 TEST(DataViewTest, SettersWithException) {
   StrictMock<MockExceptionState> exception_state;
-  script::ExceptionState::SimpleExceptionType exception_type;
+  script::MessageType message_type;
   scoped_refptr<ArrayBuffer> array_buffer = new ArrayBuffer(NULL, 13);
   scoped_refptr<DataView> data_view =
       new DataView(array_buffer, &exception_state);
 
 #define DEFINE_DATA_VIEW_SETTER_WITH_EXCEPTION_TEST(DomType, CppType)          \
   {                                                                            \
-    EXPECT_CALL(exception_state, SetSimpleException(_, _))                     \
-        .WillOnce(SaveArg<0>(&exception_type));                                \
+    EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))                   \
+        .WillOnce(SaveArg<0>(&message_type));                                  \
     data_view->Set##DomType(array_buffer->byte_length() - sizeof(CppType) + 1, \
                             0, &exception_state);                              \
-    EXPECT_EQ(script::ExceptionState::kRangeError, exception_type);            \
+    EXPECT_EQ(script::kRangeError, GetSimpleExceptionType(message_type));      \
   }
   DATA_VIEW_ACCESSOR_FOR_EACH(DEFINE_DATA_VIEW_SETTER_WITH_EXCEPTION_TEST)
 #undef DEFINE_DATA_VIEW_SETTER_WITH_EXCEPTION_TEST
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index 0a294ac..8e3c80d 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -357,10 +357,11 @@
 void Document::Accept(ConstNodeVisitor* visitor) const { visitor->Visit(this); }
 
 scoped_refptr<Node> Document::Duplicate() const {
-  // Note: Documents should not be duplicated by clients, we just need to
-  // provide an implementation since Document inherits from Node.
-  NOTIMPLEMENTED();
-  return NULL;
+  // For Document, copy Its encoding, content type, URL, its mode (quirks mode,
+  // limited quirks mode, or no-quirks mode), and its type (XML document or HTML
+  // document).
+  //   https://www.w3.org/TR/dom/#concept-node-clone
+  return new Document(html_element_context_, Document::Options(url_as_gurl()));
 }
 
 scoped_refptr<HTMLHtmlElement> Document::html() const {
diff --git a/src/cobalt/dom/dom_settings.cc b/src/cobalt/dom/dom_settings.cc
index 67b6701..894d524 100644
--- a/src/cobalt/dom/dom_settings.cc
+++ b/src/cobalt/dom/dom_settings.cc
@@ -21,14 +21,16 @@
 namespace cobalt {
 namespace dom {
 
-DOMSettings::DOMSettings(loader::FetcherFactory* fetcher_factory,
+DOMSettings::DOMSettings(const int max_dom_element_depth,
+                         loader::FetcherFactory* fetcher_factory,
                          network::NetworkModule* network_module,
                          const scoped_refptr<Window>& window,
                          MediaSource::Registry* media_source_registry,
                          script::JavaScriptEngine* engine,
                          script::GlobalObjectProxy* global_object_proxy,
                          const Options& options)
-    : fetcher_factory_(fetcher_factory),
+    : max_dom_element_depth_(max_dom_element_depth),
+      fetcher_factory_(fetcher_factory),
       network_module_(network_module),
       window_(window),
       array_buffer_allocator_(options.array_buffer_allocator),
diff --git a/src/cobalt/dom/dom_settings.h b/src/cobalt/dom/dom_settings.h
index ed4fbd8..ea6f74b 100644
--- a/src/cobalt/dom/dom_settings.h
+++ b/src/cobalt/dom/dom_settings.h
@@ -57,7 +57,8 @@
     ArrayBuffer::Cache* array_buffer_cache;
   };
 
-  DOMSettings(loader::FetcherFactory* fetcher_factory,
+  DOMSettings(const int max_dom_element_depth,
+              loader::FetcherFactory* fetcher_factory,
               network::NetworkModule* network_module,
               const scoped_refptr<Window>& window,
               MediaSource::Registry* media_source_registry,
@@ -66,6 +67,8 @@
               const Options& options = Options());
   ~DOMSettings() OVERRIDE;
 
+  int max_dom_element_depth() { return max_dom_element_depth_; }
+
   void set_window(const scoped_refptr<Window>& window) { window_ = window; }
   scoped_refptr<Window> window() const { return window_; }
 
@@ -97,6 +100,7 @@
   virtual GURL base_url() const;
 
  private:
+  const int max_dom_element_depth_;
   loader::FetcherFactory* fetcher_factory_;
   network::NetworkModule* network_module_;
   scoped_refptr<Window> window_;
diff --git a/src/cobalt/dom/dom_string_map.cc b/src/cobalt/dom/dom_string_map.cc
index 0172418..c7f8290 100644
--- a/src/cobalt/dom/dom_string_map.cc
+++ b/src/cobalt/dom/dom_string_map.cc
@@ -138,8 +138,8 @@
   if (attribute_name) {
     return element_->GetAttribute(*attribute_name);
   } else {
-    exception_state->SetSimpleException(script::ExceptionState::kSyntaxError,
-                                        property_name);
+    exception_state->SetSimpleException(script::kPropertySyntaxError,
+                                        property_name.c_str());
     return base::nullopt;
   }
 }
@@ -152,8 +152,8 @@
   if (attribute_name) {
     element_->SetAttribute(*attribute_name, value);
   } else {
-    exception_state->SetSimpleException(script::ExceptionState::kSyntaxError,
-                                        property_name);
+    exception_state->SetSimpleException(script::kPropertySyntaxError,
+                                        property_name.c_str());
   }
 }
 
diff --git a/src/cobalt/dom/dom_string_map_test.cc b/src/cobalt/dom/dom_string_map_test.cc
index 5faca86..1825b19 100644
--- a/src/cobalt/dom/dom_string_map_test.cc
+++ b/src/cobalt/dom/dom_string_map_test.cc
@@ -165,12 +165,12 @@
 
 TEST_F(DOMStringMapTest, InvalidPropertyName) {
   EXPECT_CALL(exception_state_,
-              SetSimpleException(script::ExceptionState::kSyntaxError, _));
+              SetSimpleExceptionVA(script::kPropertySyntaxError, _));
   dom_string_map_->AnonymousNamedSetter("hyphen-lowercase", "Los Angeles",
                                         &exception_state_);
 
   EXPECT_CALL(exception_state_,
-              SetSimpleException(script::ExceptionState::kSyntaxError, _));
+              SetSimpleExceptionVA(script::kPropertySyntaxError, _));
   dom_string_map_->AnonymousNamedGetter("hyphen-lowercase", &exception_state_);
 }
 
diff --git a/src/cobalt/dom/dom_token_list.cc b/src/cobalt/dom/dom_token_list.cc
index d2ece24..2002c79 100644
--- a/src/cobalt/dom/dom_token_list.cc
+++ b/src/cobalt/dom/dom_token_list.cc
@@ -170,19 +170,6 @@
   return result;
 }
 
-base::Token DOMTokenList::NonNullItem(unsigned int index) const {
-  MaybeRefresh();
-
-  // 1. If index is equal to or greater than the number of tokens in tokens,
-  //    return an empty string rather than NULL.
-  if (index >= tokens_.size()) {
-    return base::Token();
-  }
-
-  // 2. Return the indexth token in tokens.
-  return tokens_[index];
-}
-
 bool DOMTokenList::ContainsValid(base::Token valid_token) const {
   MaybeRefresh();
 
@@ -201,6 +188,11 @@
   return false;
 }
 
+const std::vector<base::Token>& DOMTokenList::GetTokens() const {
+  MaybeRefresh();
+  return tokens_;
+}
+
 DOMTokenList::~DOMTokenList() { GlobalStats::GetInstance()->Remove(this); }
 
 // Algorithm for RunUpdateSteps:
@@ -230,8 +222,10 @@
     element_node_generation_ = element_->node_generation();
     std::string attribute = element_->GetAttribute(attr_name_).value_or("");
     std::vector<std::string> tokens;
+    tokens.reserve(tokens_.size());
     base::SplitStringAlongWhitespace(attribute, &tokens);
     tokens_.clear();
+    tokens_.reserve(tokens.size());
     for (size_t i = 0; i < tokens.size(); ++i) {
       tokens_.push_back(base::Token(tokens[i]));
     }
diff --git a/src/cobalt/dom/dom_token_list.h b/src/cobalt/dom/dom_token_list.h
index 7f52b5e..abed102 100644
--- a/src/cobalt/dom/dom_token_list.h
+++ b/src/cobalt/dom/dom_token_list.h
@@ -47,14 +47,13 @@
 
   // Custom, not in any spec.
 
-  // This is a variation of Item that should only be called in cases where NULL
-  // is not needed for invalid indices.
-  base::Token NonNullItem(unsigned int index) const;
-
   // This is a variation of Contains that should only be called in cases where
   // the token has already been validated.
   bool ContainsValid(base::Token valid_token) const;
 
+  // Returns a reference to the contained tokens for rapid iteration.
+  const std::vector<base::Token>& GetTokens() const;
+
   // The associated element.
   Element* element() { return element_; }
 
diff --git a/src/cobalt/dom/element.cc b/src/cobalt/dom/element.cc
index 7ccde0b..41204da 100644
--- a/src/cobalt/dom/element.cc
+++ b/src/cobalt/dom/element.cc
@@ -117,7 +117,7 @@
   return named_node_map;
 }
 
-scoped_refptr<DOMTokenList> Element::class_list() {
+const scoped_refptr<DOMTokenList>& Element::class_list() {
   if (!class_list_) {
     // Create a new instance and store a reference to it. Because of the
     // negative performance impact of having to constantly recreate DomTokenList
diff --git a/src/cobalt/dom/element.h b/src/cobalt/dom/element.h
index 9176493..2c33a1e 100644
--- a/src/cobalt/dom/element.h
+++ b/src/cobalt/dom/element.h
@@ -84,8 +84,7 @@
     SetAttribute("class", value);
   }
 
-  scoped_refptr<DOMTokenList> class_list();
-
+  const scoped_refptr<DOMTokenList>& class_list();
   scoped_refptr<NamedNodeMap> attributes();
 
   base::optional<std::string> GetAttribute(const std::string& name) const;
diff --git a/src/cobalt/dom/element_test.cc b/src/cobalt/dom/element_test.cc
index f2ea69d..30acb76 100644
--- a/src/cobalt/dom/element_test.cc
+++ b/src/cobalt/dom/element_test.cc
@@ -305,13 +305,6 @@
   EXPECT_EQ(std::string("d"), class_list->Item(1));
   EXPECT_EQ(std::string("c"), class_list->Item(2));
   EXPECT_EQ(base::nullopt, class_list->Item(3));
-
-  // Custom, not in any spec
-  // NonNullItem
-  EXPECT_EQ(std::string("b"), class_list->NonNullItem(0));
-  EXPECT_EQ(std::string("d"), class_list->NonNullItem(1));
-  EXPECT_EQ(std::string("c"), class_list->NonNullItem(2));
-  EXPECT_EQ(std::string(""), class_list->NonNullItem(3));
 }
 
 TEST_F(ElementTest, GetElementsByClassName) {
diff --git a/src/cobalt/dom/font_list.cc b/src/cobalt/dom/font_list.cc
index ea90d51..f91dc45 100644
--- a/src/cobalt/dom/font_list.cc
+++ b/src/cobalt/dom/font_list.cc
@@ -169,16 +169,7 @@
 }
 
 float FontList::GetSpaceWidth() {
-  // The space width is lazily generated. If it hasn't been set yet, it's time
-  // to set it.
-  if (!is_space_width_set_) {
-    is_space_width_set_ = true;
-    const scoped_refptr<render_tree::Font>& primary_font = GetPrimaryFont();
-    render_tree::GlyphIndex space_glyph =
-        primary_font->GetGlyphForCharacter(' ');
-    space_width_ = primary_font->GetGlyphWidth(space_glyph);
-  }
-
+  GenerateSpaceWidth();
   return space_width_;
 }
 
@@ -292,10 +283,23 @@
 
 void FontList::GenerateEllipsisInfo() {
   if (!is_ellipsis_info_set_) {
-    is_ellipsis_info_set_ = true;
     render_tree::GlyphIndex ellipsis_glyph = render_tree::kInvalidGlyphIndex;
     ellipsis_font_ = GetCharacterFont(GetEllipsisValue(), &ellipsis_glyph);
     ellipsis_width_ = ellipsis_font_->GetGlyphWidth(ellipsis_glyph);
+
+    is_ellipsis_info_set_ = true;
+  }
+}
+
+void FontList::GenerateSpaceWidth() {
+  if (!is_space_width_set_) {
+    const scoped_refptr<render_tree::Font>& primary_font = GetPrimaryFont();
+    render_tree::GlyphIndex space_glyph =
+        primary_font->GetGlyphForCharacter(' ');
+    space_width_ = primary_font->GetGlyphWidth(space_glyph);
+    DCHECK_GT(space_width_, 0);
+
+    is_space_width_set_ = true;
   }
 }
 
diff --git a/src/cobalt/dom/font_list.h b/src/cobalt/dom/font_list.h
index 555b871..af2cdde 100644
--- a/src/cobalt/dom/font_list.h
+++ b/src/cobalt/dom/font_list.h
@@ -156,7 +156,7 @@
   // the width has not already been calculated, it lazily generates it.
   float GetEllipsisWidth();
 
-  // Returns the width of the space in the firts font in the font list that
+  // Returns the width of the space in the first font in the font list that
   // supports the space character. In the case where the width has not already
   // been calculated, it lazily generates it.
   float GetSpaceWidth();
@@ -194,10 +194,14 @@
   // |font_| and |character_map_| are non-NULL after this call.
   void RequestFont(size_t index);
 
-  // Lazily generates the ellipsis ellipsis font and ellipsis width. If the info
-  // is already generated, it is immediately returned.
+  // Lazily generates the ellipsis font and ellipsis width. If it is already
+  // generated then it immediately returns.
   void GenerateEllipsisInfo();
 
+  // Lazily generates the space width. If it is already generated then it
+  // immediately returns.
+  void GenerateSpaceWidth();
+
   // The font cache, which provides both font family fonts and character
   // fallback fonts to the font list.
   FontCache* const font_cache_;
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc
index 0d57ebd..2ed74fd 100644
--- a/src/cobalt/dom/html_element.cc
+++ b/src/cobalt/dom/html_element.cc
@@ -394,7 +394,10 @@
   // ancestors.
   scoped_refptr<HTMLElement> offset_parent_html_element =
       offset_parent_element->AsHTMLElement();
-  DCHECK(offset_parent_html_element);
+  if (!offset_parent_html_element) {
+    return layout_boxes_->GetBorderEdgeTop();
+  }
+
   DCHECK(offset_parent_html_element->layout_boxes());
   return layout_boxes_->GetBorderEdgeTop() -
          offset_parent_html_element->layout_boxes()->GetPaddingEdgeTop();
@@ -430,7 +433,10 @@
   // ancestors.
   scoped_refptr<HTMLElement> offset_parent_html_element =
       offset_parent_element->AsHTMLElement();
-  DCHECK(offset_parent_html_element);
+  if (!offset_parent_html_element) {
+    return layout_boxes_->GetBorderEdgeLeft();
+  }
+
   DCHECK(offset_parent_html_element->layout_boxes());
   return layout_boxes_->GetBorderEdgeLeft() -
          offset_parent_html_element->layout_boxes()->GetPaddingEdgeLeft();
@@ -600,8 +606,9 @@
   for (Element* element = first_element_child(); element;
        element = element->next_element_sibling()) {
     HTMLElement* html_element = element->AsHTMLElement();
-    DCHECK(html_element);
-    html_element->InvalidateMatchingRulesRecursively();
+    if (html_element) {
+      html_element->InvalidateMatchingRulesRecursively();
+    }
   }
 
   // Invalidate matching rules on all following siblings if sibling combinators
@@ -610,8 +617,9 @@
     for (Element* element = next_element_sibling(); element;
          element = element->next_element_sibling()) {
       HTMLElement* html_element = element->AsHTMLElement();
-      DCHECK(html_element);
-      html_element->InvalidateMatchingRulesRecursively();
+      if (html_element) {
+        html_element->InvalidateMatchingRulesRecursively();
+      }
     }
   }
 }
@@ -646,10 +654,11 @@
   for (Element* element = first_element_child(); element;
        element = element->next_element_sibling()) {
     HTMLElement* html_element = element->AsHTMLElement();
-    DCHECK(html_element);
-    html_element->UpdateComputedStyleRecursively(
-        css_computed_style_declaration(), root_computed_style,
-        style_change_event_time, is_valid);
+    if (html_element) {
+      html_element->UpdateComputedStyleRecursively(
+          css_computed_style_declaration(), root_computed_style,
+          style_change_event_time, is_valid);
+    }
   }
 }
 
diff --git a/src/cobalt/dom/html_element.h b/src/cobalt/dom/html_element.h
index 5e7fcae..2075d05 100644
--- a/src/cobalt/dom/html_element.h
+++ b/src/cobalt/dom/html_element.h
@@ -91,10 +91,14 @@
 //   https://www.w3.org/TR/html5/dom.html#htmlelement
 class HTMLElement : public Element, public cssom::MutationObserver {
  public:
+  typedef cssom::SelectorTree::NodeSet<12> MatchingNodes;
+  typedef cssom::SelectorTree::NodeSet<40> DescendantPotentialNodes;
+  typedef cssom::SelectorTree::NodeSet<8> FollowingSiblingPotentialNodes;
+
   struct RuleMatchingState {
-    cssom::SelectorTree::NodeSet<12> matching_nodes;
-    cssom::SelectorTree::NodeSet<40> descendant_potential_nodes;
-    cssom::SelectorTree::NodeSet<8> following_sibling_potential_nodes;
+    MatchingNodes matching_nodes;
+    DescendantPotentialNodes descendant_potential_nodes;
+    FollowingSiblingPotentialNodes following_sibling_potential_nodes;
   };
 
   // Web API: HTMLElement
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index 4f1bb38..3d7a596 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -497,6 +497,7 @@
     media_source_->SetPlayer(player_.get());
   }
   node_document()->OnDOMMutation();
+  InvalidateLayoutBoxesFromNodeAndAncestors();
 }
 
 void HTMLMediaElement::ScheduleLoad() {
diff --git a/src/cobalt/dom/html_video_element.cc b/src/cobalt/dom/html_video_element.cc
index 89d0f1e..1d25415 100644
--- a/src/cobalt/dom/html_video_element.cc
+++ b/src/cobalt/dom/html_video_element.cc
@@ -23,6 +23,7 @@
 namespace dom {
 
 using ::media::ShellVideoFrameProvider;
+using ::media::WebMediaPlayer;
 
 const char HTMLVideoElement::kTagName[] = "video";
 
@@ -88,5 +89,9 @@
   return player() ? player()->GetVideoFrameProvider() : NULL;
 }
 
+WebMediaPlayer::SetBoundsCB HTMLVideoElement::GetSetBoundsCB() {
+  return player() ? player()->GetSetBoundsCB() : WebMediaPlayer::SetBoundsCB();
+}
+
 }  // namespace dom
 }  // namespace cobalt
diff --git a/src/cobalt/dom/html_video_element.h b/src/cobalt/dom/html_video_element.h
index 2ac5c3f..d9f0953 100644
--- a/src/cobalt/dom/html_video_element.h
+++ b/src/cobalt/dom/html_video_element.h
@@ -21,6 +21,7 @@
 
 #include "cobalt/dom/html_media_element.h"
 #include "cobalt/dom/video_playback_quality.h"
+#include "cobalt/math/rect.h"
 #include "media/base/shell_video_frame_provider.h"
 
 namespace cobalt {
@@ -56,6 +57,8 @@
   // a better way to support concurrent video playbacks.
   scoped_refptr<ShellVideoFrameProvider> GetVideoFrameProvider();
 
+  WebMediaPlayer::SetBoundsCB GetSetBoundsCB();
+
   DEFINE_WRAPPABLE_TYPE(HTMLVideoElement);
 
  private:
diff --git a/src/cobalt/dom/node.cc b/src/cobalt/dom/node.cc
index 041836c..59aed34 100644
--- a/src/cobalt/dom/node.cc
+++ b/src/cobalt/dom/node.cc
@@ -139,10 +139,12 @@
 //   https://www.w3.org/TR/2015/WD-dom-20150618/#dom-node-clonenode
 scoped_refptr<Node> Node::CloneNode(bool deep) const {
   scoped_refptr<Node> new_node = Duplicate();
+  DCHECK(new_node);
   if (deep) {
     scoped_refptr<Node> child = first_child_;
     while (child) {
       scoped_refptr<Node> new_child = child->CloneNode(true);
+      DCHECK(new_child);
       new_node->AppendChild(new_child);
       child = child->next_sibling_;
     }
diff --git a/src/cobalt/dom/rule_matching.cc b/src/cobalt/dom/rule_matching.cc
index 7dc27d3..411223f 100644
--- a/src/cobalt/dom/rule_matching.cc
+++ b/src/cobalt/dom/rule_matching.cc
@@ -17,6 +17,7 @@
 #include "cobalt/dom/rule_matching.h"
 
 #include <algorithm>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -169,8 +170,7 @@
   // tree.
   //   https://www.w3.org/TR/selectors4/#type-selector
   void VisitTypeSelector(cssom::TypeSelector* type_selector) OVERRIDE {
-    if (!LowerCaseEqualsASCII(type_selector->element_name().c_str(),
-                              element_->tag_name().c_str())) {
+    if (type_selector->element_name() != element_->tag_name()) {
       element_ = NULL;
     }
   }
@@ -259,6 +259,7 @@
   void VisitCompoundSelector(
       cssom::CompoundSelector* compound_selector) OVERRIDE {
     DCHECK_GT(compound_selector->simple_selectors().size(), 0U);
+
     // Iterate through all the simple selectors. If any of the simple selectors
     // doesn't match, the compound selector doesn't match.
     for (cssom::CompoundSelector::SimpleSelectors::const_iterator
@@ -305,6 +306,7 @@
   if (!element) {
     return NULL;
   }
+
   SelectorMatcher selector_matcher(element, matching_combinators);
   selector->Accept(&selector_matcher);
   return selector_matcher.element();
@@ -364,12 +366,10 @@
 void GatherCandidateNodesFromMap(
     cssom::SimpleSelectorType simple_selector_type,
     cssom::CombinatorType combinator_type,
-    const SelectorTree::SelectorTextToNodesMap& map, base::Token key,
+    const SelectorTree::SelectorTextToNodesMap* map, base::Token key,
     SelectorTree::NodeSet<kRuleMatchingNodeSetSize>* candidate_nodes) {
-  // TODO: The hit rate here is only ~20%, use a Token specific map
-  // to pre-check if the key is in the map.
-  SelectorTree::SelectorTextToNodesMap::const_iterator it = map.find(key);
-  if (it != map.end()) {
+  SelectorTree::SelectorTextToNodesMap::const_iterator it = map->find(key);
+  if (it != map->end()) {
     const SelectorTree::SimpleSelectorNodes& nodes = it->second;
     for (SelectorTree::SimpleSelectorNodes::const_iterator nodes_iterator =
              nodes.begin();
@@ -403,6 +403,12 @@
     HTMLElement* element,
     base::Callback<void(HTMLElement* element, const SelectorTree::Node*)>
         callback) {
+  // Gathering Phase: Generate candidate nodes from the node set.
+  SelectorTree::NodeSet<kRuleMatchingNodeSetSize> candidate_nodes;
+
+  const std::vector<base::Token>& element_class_list =
+      element->class_list()->GetTokens();
+
   // Iterate through all nodes in node_set.
   for (typename NodeSet::const_iterator node_iterator = node_set.begin();
        node_iterator != node_set.end(); ++node_iterator) {
@@ -412,72 +418,87 @@
       continue;
     }
 
-    SelectorTree::NodeSet<kRuleMatchingNodeSetSize> candidate_nodes;
-
     // Gather candidate sets in node's children under the given combinator.
 
-    // Universal selector.
-    if (node->HasSimpleSelector(cssom::kUniversalSelector, combinator_type)) {
-      GatherCandidateNodesFromMap(cssom::kUniversalSelector, combinator_type,
-                                  node->selector_nodes_map(), base::Token(),
-                                  &candidate_nodes);
-    }
+    const SelectorTree::SelectorTextToNodesMap* selector_nodes_map =
+        node->selector_nodes_map();
+    if (selector_nodes_map) {
+      // Universal selector.
+      if (node->HasSimpleSelector(cssom::kUniversalSelector, combinator_type)) {
+        GatherCandidateNodesFromMap(cssom::kUniversalSelector, combinator_type,
+                                    selector_nodes_map, base::Token(),
+                                    &candidate_nodes);
+      }
 
-    // Type selector.
-    if (node->HasSimpleSelector(cssom::kTypeSelector, combinator_type)) {
-      GatherCandidateNodesFromMap(cssom::kTypeSelector, combinator_type,
-                                  node->selector_nodes_map(),
-                                  element->tag_name(), &candidate_nodes);
-    }
+      // Type selector.
+      if (node->HasSimpleSelector(cssom::kTypeSelector, combinator_type)) {
+        GatherCandidateNodesFromMap(cssom::kTypeSelector, combinator_type,
+                                    selector_nodes_map, element->tag_name(),
+                                    &candidate_nodes);
+      }
 
-    // Class selector.
-    if (node->HasSimpleSelector(cssom::kClassSelector, combinator_type)) {
-      scoped_refptr<DOMTokenList> class_list = element->class_list();
-      for (unsigned int index = 0; index < class_list->length(); ++index) {
-        GatherCandidateNodesFromMap(
-            cssom::kClassSelector, combinator_type, node->selector_nodes_map(),
-            class_list->NonNullItem(index), &candidate_nodes);
+      // Class selector.
+      if (node->HasSimpleSelector(cssom::kClassSelector, combinator_type)) {
+        for (size_t index = 0; index < element_class_list.size(); ++index) {
+          GatherCandidateNodesFromMap(
+              cssom::kClassSelector, combinator_type, selector_nodes_map,
+              element_class_list[index], &candidate_nodes);
+        }
+      }
+
+      // Id selector.
+      if (node->HasSimpleSelector(cssom::kIdSelector, combinator_type)) {
+        GatherCandidateNodesFromMap(cssom::kIdSelector, combinator_type,
+                                    selector_nodes_map, element->id(),
+                                    &candidate_nodes);
       }
     }
 
-    // Id selector.
-    if (node->HasSimpleSelector(cssom::kIdSelector, combinator_type)) {
-      GatherCandidateNodesFromMap(cssom::kIdSelector, combinator_type,
-                                  node->selector_nodes_map(), element->id(),
-                                  &candidate_nodes);
-    }
-
-    // Empty pseudo class.
-    if (node->HasPseudoClass(cssom::kEmptyPseudoClass, combinator_type) &&
-        element->IsEmpty()) {
-      GatherCandidateNodesFromSet(cssom::kEmptyPseudoClass, combinator_type,
-                                  node->pseudo_class_nodes(), &candidate_nodes);
-    }
-
-    // Focus pseudo class.
-    if (node->HasPseudoClass(cssom::kFocusPseudoClass, combinator_type) &&
-        element->HasFocus()) {
-      GatherCandidateNodesFromSet(cssom::kFocusPseudoClass, combinator_type,
-                                  node->pseudo_class_nodes(), &candidate_nodes);
-    }
-
-    // Not pseudo class.
-    if (node->HasPseudoClass(cssom::kNotPseudoClass, combinator_type)) {
-      GatherCandidateNodesFromSet(cssom::kNotPseudoClass, combinator_type,
-                                  node->pseudo_class_nodes(), &candidate_nodes);
-    }
-
-    // Check all candidate nodes and run callback for matching nodes.
-    for (SelectorTree::NodeSet<kRuleMatchingNodeSetSize>::const_iterator
-             candidate_node_iterator = candidate_nodes.begin();
-         candidate_node_iterator != candidate_nodes.end();
-         ++candidate_node_iterator) {
-      const SelectorTree::Node* candidate_node = *candidate_node_iterator;
-
-      if (MatchSelectorAndElement(candidate_node->compound_selector(), element,
-                                  false)) {
-        callback.Run(element, candidate_node);
+    if (node->HasAnyPseudoClass()) {
+      // Empty pseudo class.
+      if (node->HasPseudoClass(cssom::kEmptyPseudoClass, combinator_type) &&
+          element->IsEmpty()) {
+        GatherCandidateNodesFromSet(cssom::kEmptyPseudoClass, combinator_type,
+                                    node->pseudo_class_nodes(),
+                                    &candidate_nodes);
       }
+
+      // Focus pseudo class.
+      if (node->HasPseudoClass(cssom::kFocusPseudoClass, combinator_type) &&
+          element->HasFocus()) {
+        GatherCandidateNodesFromSet(cssom::kFocusPseudoClass, combinator_type,
+                                    node->pseudo_class_nodes(),
+                                    &candidate_nodes);
+      }
+
+      // Not pseudo class.
+      if (node->HasPseudoClass(cssom::kNotPseudoClass, combinator_type)) {
+        GatherCandidateNodesFromSet(cssom::kNotPseudoClass, combinator_type,
+                                    node->pseudo_class_nodes(),
+                                    &candidate_nodes);
+      }
+    }
+  }
+
+  // Verifying Phase: Check all candidate nodes and run callback for matching
+  // nodes.
+  for (SelectorTree::NodeSet<kRuleMatchingNodeSetSize>::const_iterator
+           candidate_node_iterator = candidate_nodes.begin();
+       candidate_node_iterator != candidate_nodes.end();
+       ++candidate_node_iterator) {
+    const SelectorTree::Node* candidate_node = *candidate_node_iterator;
+
+    // Verify that this node is a match:
+    // 1. If the candidate node's compound selector doesn't require a visit to
+    //    verify the match, then the act of gathering the node as a candidate
+    //    proved the match.
+    // 2. Otherwise, the node requires additional verification checks, so call
+    //    MatchSelectorAndElement().
+    if (!candidate_node->compound_selector()
+             ->requires_rule_matching_verification_visit() ||
+        MatchSelectorAndElement(candidate_node->compound_selector(), element,
+                                false)) {
+      callback.Run(element, candidate_node);
     }
   }
 }
@@ -559,9 +580,20 @@
     current_element->rule_matching_state()->descendant_potential_nodes.insert(
         selector_tree->root());
   }
-  current_element->rule_matching_state()->descendant_potential_nodes.insert(
-      current_element->rule_matching_state()->matching_nodes.begin(),
-      current_element->rule_matching_state()->matching_nodes.end());
+  // Walk all of the matching nodes, adding any that have a descendant
+  // combinator as a descendant potential node. Any missing that combinator can
+  // never match descendants.
+  for (dom::HTMLElement::MatchingNodes::const_iterator iter =
+           current_element->rule_matching_state()->matching_nodes.begin();
+       iter != current_element->rule_matching_state()->matching_nodes.end();
+       ++iter) {
+    if ((*iter)->HasCombinator(cssom::kDescendantCombinator)) {
+      // It is possible for the two lists to contain duplicate nodes, so only
+      // add the node if it isn't a duplicate.
+      current_element->rule_matching_state()->descendant_potential_nodes.insert(
+          *iter, true /*check_for_duplicate*/);
+    }
+  }
 
   // Calculate current element's following sibling potential nodes.
   if (selector_tree->has_sibling_combinators()) {
@@ -573,10 +605,21 @@
               previous_sibling->rule_matching_state()
                   ->following_sibling_potential_nodes.end());
     }
-    current_element->rule_matching_state()
-        ->following_sibling_potential_nodes.insert(
-            current_element->rule_matching_state()->matching_nodes.begin(),
-            current_element->rule_matching_state()->matching_nodes.end());
+    // Walk all of the matching nodes, adding any that have a following sibling
+    // combinator as a following sibling potential node. Any missing that
+    // combinator can never match following siblings..
+    for (dom::HTMLElement::MatchingNodes::const_iterator iter =
+             current_element->rule_matching_state()->matching_nodes.begin();
+         iter != current_element->rule_matching_state()->matching_nodes.end();
+         ++iter) {
+      if ((*iter)->HasCombinator(cssom::kFollowingSiblingCombinator)) {
+        // It is possible for the two lists to contain duplicate nodes, so only
+        // add the node if it isn't a duplicate.
+        current_element->rule_matching_state()
+            ->following_sibling_potential_nodes.insert(
+                *iter, true /*check_for_duplicate*/);
+      }
+    }
   }
 }
 
diff --git a/src/cobalt/dom/time_ranges_test.cc b/src/cobalt/dom/time_ranges_test.cc
index d31023a..4404477 100644
--- a/src/cobalt/dom/time_ranges_test.cc
+++ b/src/cobalt/dom/time_ranges_test.cc
@@ -30,15 +30,10 @@
     dom_exception_ = make_scoped_refptr(
         base::polymorphic_downcast<DOMException*>(exception.get()));
   }
-  void SetSimpleException(
-      script::ExceptionState::SimpleExceptionType simple_exception_type,
-      const std::string& message) OVERRIDE {
-    simple_exception_ = simple_exception_type;
-    simple_exception_message_ = message;
+  void SetSimpleException(script::MessageType /*message_type*/, ...) OVERRIDE {
+    // no-op
   }
   scoped_refptr<DOMException> dom_exception_;
-  script::ExceptionState::SimpleExceptionType simple_exception_;
-  std::string simple_exception_message_;
 };
 }  // namespace
 
diff --git a/src/cobalt/dom/typed_array.h b/src/cobalt/dom/typed_array.h
index 8cafc15..266e002 100644
--- a/src/cobalt/dom/typed_array.h
+++ b/src/cobalt/dom/typed_array.h
@@ -68,10 +68,8 @@
              script::ExceptionState* exception_state)
       : ArrayBufferView(buffer) {
     if (buffer->byte_length() % kBytesPerElement != 0) {
-      exception_state->SetSimpleException(
-          script::ExceptionState::kRangeError,
-          base::StringPrintf("Byte length should be a multiple of %d",
-                             kBytesPerElement));
+      exception_state->SetSimpleException(script::kWrongByteLengthMultiple,
+                                          kBytesPerElement);
     }
   }
 
@@ -80,15 +78,11 @@
       : ArrayBufferView(buffer, byte_offset,
                         buffer->byte_length() - byte_offset) {
     if (this->byte_offset() % kBytesPerElement != 0) {
-      exception_state->SetSimpleException(
-          script::ExceptionState::kRangeError,
-          base::StringPrintf("Byte offset should be a multiple of %d",
-                             kBytesPerElement));
+      exception_state->SetSimpleException(script::kWrongByteOffsetMultiple,
+                                          kBytesPerElement);
     } else if (buffer->byte_length() % kBytesPerElement != 0) {
-      exception_state->SetSimpleException(
-          script::ExceptionState::kRangeError,
-          base::StringPrintf("Byte length should be a multiple of %d",
-                             kBytesPerElement));
+      exception_state->SetSimpleException(script::kWrongByteLengthMultiple,
+                                          kBytesPerElement);
     }
   }
 
@@ -96,14 +90,11 @@
              uint32 length, script::ExceptionState* exception_state)
       : ArrayBufferView(buffer, byte_offset, length * kBytesPerElement) {
     if (this->byte_offset() % kBytesPerElement != 0) {
-      exception_state->SetSimpleException(
-          script::ExceptionState::kRangeError,
-          base::StringPrintf("Byte offset should be a multiple of %d",
-                             kBytesPerElement));
+      exception_state->SetSimpleException(script::kWrongByteOffsetMultiple,
+                                          kBytesPerElement);
     } else if (byte_offset + length * kBytesPerElement >
                buffer->byte_length()) {
-      exception_state->SetSimpleException(script::ExceptionState::kRangeError,
-                                          "Invalid typed array length");
+      exception_state->SetSimpleException(script::kInvalidLength);
     }
   }
 
@@ -127,8 +118,7 @@
   void Set(const scoped_refptr<TypedArray>& source, uint32 offset,
            script::ExceptionState* exception_state) {
     if (offset >= length() || length() - offset < source->length()) {
-      exception_state->SetSimpleException(script::ExceptionState::kRangeError,
-                                          "Source is too large");
+      exception_state->SetSimpleException(script::kInvalidLength);
       return;
     }
     uint32 source_offset = 0;
@@ -239,6 +229,6 @@
                                                                                \
    private:                                                                    \
     DISALLOW_COPY_AND_ASSIGN(SubarrayType);                                    \
-  }
+  };
 
 #endif  // COBALT_DOM_TYPED_ARRAY_H_
diff --git a/src/cobalt/dom/typed_array_test.cc b/src/cobalt/dom/typed_array_test.cc
index a305942..3f627c5 100644
--- a/src/cobalt/dom/typed_array_test.cc
+++ b/src/cobalt/dom/typed_array_test.cc
@@ -337,10 +337,10 @@
   }
 
   StrictMock<MockExceptionState> exception_state;
-  script::ExceptionState::SimpleExceptionType exception_type;
+  script::MessageType message_type;
 
-  EXPECT_CALL(exception_state, SetSimpleException(_, _))
-      .WillOnce(SaveArg<0>(&exception_type));
+  EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))
+      .WillOnce(SaveArg<0>(&message_type));
 
   // Create an ArrayBuffer whose size isn't a multiple of
   // TypeParam::kBytesPerElement.
@@ -350,30 +350,30 @@
   // TypeParam::kBytesPerElement.
   scoped_refptr<TypeParam> array =
       new TypeParam(NULL, array_buffer, &exception_state);
-  EXPECT_EQ(script::ExceptionState::kRangeError, exception_type);
+  EXPECT_EQ(script::kRangeError, GetSimpleExceptionType(message_type));
 
-  EXPECT_CALL(exception_state, SetSimpleException(_, _))
-      .WillOnce(SaveArg<0>(&exception_type));
+  EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))
+      .WillOnce(SaveArg<0>(&message_type));
   // Neither the size of the array_buffer nor the byte_offset is a multiple of
   // TypeParam::kBytesPerElement, but SetSimpleException() should only be called
   // once.
   array = new TypeParam(NULL, array_buffer, 1, &exception_state);
-  EXPECT_EQ(script::ExceptionState::kRangeError, exception_type);
+  EXPECT_EQ(script::kRangeError, GetSimpleExceptionType(message_type));
 
-  EXPECT_CALL(exception_state, SetSimpleException(_, _))
-      .WillOnce(SaveArg<0>(&exception_type));
+  EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))
+      .WillOnce(SaveArg<0>(&message_type));
   // Now the size of the array_buffer is a multiple of
   // TypeParam::kBytesPerElement but the byte_offset isn't.
   array_buffer = new ArrayBuffer(NULL, TypeParam::kBytesPerElement);
   array = new TypeParam(NULL, array_buffer, 1, &exception_state);
-  EXPECT_EQ(script::ExceptionState::kRangeError, exception_type);
+  EXPECT_EQ(script::kRangeError, GetSimpleExceptionType(message_type));
 
-  EXPECT_CALL(exception_state, SetSimpleException(_, _))
-      .WillOnce(SaveArg<0>(&exception_type));
+  EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))
+      .WillOnce(SaveArg<0>(&message_type));
   // Both the size of the array_buffer and the byte_offset are multiples of
   // TypeParam::kBytesPerElement but array_buffer cannot hold 2 elements.
   array = new TypeParam(NULL, array_buffer, 0, 2, &exception_state);
-  EXPECT_EQ(script::ExceptionState::kRangeError, exception_type);
+  EXPECT_EQ(script::kRangeError, GetSimpleExceptionType(message_type));
 
   // The size of the array_buffer isn't a multiple of
   // TypeParam::kBytesPerElement but the byte_offset is.  Also the whole typed
@@ -391,10 +391,10 @@
   }
 
   StrictMock<MockExceptionState> exception_state;
-  script::ExceptionState::SimpleExceptionType exception_type;
+  script::MessageType message_type;
 
-  EXPECT_CALL(exception_state, SetSimpleException(_, _))
-      .WillOnce(SaveArg<0>(&exception_type));
+  EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))
+      .WillOnce(SaveArg<0>(&message_type));
 
   static const uint32 kLength = 5;
   scoped_refptr<TypeParam> source =
@@ -402,14 +402,14 @@
   scoped_refptr<TypeParam> dest =
       new TypeParam(NULL, kLength, &exception_state);
   dest->Set(source, &exception_state);
-  EXPECT_EQ(script::ExceptionState::kRangeError, exception_type);
+  EXPECT_EQ(script::kRangeError, GetSimpleExceptionType(message_type));
 
-  EXPECT_CALL(exception_state, SetSimpleException(_, _))
-      .WillOnce(SaveArg<0>(&exception_type));
+  EXPECT_CALL(exception_state, SetSimpleExceptionVA(_, _))
+      .WillOnce(SaveArg<0>(&message_type));
   source = new TypeParam(NULL, kLength, &exception_state);
   dest = new TypeParam(NULL, kLength + 1, &exception_state);
   dest->Set(source, 2, &exception_state);
-  EXPECT_EQ(script::ExceptionState::kRangeError, exception_type);
+  EXPECT_EQ(script::kRangeError, GetSimpleExceptionType(message_type));
 
   dest->Set(source, 1, &exception_state);
 }
diff --git a/src/cobalt/dom_parser/html_decoder.cc b/src/cobalt/dom_parser/html_decoder.cc
index ec744b2..ddda365 100644
--- a/src/cobalt/dom_parser/html_decoder.cc
+++ b/src/cobalt/dom_parser/html_decoder.cc
@@ -28,12 +28,12 @@
     const scoped_refptr<dom::Document>& document,
     const scoped_refptr<dom::Node>& parent_node,
     const scoped_refptr<dom::Node>& reference_node,
-    const base::SourceLocation& input_location,
+    const int dom_max_element_depth, const base::SourceLocation& input_location,
     const base::Closure& done_callback,
     const base::Callback<void(const std::string&)>& error_callback)
-    : libxml_html_parser_wrapper_(
-          new LibxmlHTMLParserWrapper(document, parent_node, reference_node,
-                                      input_location, error_callback)),
+    : libxml_html_parser_wrapper_(new LibxmlHTMLParserWrapper(
+          document, parent_node, reference_node, dom_max_element_depth,
+          input_location, error_callback)),
       document_(document),
       done_callback_(done_callback) {}
 
diff --git a/src/cobalt/dom_parser/html_decoder.h b/src/cobalt/dom_parser/html_decoder.h
index 370184f..853fd47 100644
--- a/src/cobalt/dom_parser/html_decoder.h
+++ b/src/cobalt/dom_parser/html_decoder.h
@@ -46,6 +46,7 @@
   HTMLDecoder(const scoped_refptr<dom::Document>& document,
               const scoped_refptr<dom::Node>& parent_node,
               const scoped_refptr<dom::Node>& reference_node,
+              const int dom_max_element_depth,
               const base::SourceLocation& input_location,
               const base::Closure& done_callback,
               const base::Callback<void(const std::string&)>& error_callback);
diff --git a/src/cobalt/dom_parser/html_decoder_test.cc b/src/cobalt/dom_parser/html_decoder_test.cc
index d9ca19a..e00a271 100644
--- a/src/cobalt/dom_parser/html_decoder_test.cc
+++ b/src/cobalt/dom_parser/html_decoder_test.cc
@@ -36,6 +36,8 @@
 namespace cobalt {
 namespace dom_parser {
 
+const int kDOMMaxElementDepth = 32;
+
 class MockErrorCallback : public base::Callback<void(const std::string&)> {
  public:
   MOCK_METHOD1(Run, void(const std::string&));
@@ -78,9 +80,9 @@
 TEST_F(HTMLDecoderTest, CanParseEmptyDocument) {
   const std::string input = "";
   html_decoder_.reset(new HTMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -100,9 +102,9 @@
   unsigned char temp[] = {0x0, 0x0};
 
   html_decoder_.reset(new HTMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(reinterpret_cast<char*>(temp), sizeof(temp));
   html_decoder_->Finish();
 
@@ -118,9 +120,9 @@
 TEST_F(HTMLDecoderTest, DISABLED_CanParseDocumentWithOnlySpaces) {
   const std::string input = "   ";
   html_decoder_.reset(new HTMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -136,9 +138,9 @@
 TEST_F(HTMLDecoderTest, DISABLED_CanParseDocumentWithOnlyHTML) {
   const std::string input = "<html>";
   html_decoder_.reset(new HTMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -154,9 +156,9 @@
 TEST_F(HTMLDecoderTest, CanParseDocumentWithOnlyBody) {
   const std::string input = "<body>";
   html_decoder_.reset(new HTMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -172,9 +174,9 @@
 TEST_F(HTMLDecoderTest, DecodingWholeDocumentShouldAddImpliedTags) {
   const std::string input = "<p></p>";
   html_decoder_.reset(new HTMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -194,10 +196,10 @@
 
 TEST_F(HTMLDecoderTest, DecodingDocumentFragmentShouldNotAddImpliedTags) {
   const std::string input = "<p></p>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -209,10 +211,10 @@
 
 TEST_F(HTMLDecoderTest, CanParseAttributesWithAndWithoutValue) {
   const std::string input = "<div a b=2 c d></div>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -233,10 +235,10 @@
 
 TEST_F(HTMLDecoderTest, CanParseIncompleteAttributesAssignment) {
   const std::string input = "<div a= b=2 c=></div>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -253,10 +255,10 @@
 
 TEST_F(HTMLDecoderTest, CanParseSelfClosingTags) {
   const std::string input = "<p><p>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -271,10 +273,10 @@
 
 TEST_F(HTMLDecoderTest, CanParseNormalCharacters) {
   const std::string input = "<p>text</p>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -290,10 +292,10 @@
 TEST_F(HTMLDecoderTest, ShouldIgnoreNonUTF8Input) {
   unsigned char temp[] = {0xff, 0xff};
 
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(reinterpret_cast<char*>(temp), sizeof(temp));
   html_decoder_->Finish();
 
@@ -303,10 +305,10 @@
 // Test a decimal and hex escaped supplementary (not in BMP) character.
 TEST_F(HTMLDecoderTest, CanParseEscapedCharacters) {
   const std::string input = "<p>&#128169;</p><p>&#x1f4a9;</p>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -330,10 +332,10 @@
 // Test an escaped invalid Unicode character.
 TEST_F(HTMLDecoderTest, CanParseEscapedInvalidUnicodeCharacters) {
   const std::string input = "<p>&#xe62b;</p>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -349,10 +351,10 @@
 // Test a UTF8 encoded supplementary (not in BMP) character.
 TEST_F(HTMLDecoderTest, CanParseUTF8EncodedSupplementaryCharacters) {
   const std::string input = "<p>💩</p>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -371,10 +373,10 @@
 // The current version DOES NOT handle the error as outlined in the link above.
 TEST_F(HTMLDecoderTest, CanParseMisnestedTags1) {
   const std::string input = "<p>1<b>2<i>3</b>4</i>5</p>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -397,10 +399,10 @@
 // The current version DOES NOT handle the error as outlined in the link above.
 TEST_F(HTMLDecoderTest, CanParseMisnestedTags2) {
   const std::string input = "<b>1<p>2</b>3</p>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -415,10 +417,10 @@
 
 TEST_F(HTMLDecoderTest, TagNamesShouldBeCaseInsensitive) {
   const std::string input = "<DIV></DIV>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -429,10 +431,10 @@
 
 TEST_F(HTMLDecoderTest, AttributesShouldBeCaseInsensitive) {
   const std::string input = "<div A></div>";
-  html_decoder_.reset(
-      new HTMLDecoder(document_, root_, NULL, source_location_, base::Closure(),
-                      base::Bind(&MockErrorCallback::Run,
-                                 base::Unretained(&mock_error_callback_))));
+  html_decoder_.reset(new HTMLDecoder(
+      document_, root_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
@@ -453,9 +455,9 @@
       "<body>陈绮贞</body>"
       "</html>";
   html_decoder_.reset(new HTMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   html_decoder_->DecodeChunk(input.c_str(), input.length());
   html_decoder_->Finish();
 
diff --git a/src/cobalt/dom_parser/libxml_html_parser_wrapper.h b/src/cobalt/dom_parser/libxml_html_parser_wrapper.h
index 24bb4cb..f553818 100644
--- a/src/cobalt/dom_parser/libxml_html_parser_wrapper.h
+++ b/src/cobalt/dom_parser/libxml_html_parser_wrapper.h
@@ -38,10 +38,12 @@
       const scoped_refptr<dom::Document>& document,
       const scoped_refptr<dom::Node>& parent_node,
       const scoped_refptr<dom::Node>& reference_node,
+      const int dom_max_element_depth,
       const base::SourceLocation& input_location,
       const base::Callback<void(const std::string&)>& error_callback)
       : LibxmlParserWrapper(document, parent_node, reference_node,
-                            input_location, error_callback),
+                            dom_max_element_depth, input_location,
+                            error_callback),
         html_parser_context_(NULL) {
     DCHECK(!document->IsXMLDocument());
   }
diff --git a/src/cobalt/dom_parser/libxml_parser_wrapper.cc b/src/cobalt/dom_parser/libxml_parser_wrapper.cc
index 993e453..3acaf88 100644
--- a/src/cobalt/dom_parser/libxml_parser_wrapper.cc
+++ b/src/cobalt/dom_parser/libxml_parser_wrapper.cc
@@ -160,7 +160,7 @@
                           attributes[i].value.as_string());
   }
 
-  if (node_stack_.size() < kMaxStackDepth) {
+  if (static_cast<int>(node_stack_.size()) <= dom_max_element_depth_) {
     element->OnParserStartTag(GetSourceLocation());
     node_stack_.top()->InsertBefore(element, reference_node_);
   } else {
@@ -178,7 +178,7 @@
     scoped_refptr<dom::Element> element = node_stack_.top()->AsElement();
     node_stack_.pop();
 
-    if (node_stack_.size() < kMaxStackDepth) {
+    if (static_cast<int>(node_stack_.size()) <= dom_max_element_depth_) {
       element->OnParserEndTag();
     }
 
diff --git a/src/cobalt/dom_parser/libxml_parser_wrapper.h b/src/cobalt/dom_parser/libxml_parser_wrapper.h
index 4f39651..61f3d04 100644
--- a/src/cobalt/dom_parser/libxml_parser_wrapper.h
+++ b/src/cobalt/dom_parser/libxml_parser_wrapper.h
@@ -78,19 +78,17 @@
   };
   typedef std::vector<ParserAttribute> ParserAttributeVector;
 
-  // This restricts the depth of the nodes in the DOM tree. All elements at a
-  // depth deeper than this will be discarded.
-  static const size_t kMaxStackDepth = 32;
-
   LibxmlParserWrapper(
       const scoped_refptr<dom::Document>& document,
       const scoped_refptr<dom::Node>& parent_node,
       const scoped_refptr<dom::Node>& reference_node,
+      const int dom_max_element_depth,
       const base::SourceLocation& first_chunk_location,
       const base::Callback<void(const std::string&)>& error_callback)
       : document_(document),
         parent_node_(parent_node),
         reference_node_(reference_node),
+        dom_max_element_depth_(dom_max_element_depth),
         first_chunk_location_(first_chunk_location),
         error_callback_(error_callback),
         depth_limit_exceeded_(false),
@@ -140,8 +138,12 @@
   const scoped_refptr<dom::Document> document_;
   const scoped_refptr<dom::Node> parent_node_;
   const scoped_refptr<dom::Node> reference_node_;
+  // Max number the depth of the elements in the DOM tree. All elements at a
+  // depth deeper than this will be discarded.
+  const int dom_max_element_depth_;
   const base::SourceLocation first_chunk_location_;
   const base::Callback<void(const std::string&)> error_callback_;
+
   bool depth_limit_exceeded_;
   IssueSeverity issue_level_;
 
diff --git a/src/cobalt/dom_parser/libxml_xml_parser_wrapper.h b/src/cobalt/dom_parser/libxml_xml_parser_wrapper.h
index 8eea743..f53c729 100644
--- a/src/cobalt/dom_parser/libxml_xml_parser_wrapper.h
+++ b/src/cobalt/dom_parser/libxml_xml_parser_wrapper.h
@@ -38,10 +38,12 @@
       const scoped_refptr<dom::XMLDocument>& xml_document,
       const scoped_refptr<dom::Node>& parent_node,
       const scoped_refptr<dom::Node>& reference_node,
+      const int dom_max_element_depth,
       const base::SourceLocation& input_location,
       const base::Callback<void(const std::string&)>& error_callback)
       : LibxmlParserWrapper(xml_document, parent_node, reference_node,
-                            input_location, error_callback),
+                            dom_max_element_depth, input_location,
+                            error_callback),
         xml_parser_context_(NULL) {}
   ~LibxmlXMLParserWrapper() OVERRIDE;
 
diff --git a/src/cobalt/dom_parser/parser.cc b/src/cobalt/dom_parser/parser.cc
index 98be631..1c8c1ee 100644
--- a/src/cobalt/dom_parser/parser.cc
+++ b/src/cobalt/dom_parser/parser.cc
@@ -30,8 +30,8 @@
     const base::SourceLocation& input_location) {
   scoped_refptr<dom::Document> document =
       new dom::Document(html_element_context, dom::Document::Options());
-  HTMLDecoder html_decoder(document, document, NULL, input_location,
-                           base::Closure(), error_callback_);
+  HTMLDecoder html_decoder(document, document, NULL, dom_max_element_depth_,
+                           input_location, base::Closure(), error_callback_);
   html_decoder.DecodeChunk(input.c_str(), input.length());
   html_decoder.Finish();
   return document;
@@ -41,7 +41,8 @@
     const std::string& input, const base::SourceLocation& input_location) {
   scoped_refptr<dom::XMLDocument> xml_document = new dom::XMLDocument();
   XMLDecoder xml_decoder(
-      xml_document, xml_document, NULL, input_location, base::Closure(),
+      xml_document, xml_document, NULL, dom_max_element_depth_, input_location,
+      base::Closure(),
       base::Bind(&Parser::ErrorCallback, base::Unretained(this)));
   xml_decoder.DecodeChunk(input.c_str(), input.length());
   xml_decoder.Finish();
@@ -54,7 +55,8 @@
     const scoped_refptr<dom::Node>& reference_node,
     const base::SourceLocation& input_location) {
   HTMLDecoder html_decoder(document, parent_node, reference_node,
-                           input_location, base::Closure(), error_callback_);
+                           dom_max_element_depth_, input_location,
+                           base::Closure(), error_callback_);
   html_decoder.DecodeChunk(input.c_str(), input.length());
   html_decoder.Finish();
 }
@@ -66,8 +68,8 @@
     const scoped_refptr<dom::Node>& reference_node,
     const base::SourceLocation& input_location) {
   XMLDecoder xml_decoder(
-      xml_document, parent_node, reference_node, input_location,
-      base::Closure(),
+      xml_document, parent_node, reference_node, dom_max_element_depth_,
+      input_location, base::Closure(),
       base::Bind(&Parser::ErrorCallback, base::Unretained(this)));
   xml_decoder.DecodeChunk(input.c_str(), input.length());
   xml_decoder.Finish();
@@ -77,16 +79,16 @@
     const scoped_refptr<dom::Document>& document,
     const base::SourceLocation& input_location) {
   return scoped_ptr<loader::Decoder>(
-      new HTMLDecoder(document, document, NULL, input_location, base::Closure(),
-                      error_callback_));
+      new HTMLDecoder(document, document, NULL, dom_max_element_depth_,
+                      input_location, base::Closure(), error_callback_));
 }
 
 scoped_ptr<loader::Decoder> Parser::ParseXMLDocumentAsync(
     const scoped_refptr<dom::XMLDocument>& xml_document,
     const base::SourceLocation& input_location) {
   return scoped_ptr<loader::Decoder>(
-      new XMLDecoder(xml_document, xml_document, NULL, input_location,
-                     base::Closure(), error_callback_));
+      new XMLDecoder(xml_document, xml_document, NULL, dom_max_element_depth_,
+                     input_location, base::Closure(), error_callback_));
 }
 
 void Parser::ErrorCallback(const std::string& error) {
diff --git a/src/cobalt/dom_parser/parser.h b/src/cobalt/dom_parser/parser.h
index 700c9c9..cefbf7f 100644
--- a/src/cobalt/dom_parser/parser.h
+++ b/src/cobalt/dom_parser/parser.h
@@ -29,11 +29,17 @@
 class Parser : public dom::Parser {
  public:
   Parser()
-      : ALLOW_THIS_IN_INITIALIZER_LIST(error_callback_(
+      : dom_max_element_depth_(kDefaultDOMMaxElementDepth),
+        ALLOW_THIS_IN_INITIALIZER_LIST(error_callback_(
             base::Bind(&Parser::ErrorCallback, base::Unretained(this)))) {}
   explicit Parser(
       const base::Callback<void(const std::string&)>& error_callback)
-      : error_callback_(error_callback) {}
+      : dom_max_element_depth_(kDefaultDOMMaxElementDepth),
+        error_callback_(error_callback) {}
+  Parser(const int dom_max_element_depth,
+         const base::Callback<void(const std::string&)>& error_callback)
+      : dom_max_element_depth_(dom_max_element_depth),
+        error_callback_(error_callback) {}
   ~Parser() OVERRIDE {}
 
   // From dom::Parser.
@@ -68,10 +74,13 @@
       const base::SourceLocation& input_location) OVERRIDE;
 
  private:
-  void ErrorCallback(const std::string& error);
+  static const int kDefaultDOMMaxElementDepth = 32;
 
+  const int dom_max_element_depth_;
   const base::Callback<void(const std::string&)> error_callback_;
 
+  void ErrorCallback(const std::string& error);
+
   DISALLOW_COPY_AND_ASSIGN(Parser);
 };
 
diff --git a/src/cobalt/dom_parser/xml_decoder.cc b/src/cobalt/dom_parser/xml_decoder.cc
index a840ac3..a1b1b1f 100644
--- a/src/cobalt/dom_parser/xml_decoder.cc
+++ b/src/cobalt/dom_parser/xml_decoder.cc
@@ -25,12 +25,12 @@
     const scoped_refptr<dom::XMLDocument>& xml_document,
     const scoped_refptr<dom::Node>& parent_node,
     const scoped_refptr<dom::Node>& reference_node,
-    const base::SourceLocation& input_location,
+    const int dom_max_element_depth, const base::SourceLocation& input_location,
     const base::Closure& done_callback,
     const base::Callback<void(const std::string&)>& error_callback)
-    : libxml_xml_parser_wrapper_(
-          new LibxmlXMLParserWrapper(xml_document, parent_node, reference_node,
-                                     input_location, error_callback)),
+    : libxml_xml_parser_wrapper_(new LibxmlXMLParserWrapper(
+          xml_document, parent_node, reference_node, dom_max_element_depth,
+          input_location, error_callback)),
       done_callback_(done_callback) {}
 
 XMLDecoder::~XMLDecoder() {}
diff --git a/src/cobalt/dom_parser/xml_decoder.h b/src/cobalt/dom_parser/xml_decoder.h
index 5784da6..1be11a7 100644
--- a/src/cobalt/dom_parser/xml_decoder.h
+++ b/src/cobalt/dom_parser/xml_decoder.h
@@ -42,6 +42,7 @@
   XMLDecoder(const scoped_refptr<dom::XMLDocument>& xml_document,
              const scoped_refptr<dom::Node>& parent_node,
              const scoped_refptr<dom::Node>& reference_node,
+             const int dom_max_element_depth,
              const base::SourceLocation& input_location,
              const base::Closure& done_callback,
              const base::Callback<void(const std::string&)>& error_callback);
diff --git a/src/cobalt/dom_parser/xml_decoder_test.cc b/src/cobalt/dom_parser/xml_decoder_test.cc
index 3f4b3cf..ecc6b41 100644
--- a/src/cobalt/dom_parser/xml_decoder_test.cc
+++ b/src/cobalt/dom_parser/xml_decoder_test.cc
@@ -29,6 +29,8 @@
 namespace cobalt {
 namespace dom_parser {
 
+const int kDOMMaxElementDepth = 32;
+
 class MockErrorCallback : public base::Callback<void(const std::string&)> {
  public:
   MOCK_METHOD1(Run, void(const std::string&));
@@ -52,9 +54,9 @@
 TEST_F(XMLDecoderTest, ShouldNotAddImpliedTags) {
   const std::string input = "<ELEMENT></ELEMENT>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -76,9 +78,9 @@
       "]]>"
       "</ELEMENT>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -99,9 +101,9 @@
 TEST_F(XMLDecoderTest, CanParseAttributesWithValue) {
   const std::string input = "<ELEMENT a=\"1\" b=\"2\"></ELEMENT>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -119,9 +121,9 @@
 TEST_F(XMLDecoderTest, TagNamesShouldBeCaseSensitive) {
   const std::string input = "<ELEMENT><element></element></ELEMENT>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -137,9 +139,9 @@
 TEST_F(XMLDecoderTest, AttributesShouldBeCaseSensitive) {
   const std::string input = "<ELEMENT A=\"1\" a=\"2\"></ELEMENT>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -159,9 +161,9 @@
       "<!DOCTYPE doc [ <!ENTITY ent SYSTEM \"file:///dev/tty\"> ]>"
       "<element>&ent;</element>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -175,9 +177,9 @@
       "<!DOCTYPE doc [ <!ENTITY ent SYSTEM \"file:///dev/tty\"> ]>"
       "<element>&ent;</element>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -191,9 +193,9 @@
       "<!DOCTYPE doc [ <!ENTITY % ent SYSTEM \"http://www.google.com/\"> ]>"
       "<element>&ent;</element>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -207,9 +209,9 @@
       "<!DOCTYPE doc [ <!ENTITY % ent SYSTEM \"file:///dev/tty\"> ]>"
       "<element>hey</element>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -223,9 +225,9 @@
       "<!DOCTYPE doc SYSTEM \"file:///dev/tty\">"
       "<element>hey</element>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -255,9 +257,9 @@
       "]>"
       "<element>&ha15;</element>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
@@ -275,9 +277,9 @@
       "</child>"
       "</root>";
   xml_decoder_.reset(new XMLDecoder(
-      document_, document_, NULL, source_location_, base::Closure(),
-      base::Bind(&MockErrorCallback::Run,
-                 base::Unretained(&mock_error_callback_))));
+      document_, document_, NULL, kDOMMaxElementDepth, source_location_,
+      base::Closure(), base::Bind(&MockErrorCallback::Run,
+                                  base::Unretained(&mock_error_callback_))));
   xml_decoder_->DecodeChunk(input.c_str(), input.length());
   xml_decoder_->Finish();
 
diff --git a/src/cobalt/input/key_repeat_filter.cc b/src/cobalt/input/key_repeat_filter.cc
index 04436c3..98eaaec 100644
--- a/src/cobalt/input/key_repeat_filter.cc
+++ b/src/cobalt/input/key_repeat_filter.cc
@@ -25,7 +25,7 @@
 
 const base::TimeDelta kRepeatInitialDelay =
     base::TimeDelta::FromMilliseconds(500);
-const float kRepeatRateInHertz = 10.0f;
+const float kRepeatRateInHertz = 20.0f;
 const base::TimeDelta kRepeatRate = base::TimeDelta::FromMilliseconds(
     base::Time::kMillisecondsPerSecond / kRepeatRateInHertz);
 
diff --git a/src/cobalt/layout/block_level_replaced_box.cc b/src/cobalt/layout/block_level_replaced_box.cc
index e05916f..14658fa 100644
--- a/src/cobalt/layout/block_level_replaced_box.cc
+++ b/src/cobalt/layout/block_level_replaced_box.cc
@@ -24,15 +24,16 @@
 BlockLevelReplacedBox::BlockLevelReplacedBox(
     const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
         css_computed_style_declaration,
-    const ReplaceImageCB& replace_image_cb,
+    const ReplaceImageCB& replace_image_cb, const SetBoundsCB& set_bounds_cb,
     const scoped_refptr<Paragraph>& paragraph, int32 text_position,
     const base::optional<LayoutUnit>& maybe_intrinsic_width,
     const base::optional<LayoutUnit>& maybe_intrinsic_height,
     const base::optional<float>& maybe_intrinsic_ratio,
     UsedStyleProvider* used_style_provider,
     LayoutStatTracker* layout_stat_tracker)
-    : ReplacedBox(css_computed_style_declaration, replace_image_cb, paragraph,
-                  text_position, maybe_intrinsic_width, maybe_intrinsic_height,
+    : ReplacedBox(css_computed_style_declaration, replace_image_cb,
+                  set_bounds_cb, paragraph, text_position,
+                  maybe_intrinsic_width, maybe_intrinsic_height,
                   maybe_intrinsic_ratio, used_style_provider,
                   layout_stat_tracker) {}
 
diff --git a/src/cobalt/layout/block_level_replaced_box.h b/src/cobalt/layout/block_level_replaced_box.h
index f461485..bd7982b 100644
--- a/src/cobalt/layout/block_level_replaced_box.h
+++ b/src/cobalt/layout/block_level_replaced_box.h
@@ -34,7 +34,7 @@
   BlockLevelReplacedBox(
       const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
           css_computed_style_declaration,
-      const ReplaceImageCB& replace_image_cb,
+      const ReplaceImageCB& replace_image_cb, const SetBoundsCB& set_bounds_cb,
       const scoped_refptr<Paragraph>& paragraph, int32 text_position,
       const base::optional<LayoutUnit>& maybe_intrinsic_width,
       const base::optional<LayoutUnit>& maybe_intrinsic_height,
diff --git a/src/cobalt/layout/box_generator.cc b/src/cobalt/layout/box_generator.cc
index 2cfb06b..d19d55e 100644
--- a/src/cobalt/layout/box_generator.cc
+++ b/src/cobalt/layout/box_generator.cc
@@ -72,11 +72,13 @@
     const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
         parent_css_computed_style_declaration,
     const scoped_refptr<const web_animations::AnimationSet>& parent_animations,
-    scoped_refptr<Paragraph>* paragraph, const Context* context)
+    scoped_refptr<Paragraph>* paragraph, const int dom_element_depth,
+    const Context* context)
     : parent_css_computed_style_declaration_(
           parent_css_computed_style_declaration),
       parent_animations_(parent_animations),
       paragraph_(paragraph),
+      dom_element_depth_(dom_element_depth),
       context_(context) {}
 
 BoxGenerator::~BoxGenerator() {
@@ -92,8 +94,15 @@
 }
 
 void BoxGenerator::Visit(dom::Element* element) {
+  if (dom_element_depth_ > context_->dom_max_element_depth) {
+    LOG(WARNING) << "Elements too deep in the DOM tree are ignored in layout.";
+    return;
+  }
+
   scoped_refptr<dom::HTMLElement> html_element = element->AsHTMLElement();
-  DCHECK(html_element);
+  if (!html_element) {
+    return;
+  }
   generating_html_element_ = html_element;
 
   bool partial_layout_is_enabled = true;
@@ -148,6 +157,7 @@
   ReplacedBoxGenerator(const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
                            css_computed_style_declaration,
                        const ReplacedBox::ReplaceImageCB& replace_image_cb,
+                       const ReplacedBox::SetBoundsCB& set_bounds_cb,
                        const scoped_refptr<Paragraph>& paragraph,
                        int32 text_position,
                        const base::optional<LayoutUnit>& maybe_intrinsic_width,
@@ -156,6 +166,7 @@
                        const BoxGenerator::Context* context)
       : css_computed_style_declaration_(css_computed_style_declaration),
         replace_image_cb_(replace_image_cb),
+        set_bounds_cb_(set_bounds_cb),
         paragraph_(paragraph),
         text_position_(text_position),
         maybe_intrinsic_width_(maybe_intrinsic_width),
@@ -171,6 +182,7 @@
   const scoped_refptr<cssom::CSSComputedStyleDeclaration>
       css_computed_style_declaration_;
   const ReplacedBox::ReplaceImageCB replace_image_cb_;
+  const ReplacedBox::SetBoundsCB set_bounds_cb_;
   const scoped_refptr<Paragraph> paragraph_;
   const int32 text_position_;
   const base::optional<LayoutUnit> maybe_intrinsic_width_;
@@ -187,10 +199,10 @@
     // Generate a block-level replaced box.
     case cssom::KeywordValue::kBlock:
       replaced_box_ = make_scoped_refptr(new BlockLevelReplacedBox(
-          css_computed_style_declaration_, replace_image_cb_, paragraph_,
-          text_position_, maybe_intrinsic_width_, maybe_intrinsic_height_,
-          maybe_intrinsic_ratio_, context_->used_style_provider,
-          context_->layout_stat_tracker));
+          css_computed_style_declaration_, replace_image_cb_, set_bounds_cb_,
+          paragraph_, text_position_, maybe_intrinsic_width_,
+          maybe_intrinsic_height_, maybe_intrinsic_ratio_,
+          context_->used_style_provider, context_->layout_stat_tracker));
       break;
     // Generate an inline-level replaced box. There is no need to distinguish
     // between inline replaced elements and inline-block replaced elements
@@ -199,10 +211,10 @@
     case cssom::KeywordValue::kInline:
     case cssom::KeywordValue::kInlineBlock:
       replaced_box_ = make_scoped_refptr(new InlineLevelReplacedBox(
-          css_computed_style_declaration_, replace_image_cb_, paragraph_,
-          text_position_, maybe_intrinsic_width_, maybe_intrinsic_height_,
-          maybe_intrinsic_ratio_, context_->used_style_provider,
-          context_->layout_stat_tracker));
+          css_computed_style_declaration_, replace_image_cb_, set_bounds_cb_,
+          paragraph_, text_position_, maybe_intrinsic_width_,
+          maybe_intrinsic_height_, maybe_intrinsic_ratio_,
+          context_->used_style_provider, context_->layout_stat_tracker));
       break;
     // The element generates no boxes and has no effect on layout.
     case cssom::KeywordValue::kNone:
@@ -283,8 +295,8 @@
       video_element->GetVideoFrameProvider()
           ? base::Bind(GetVideoFrame, video_element->GetVideoFrameProvider())
           : ReplacedBox::ReplaceImageCB(),
-      *paragraph_, text_position, base::nullopt, base::nullopt, base::nullopt,
-      context_);
+      video_element->GetSetBoundsCB(), *paragraph_, text_position,
+      base::nullopt, base::nullopt, base::nullopt, context_);
   video_element->computed_style()->display()->Accept(&replaced_box_generator);
 
   scoped_refptr<ReplacedBox> replaced_box =
@@ -784,7 +796,7 @@
             pseudo_element->css_computed_style_declaration(),
             use_html_element_animations ? html_element->animations()
                                         : pseudo_element->animations(),
-            paragraph_, context_);
+            paragraph_, dom_element_depth_ + 1, context_);
         child_node->Accept(&child_box_generator);
         const Boxes& child_boxes = child_box_generator.boxes();
         for (Boxes::const_iterator child_box_iterator = child_boxes.begin();
@@ -855,7 +867,7 @@
     BoxGenerator child_box_generator(
         html_element->css_computed_style_declaration(),
         html_element->css_computed_style_declaration()->animations(),
-        paragraph_, context_);
+        paragraph_, dom_element_depth_ + 1, context_);
     child_node->Accept(&child_box_generator);
     const Boxes& child_boxes = child_box_generator.boxes();
     for (Boxes::const_iterator child_box_iterator = child_boxes.begin();
diff --git a/src/cobalt/layout/box_generator.h b/src/cobalt/layout/box_generator.h
index b2898c8..2b89c95 100644
--- a/src/cobalt/layout/box_generator.h
+++ b/src/cobalt/layout/box_generator.h
@@ -54,12 +54,14 @@
             LayoutStatTracker* layout_stat_tracker,
             icu::BreakIterator* line_break_iterator,
             icu::BreakIterator* character_break_iterator,
-            dom::HTMLElement* ignore_background_element)
+            dom::HTMLElement* ignore_background_element,
+            int dom_max_element_depth)
         : used_style_provider(used_style_provider),
           layout_stat_tracker(layout_stat_tracker),
           line_break_iterator(line_break_iterator),
           character_break_iterator(character_break_iterator),
-          ignore_background_element(ignore_background_element) {}
+          ignore_background_element(ignore_background_element),
+          dom_max_element_depth(dom_max_element_depth) {}
     UsedStyleProvider* used_style_provider;
     LayoutStatTracker* layout_stat_tracker;
     icu::BreakIterator* line_break_iterator;
@@ -70,6 +72,9 @@
     // re-use those properties on that element.  This value will track that
     // element.
     dom::HTMLElement* ignore_background_element;
+
+    // The maximum element depth for layout.
+    int dom_max_element_depth;
   };
 
   BoxGenerator(const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
@@ -81,7 +86,8 @@
                // animation inheritance is implemented.
                const scoped_refptr<const web_animations::AnimationSet>&
                    parent_animations,
-               scoped_refptr<Paragraph>* paragraph, const Context* context);
+               scoped_refptr<Paragraph>* paragraph,
+               const int dom_element_depth_, const Context* context);
   ~BoxGenerator();
 
   void Visit(dom::CDATASection* cdata_section) OVERRIDE;
@@ -106,7 +112,10 @@
       parent_css_computed_style_declaration_;
   const scoped_refptr<const web_animations::AnimationSet>& parent_animations_;
   scoped_refptr<Paragraph>* paragraph_;
+  // The current element depth.
+  const int dom_element_depth_;
   const Context* context_;
+
   scoped_refptr<dom::HTMLElement> generating_html_element_;
 
   // The result of a box generator is zero or more root boxes.
diff --git a/src/cobalt/layout/container_box.cc b/src/cobalt/layout/container_box.cc
index 4ee4b0b..1d55190 100644
--- a/src/cobalt/layout/container_box.cc
+++ b/src/cobalt/layout/container_box.cc
@@ -400,10 +400,7 @@
 
 Vector2dLayoutUnit GetOffsetFromContainingBlockToStackingContext(
     Box* child_box) {
-  DCHECK((child_box->computed_style()->position() ==
-          cssom::KeywordValue::GetFixed()) ||
-         (child_box->computed_style()->position() ==
-          cssom::KeywordValue::GetAbsolute()));
+  DCHECK(child_box->IsPositioned());
 
   Vector2dLayoutUnit relative_position;
   for (Box *containing_block = child_box->GetContainingBlock(),
@@ -411,14 +408,19 @@
        current_box != containing_block;
        current_box = current_box->GetContainingBlock()) {
     if (!current_box) {
-      NOTREACHED() << "Unable to find stacking context while "
-                      "traversing containing blocks.";
+      DLOG(WARNING)
+          << "Unsupported stacking context and containing block relation.";
       break;
     }
+#if !defined(NDEBUG)
     // We should not determine a used position through a transform, as
     // rectangles may not remain rectangles past it, and thus obtaining
     // a position may be misleading.
-    DCHECK(!current_box->IsTransformed());
+    if (current_box->IsTransformed()) {
+      DLOG(WARNING) << "Boxes with stacking contexts above containing blocks "
+                       "with transforms may not be positioned correctly.";
+    }
+#endif
 
     relative_position += current_box->GetContentBoxOffsetFromMarginBox();
     relative_position += current_box->margin_box_offset_from_containing_block();
@@ -450,15 +452,20 @@
        current_box != stacking_context;
        current_box = current_box->GetContainingBlock()) {
     if (!current_box) {
-      // Elements with absolute position may have their containing block farther
+      // Positioned elements may have their containing block farther
       // up the hierarchy than the stacking context, so handle this case here.
-      DCHECK(child_box_position == cssom::KeywordValue::GetAbsolute());
+      DCHECK(child_box->IsPositioned());
       return -GetOffsetFromContainingBlockToStackingContext(child_box);
     }
+#if !defined(NDEBUG)
     // We should not determine a used position through a transform, as
     // rectangles may not remain rectangles past it, and thus obtaining
     // a position may be misleading.
-    DCHECK(!current_box->IsTransformed());
+    if (current_box->IsTransformed()) {
+      DLOG(WARNING) << "Boxes with stacking contexts below containing blocks "
+                       "with transforms may not be positioned correctly.";
+    }
+#endif
 
     relative_position += current_box->GetContentBoxOffsetFromMarginBox();
     relative_position += current_box->margin_box_offset_from_containing_block();
diff --git a/src/cobalt/layout/inline_level_replaced_box.cc b/src/cobalt/layout/inline_level_replaced_box.cc
index 9d6072c..5eab8c8 100644
--- a/src/cobalt/layout/inline_level_replaced_box.cc
+++ b/src/cobalt/layout/inline_level_replaced_box.cc
@@ -24,15 +24,16 @@
 InlineLevelReplacedBox::InlineLevelReplacedBox(
     const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
         css_computed_style_declaration,
-    const ReplaceImageCB& replace_image_cb,
+    const ReplaceImageCB& replace_image_cb, const SetBoundsCB& set_bounds_cb,
     const scoped_refptr<Paragraph>& paragraph, int32 text_position,
     const base::optional<LayoutUnit>& maybe_intrinsic_width,
     const base::optional<LayoutUnit>& maybe_intrinsic_height,
     const base::optional<float>& maybe_intrinsic_ratio,
     UsedStyleProvider* used_style_provider,
     LayoutStatTracker* layout_stat_tracker)
-    : ReplacedBox(css_computed_style_declaration, replace_image_cb, paragraph,
-                  text_position, maybe_intrinsic_width, maybe_intrinsic_height,
+    : ReplacedBox(css_computed_style_declaration, replace_image_cb,
+                  set_bounds_cb, paragraph, text_position,
+                  maybe_intrinsic_width, maybe_intrinsic_height,
                   maybe_intrinsic_ratio, used_style_provider,
                   layout_stat_tracker),
       is_hidden_by_ellipsis_(false),
diff --git a/src/cobalt/layout/inline_level_replaced_box.h b/src/cobalt/layout/inline_level_replaced_box.h
index b0f1a25..32a85aa 100644
--- a/src/cobalt/layout/inline_level_replaced_box.h
+++ b/src/cobalt/layout/inline_level_replaced_box.h
@@ -36,7 +36,7 @@
   InlineLevelReplacedBox(
       const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
           css_computed_style_declaration,
-      const ReplaceImageCB& replace_image_cb,
+      const ReplaceImageCB& replace_image_cb, const SetBoundsCB& set_bounds_cb,
       const scoped_refptr<Paragraph>& paragraph, int32 text_position,
       const base::optional<LayoutUnit>& maybe_intrinsic_width,
       const base::optional<LayoutUnit>& maybe_intrinsic_height,
diff --git a/src/cobalt/layout/layout.cc b/src/cobalt/layout/layout.cc
index d517a4f..46ca1c1 100644
--- a/src/cobalt/layout/layout.cc
+++ b/src/cobalt/layout/layout.cc
@@ -52,7 +52,7 @@
 
 void UpdateComputedStylesAndLayoutBoxTree(
     const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
-    UsedStyleProvider* used_style_provider,
+    int dom_max_element_depth, UsedStyleProvider* used_style_provider,
     LayoutStatTracker* layout_stat_tracker,
     icu::BreakIterator* line_break_iterator,
     icu::BreakIterator* character_break_iterator,
@@ -91,13 +91,14 @@
     BoxGenerator::Context context(
         used_style_provider, layout_stat_tracker, line_break_iterator,
         character_break_iterator,
-        initial_containing_block_creation_results.background_style_source);
+        initial_containing_block_creation_results.background_style_source,
+        dom_max_element_depth);
     BoxGenerator root_box_generator(
         (*initial_containing_block)->css_computed_style_declaration(),
         (*initial_containing_block)
             ->css_computed_style_declaration()
             ->animations(),
-        &(scoped_paragraph.get()), &context);
+        &(scoped_paragraph.get()), 1 /* dom_element_depth */, &context);
     document->html()->Accept(&root_box_generator);
     const Boxes& root_boxes = root_box_generator.boxes();
     for (Boxes::const_iterator root_box_iterator = root_boxes.begin();
@@ -130,15 +131,16 @@
 
 scoped_refptr<render_tree::Node> Layout(
     const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
-    UsedStyleProvider* used_style_provider,
+    int dom_max_element_depth, UsedStyleProvider* used_style_provider,
     LayoutStatTracker* layout_stat_tracker,
     icu::BreakIterator* line_break_iterator,
     icu::BreakIterator* character_break_iterator,
     scoped_refptr<BlockLevelBlockContainerBox>* initial_containing_block) {
   TRACE_EVENT0("cobalt::layout", "Layout()");
   UpdateComputedStylesAndLayoutBoxTree(
-      locale, document, used_style_provider, layout_stat_tracker,
-      line_break_iterator, character_break_iterator, initial_containing_block);
+      locale, document, dom_max_element_depth, used_style_provider,
+      layout_stat_tracker, line_break_iterator, character_break_iterator,
+      initial_containing_block);
 
   // Add to render tree.
   render_tree::CompositionNode::Builder render_tree_root_builder;
diff --git a/src/cobalt/layout/layout.h b/src/cobalt/layout/layout.h
index d9cdf7a..fa6c03f 100644
--- a/src/cobalt/layout/layout.h
+++ b/src/cobalt/layout/layout.h
@@ -43,7 +43,7 @@
 // Update the computed styles, then generate and layout the box tree.
 void UpdateComputedStylesAndLayoutBoxTree(
     const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
-    UsedStyleProvider* used_style_provider,
+    int dom_max_element_depth, UsedStyleProvider* used_style_provider,
     LayoutStatTracker* layout_stat_tracker,
     icu::BreakIterator* line_break_iterator,
     icu::BreakIterator* character_break_iterator,
@@ -54,7 +54,7 @@
 // result of recursive layout of the given HTML element.
 scoped_refptr<render_tree::Node> Layout(
     const icu::Locale& locale, const scoped_refptr<dom::Document>& document,
-    UsedStyleProvider* used_style_provider,
+    int dom_max_element_depth, UsedStyleProvider* used_style_provider,
     LayoutStatTracker* layout_stat_tracker,
     icu::BreakIterator* line_break_iterator,
     icu::BreakIterator* character_break_iterator,
diff --git a/src/cobalt/layout/layout_manager.cc b/src/cobalt/layout/layout_manager.cc
index c0fb5c6..da165f9 100644
--- a/src/cobalt/layout/layout_manager.cc
+++ b/src/cobalt/layout/layout_manager.cc
@@ -39,8 +39,9 @@
  public:
   Impl(const scoped_refptr<dom::Window>& window,
        const OnRenderTreeProducedCallback& on_render_tree_produced,
-       LayoutTrigger layout_trigger, float layout_refresh_rate,
-       const std::string& language, LayoutStatTracker* layout_stat_tracker);
+       LayoutTrigger layout_trigger, int dom_max_element_depth,
+       float layout_refresh_rate, const std::string& language,
+       LayoutStatTracker* layout_stat_tracker);
   ~Impl();
 
   // From dom::DocumentObserver.
@@ -78,6 +79,7 @@
   scoped_ptr<icu::BreakIterator> character_break_iterator_;
 
   base::Timer layout_timer_;
+  int dom_max_element_depth_;
   float layout_refresh_rate_;
 
   LayoutStatTracker* const layout_stat_tracker_;
@@ -92,8 +94,9 @@
 LayoutManager::Impl::Impl(
     const scoped_refptr<dom::Window>& window,
     const OnRenderTreeProducedCallback& on_render_tree_produced,
-    LayoutTrigger layout_trigger, float layout_refresh_rate,
-    const std::string& language, LayoutStatTracker* layout_stat_tracker)
+    LayoutTrigger layout_trigger, int dom_max_element_depth,
+    float layout_refresh_rate, const std::string& language,
+    LayoutStatTracker* layout_stat_tracker)
     : window_(window),
       locale_(icu::Locale::createCanonical(language.c_str())),
       used_style_provider_(
@@ -103,6 +106,7 @@
       layout_trigger_(layout_trigger),
       layout_dirty_(true),
       layout_timer_(true, true, true),
+      dom_max_element_depth_(dom_max_element_depth),
       layout_refresh_rate_(layout_refresh_rate),
       layout_stat_tracker_(layout_stat_tracker) {
   window_->document()->AddObserver(this);
@@ -163,9 +167,10 @@
 void LayoutManager::Impl::DoSynchronousLayout() {
   TRACE_EVENT0("cobalt::layout", "LayoutManager::Impl::DoSynchronousLayout()");
   layout::UpdateComputedStylesAndLayoutBoxTree(
-      locale_, window_->document(), used_style_provider_.get(),
-      layout_stat_tracker_, line_break_iterator_.get(),
-      character_break_iterator_.get(), &initial_containing_block_);
+      locale_, window_->document(), dom_max_element_depth_,
+      used_style_provider_.get(), layout_stat_tracker_,
+      line_break_iterator_.get(), character_break_iterator_.get(),
+      &initial_containing_block_);
 }
 
 #if defined(ENABLE_TEST_RUNNER)
@@ -240,9 +245,10 @@
     }
 
     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_);
+        locale_, window_->document(), dom_max_element_depth_,
+        used_style_provider_.get(), layout_stat_tracker_,
+        line_break_iterator_.get(), character_break_iterator_.get(),
+        &initial_containing_block_);
     bool run_on_render_tree_produced_callback = true;
 #if defined(ENABLE_TEST_RUNNER)
     if (layout_trigger_ == kTestRunnerMode &&
@@ -265,10 +271,12 @@
 LayoutManager::LayoutManager(
     const scoped_refptr<dom::Window>& window,
     const OnRenderTreeProducedCallback& on_render_tree_produced,
-    LayoutTrigger layout_trigger, float layout_refresh_rate,
-    const std::string& language, LayoutStatTracker* layout_stat_tracker)
+    LayoutTrigger layout_trigger, const int dom_max_element_depth,
+    const float layout_refresh_rate, const std::string& language,
+    LayoutStatTracker* layout_stat_tracker)
     : impl_(new Impl(window, on_render_tree_produced, layout_trigger,
-                     layout_refresh_rate, language, layout_stat_tracker)) {}
+                     dom_max_element_depth, layout_refresh_rate, language,
+                     layout_stat_tracker)) {}
 
 LayoutManager::~LayoutManager() {}
 
diff --git a/src/cobalt/layout/layout_manager.h b/src/cobalt/layout/layout_manager.h
index 39e4eb7..3c60206 100644
--- a/src/cobalt/layout/layout_manager.h
+++ b/src/cobalt/layout/layout_manager.h
@@ -63,8 +63,8 @@
 
   LayoutManager(const scoped_refptr<dom::Window>& window,
                 const OnRenderTreeProducedCallback& on_render_tree_produced,
-                LayoutTrigger layout_trigger, float layout_refresh_rate,
-                const std::string& language,
+                LayoutTrigger layout_trigger, const int dom_max_element_depth,
+                const float layout_refresh_rate, const std::string& language,
                 LayoutStatTracker* layout_stat_tracker);
   ~LayoutManager();
 
diff --git a/src/cobalt/layout/replaced_box.cc b/src/cobalt/layout/replaced_box.cc
index d8a694c..1b1c865 100644
--- a/src/cobalt/layout/replaced_box.cc
+++ b/src/cobalt/layout/replaced_box.cc
@@ -29,29 +29,23 @@
 #include "cobalt/math/vector2d_f.h"
 #include "cobalt/render_tree/brush.h"
 #include "cobalt/render_tree/color_rgba.h"
+#include "cobalt/render_tree/filter_node.h"
 #include "cobalt/render_tree/image_node.h"
+#include "cobalt/render_tree/map_to_mesh_filter.h"
 #include "cobalt/render_tree/punch_through_video_node.h"
 #include "cobalt/render_tree/rect_node.h"
 
-// Here we determine if we are going to be rendering video ourselves, or if
-// the Starboard Player system will be rendering video in which case we need to
-// punch through our scene so that the video will be visible.
-#if defined(OS_STARBOARD)
-#include "starboard/configuration.h"
-#define PUNCH_THROUGH_VIDEO_RENDERING SB_IS(PLAYER_PUNCHED_OUT)
-#else  // defined(OS_STARBOARD)
-#define PUNCH_THROUGH_VIDEO_RENDERING 0
-#endif  // defined(OS_STARBOARD)
-
 namespace cobalt {
 namespace layout {
 
 using render_tree::animations::AnimateNode;
 using render_tree::CompositionNode;
+using render_tree::FilterNode;
 using render_tree::ImageNode;
 using render_tree::PunchThroughVideoNode;
 using render_tree::RectNode;
 using render_tree::SolidColorBrush;
+using render_tree::MapToMeshFilter;
 
 namespace {
 
@@ -68,7 +62,7 @@
 ReplacedBox::ReplacedBox(
     const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
         css_computed_style_declaration,
-    const ReplaceImageCB& replace_image_cb,
+    const ReplaceImageCB& replace_image_cb, const SetBoundsCB& set_bounds_cb,
     const scoped_refptr<Paragraph>& paragraph, int32 text_position,
     const base::optional<LayoutUnit>& maybe_intrinsic_width,
     const base::optional<LayoutUnit>& maybe_intrinsic_height,
@@ -84,6 +78,7 @@
       // https://www.w3.org/TR/CSS21/visudet.html#inline-replaced-width.
       intrinsic_ratio_(maybe_intrinsic_ratio.value_or(kFallbackIntrinsicRatio)),
       replace_image_cb_(replace_image_cb),
+      set_bounds_cb_(set_bounds_cb),
       paragraph_(paragraph),
       text_position_(text_position) {}
 
@@ -204,7 +199,8 @@
 
 #endif  // !PUNCH_THROUGH_VIDEO_RENDERING
 
-void AnimateCB(ReplacedBox::ReplaceImageCB replace_image_cb,
+void AnimateCB(const ReplacedBox::ReplaceImageCB& replace_image_cb,
+               const ReplacedBox::SetBoundsCB& set_bounds_cb,
                math::SizeF destination_size,
                CompositionNode::Builder* composition_node_builder,
                base::TimeDelta time) {
@@ -216,9 +212,11 @@
 #if PUNCH_THROUGH_VIDEO_RENDERING
   // For systems that have their own path to blitting video to the display, we
   // simply punch a hole through our scene so that the video can appear there.
-  composition_node_builder->AddChild(
-      new PunchThroughVideoNode(math::RectF(destination_size)));
-#else
+  PunchThroughVideoNode::Builder builder(math::RectF(destination_size),
+                                         set_bounds_cb);
+  composition_node_builder->AddChild(new PunchThroughVideoNode(builder));
+#else   // PUNCH_THROUGH_VIDEO_RENDERING
+  UNREFERENCED_PARAMETER(set_bounds_cb);
   scoped_refptr<render_tree::Image> image = replace_image_cb.Run();
 
   // TODO: Detect better when the intrinsic video size is used for the
@@ -233,7 +231,7 @@
         GetLetterboxDimensions(image->GetSize(), destination_size), image,
         composition_node_builder);
   }
-#endif
+#endif  // PUNCH_THROUGH_VIDEO_RENDERING
 }
 
 }  // namespace
@@ -258,9 +256,10 @@
 
   AnimateNode::Builder animate_node_builder;
   animate_node_builder.Add(
-      composition_node,
-      base::Bind(AnimateCB, replace_image_cb_, content_box_size()));
+      composition_node, base::Bind(AnimateCB, replace_image_cb_, set_bounds_cb_,
+                                   content_box_size()));
 
+  // TODO: Apply map to mesh filter if present.
   border_node_builder->AddChild(
       new AnimateNode(animate_node_builder, composition_node));
 }
diff --git a/src/cobalt/layout/replaced_box.h b/src/cobalt/layout/replaced_box.h
index 259b2d0..aaa6cbc 100644
--- a/src/cobalt/layout/replaced_box.h
+++ b/src/cobalt/layout/replaced_box.h
@@ -24,7 +24,19 @@
 #include "base/time.h"
 #include "cobalt/layout/box.h"
 #include "cobalt/layout/paragraph.h"
+#include "cobalt/math/rect.h"
 #include "cobalt/render_tree/image.h"
+#include "cobalt/render_tree/punch_through_video_node.h"
+
+// Here we determine if we are going to be rendering video ourselves, or if
+// the Starboard Player system will be rendering video in which case we need to
+// punch through our scene so that the video will be visible.
+#if defined(OS_STARBOARD)
+#include "starboard/configuration.h"
+#define PUNCH_THROUGH_VIDEO_RENDERING SB_IS(PLAYER_PUNCHED_OUT)
+#else  // defined(OS_STARBOARD)
+#define PUNCH_THROUGH_VIDEO_RENDERING 0
+#endif  // defined(OS_STARBOARD)
 
 namespace cobalt {
 namespace layout {
@@ -38,10 +50,12 @@
 class ReplacedBox : public Box {
  public:
   typedef base::Callback<scoped_refptr<render_tree::Image>()> ReplaceImageCB;
+  typedef render_tree::PunchThroughVideoNode::SetBoundsCB SetBoundsCB;
 
   ReplacedBox(const scoped_refptr<cssom::CSSComputedStyleDeclaration>&
                   css_computed_style_declaration,
               const ReplaceImageCB& replace_image_cb,
+              const SetBoundsCB& set_bounds_cb,
               const scoped_refptr<Paragraph>& paragraph, int32 text_position,
               const base::optional<LayoutUnit>& maybe_intrinsic_width,
               const base::optional<LayoutUnit>& maybe_intrinsic_height,
@@ -102,6 +116,7 @@
 
  private:
   const ReplaceImageCB replace_image_cb_;
+  const SetBoundsCB set_bounds_cb_;
 
   const scoped_refptr<Paragraph> paragraph_;
   int32 text_position_;
diff --git a/src/cobalt/layout_tests/testdata/cobalt/100-dynamically-created-nested-elements-expected.png b/src/cobalt/layout_tests/testdata/cobalt/100-dynamically-created-nested-elements-expected.png
new file mode 100644
index 0000000..723686a
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cobalt/100-dynamically-created-nested-elements-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/cobalt/100-dynamically-created-nested-elements.html b/src/cobalt/layout_tests/testdata/cobalt/100-dynamically-created-nested-elements.html
new file mode 100644
index 0000000..498e1a7
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cobalt/100-dynamically-created-nested-elements.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <style>
+    body {
+      background-color: white;
+      font-family: Roboto;
+      font-size: 30px;
+    }
+  </style>
+</head>
+<body>
+
+  <!-- 100 dynamically created nested <span>s. -->
+  <!-- Cobalt should only render 30 <span>s along with <html> and <body>, given
+  that max element depth is 32. -->
+
+<script>
+  var parent = document.body;
+  for (var i = 1; i <= 100; i++) {
+    var new_child = document.createElement("span");
+    new_child.textContent = i + " ";
+    parent.appendChild(new_child);
+    parent = new_child;
+  }
+</script>
+
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/cobalt/100-nested-elements-expected.png b/src/cobalt/layout_tests/testdata/cobalt/100-nested-elements-expected.png
new file mode 100644
index 0000000..723686a
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/cobalt/100-nested-elements-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/cobalt/1000-nested-elements.html b/src/cobalt/layout_tests/testdata/cobalt/100-nested-elements.html
similarity index 98%
rename from src/cobalt/layout_tests/testdata/cobalt/1000-nested-elements.html
rename to src/cobalt/layout_tests/testdata/cobalt/100-nested-elements.html
index bc583e3..2d18c87 100644
--- a/src/cobalt/layout_tests/testdata/cobalt/1000-nested-elements.html
+++ b/src/cobalt/layout_tests/testdata/cobalt/100-nested-elements.html
@@ -12,8 +12,8 @@
 <body>
 
   <!-- 1000 nested <span>s, closing tags are implied. -->
-  <!-- Cobalt should only attach 29 <span>s, since there're the document, <html>
-  and <body> in the stack, given that max depth is 32. -->
+  <!-- Cobalt should only attach 30 <span>s along with <html> and <body>, given
+  that max element depth is 32. -->
 
   <span>1
   <span>2
diff --git a/src/cobalt/layout_tests/testdata/cobalt/1000-nested-elements-expected.png b/src/cobalt/layout_tests/testdata/cobalt/1000-nested-elements-expected.png
deleted file mode 100644
index 0a80611..0000000
--- a/src/cobalt/layout_tests/testdata/cobalt/1000-nested-elements-expected.png
+++ /dev/null
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/cobalt/layout_tests.txt b/src/cobalt/layout_tests/testdata/cobalt/layout_tests.txt
index 93e5eda..e336781 100644
--- a/src/cobalt/layout_tests/testdata/cobalt/layout_tests.txt
+++ b/src/cobalt/layout_tests/testdata/cobalt/layout_tests.txt
@@ -1,4 +1,5 @@
-1000-nested-elements
+100-dynamically-created-nested-elements
+100-nested-elements
 block-and-inline-block-display
 changing-css-text-triggers-layout
 cobalt-oxide, file:///cobalt/browser/testdata/cobalt-oxide/cobalt-oxide.html
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/DISABLED-9-9-1-stacking-contexts-and-containing-blocks-in-separate-subtrees.html b/src/cobalt/layout_tests/testdata/css-2-1/DISABLED-9-9-1-stacking-contexts-and-containing-blocks-in-separate-subtrees.html
new file mode 100644
index 0000000..5fabe2f
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css-2-1/DISABLED-9-9-1-stacking-contexts-and-containing-blocks-in-separate-subtrees.html
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<!--
+ | Test stacking context and containing blocks, verifying that their relative
+ | positions can still be found when neither is in a subtree of the other.
+ -->
+<html>
+<head>
+  <style>
+    body {
+      font-family: Roboto;
+      margin: 0px;
+    }
+    div {
+      padding: 10px;
+    }
+    .always_containing_block {
+      opacity: 0.999;
+      transform: rotate(0deg);
+    }
+    .absolute {
+      position: absolute;
+    }
+    .relative {
+      position: relative;
+    }
+    .fixed {
+      position: fixed;
+    }
+    .blue1 {
+      background-color: #BBDEFB;
+    }
+    .blue2 {
+      background-color: #2196F3;
+    }
+    .blue3 {
+      background-color: #1976D2;
+    }
+    .blue4 {
+      background-color: #0D47A1;
+    }
+  </style>
+</head>
+<body style="background-color:#000000;">
+<div class="always_containing_block absolute">
+  <div class="blue1 absolute" style="transform: rotate(0deg); width:75px; height:75px;">
+    <div class="blue2 absolute" style="z-index: -1; top:25px; left:25px">
+      <div class="blue3 fixed" style="top:50px; left:50px;">
+        <div class="blue4 absolute" style="z-index: 1; top:5px; left:5px">
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+<div class="always_containing_block absolute" style="left:100px;">
+  <div class="blue1 relative" style="z-index:1; width:75px; height:75px;">
+   <div class="blue2 fixed" style="top:50px; left:50px;">
+    <div class="blue3 relative" style="z-index:1; top:5px; left:5px">
+    </div>
+   </div>
+  </div>
+</div>
+<div class="always_containing_block absolute" style="left:200px;">
+  <div class="blue1" style="opacity: 0.5; width:75px; height:75px;">
+    <div class="blue2 absolute" style="top:25px; left:25px">
+      <div class="blue3 absolute" style="z-index: 1; top:25px; left:25px">
+      </div>
+    </div>
+  </div>
+</div>
+</body>
+</html>
+
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/DISABLED-9-9-1-stacking-contexts-and-containing-blocks-with-transforms.html b/src/cobalt/layout_tests/testdata/css-2-1/DISABLED-9-9-1-stacking-contexts-and-containing-blocks-with-transforms.html
new file mode 100644
index 0000000..9743f20
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css-2-1/DISABLED-9-9-1-stacking-contexts-and-containing-blocks-with-transforms.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<!--
+ | Test stacking context and containing blocks, verifying that the boxes are
+ | positioned correctly when combined with transforms.
+ -->
+<html>
+<head>
+  <style>
+    body {
+      font-family: Roboto;
+      margin: 0px;
+    }
+    div {
+      padding: 10px;
+    }
+    .always_containing_block {
+      opacity: 0.999;
+      transform: rotate(0deg);
+    }
+    .absolute {
+      position: absolute;
+    }
+    .fixed {
+      position: fixed;
+    }
+    .blue1 {
+      background-color: #BBDEFB;
+    }
+    .blue2 {
+      background-color: #2196F3;
+    }
+    .blue3 {
+      background-color: #1976D2;
+    }
+    .blue4 {
+      background-color: #0D47A1;
+    }
+  </style>
+</head>
+<body style="background-color:#000000;">
+<div class="always_containing_block absolute">
+  <div class="blue1 absolute" style="transform: rotate(15deg); width:75px; height:75px;">
+    <div class="blue2 absolute" style="z-index: -1; top:25px; left:25px">
+      <div class="blue3 fixed" style="top:50px; left:50px;">
+        <div class="blue4 absolute" style="z-index: 1; top:5px; left:5px">
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+<div class="always_containing_block absolute" style="left:100px;">
+  <div class="blue1 absolute" style="transform: rotate(15deg); width:75px; height:75px;">
+    <div class="blue2 absolute" style="transform: rotate(-30deg); z-index: -1; top:25px; left:25px">
+      <div class="blue3 fixed" style="top:50px; left:50px;">
+        <div class="blue4 absolute" style="z-index: 1; top:5px; left:5px">
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+<div class="always_containing_block absolute" style="left:225px;">
+  <div class="blue1 absolute" style="transform: rotate(15deg); width:75px; height:75px;">
+    <div class="blue2 absolute" style="z-index: -1; top:25px; left:25px">
+      <div class="blue3 fixed" style="transform: rotate(-30deg); top:50px; left:50px;">
+        <div class="blue4 absolute" style="z-index: 1; top:5px; left:5px">
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+</body>
+</html>
+
diff --git a/src/cobalt/layout_tests/web_platform_tests.cc b/src/cobalt/layout_tests/web_platform_tests.cc
index 0c28e1a..14e32ae 100644
--- a/src/cobalt/layout_tests/web_platform_tests.cc
+++ b/src/cobalt/layout_tests/web_platform_tests.cc
@@ -157,8 +157,9 @@
 
   // Media module
   render_tree::ResourceProviderStub resource_provider;
-  scoped_ptr<media::MediaModule> media_module(media::MediaModule::Create(
-      kDefaultViewportSize, &resource_provider, media::MediaModule::Options()));
+  scoped_ptr<media::MediaModule> media_module(
+      media::MediaModule::Create(NULL, kDefaultViewportSize, &resource_provider,
+                                 media::MediaModule::Options()));
 
   dom::CspDelegateFactory::GetInstance()->OverrideCreator(
       dom::kCspEnforcementEnable, CspDelegatePermissive::Create);
diff --git a/src/cobalt/media/fetcher_buffered_data_source.cc b/src/cobalt/media/fetcher_buffered_data_source.cc
index b50aabc..33346ee 100644
--- a/src/cobalt/media/fetcher_buffered_data_source.cc
+++ b/src/cobalt/media/fetcher_buffered_data_source.cc
@@ -56,7 +56,6 @@
       pending_read_data_(NULL),
       security_callback_(security_callback) {
   DCHECK(message_loop_);
-  DCHECK(!url.path().empty());
   DCHECK(network_module);
 }
 
diff --git a/src/cobalt/media/media_module.h b/src/cobalt/media/media_module.h
index c055bd6..9415df5 100644
--- a/src/cobalt/media/media_module.h
+++ b/src/cobalt/media/media_module.h
@@ -30,6 +30,7 @@
 #include "cobalt/media/web_media_player_factory.h"
 #include "cobalt/render_tree/image.h"
 #include "cobalt/render_tree/resource_provider.h"
+#include "cobalt/system_window/system_window.h"
 #include "media/base/shell_media_platform.h"
 #include "media/base/shell_video_frame_provider.h"
 #include "media/filters/shell_video_decoder_impl.h"
@@ -127,7 +128,7 @@
   // This function should be defined on individual platform to create the
   // platform specific MediaModule.
   static scoped_ptr<MediaModule> Create(
-      const math::Size& output_size,
+      system_window::SystemWindow* system_window, const math::Size& output_size,
       render_tree::ResourceProvider* resource_provider,
       const Options& options = Options());
 
diff --git a/src/cobalt/media/media_module_starboard.cc b/src/cobalt/media/media_module_starboard.cc
index 5e388a1..4c54544 100644
--- a/src/cobalt/media/media_module_starboard.cc
+++ b/src/cobalt/media/media_module_starboard.cc
@@ -18,8 +18,10 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "cobalt/base/polymorphic_downcast.h"
 #include "cobalt/math/size.h"
 #include "cobalt/media/shell_media_platform_starboard.h"
+#include "cobalt/system_window/starboard/system_window.h"
 #include "media/audio/null_audio_streamer.h"
 #include "media/audio/shell_audio_sink.h"
 #include "media/base/filter_collection.h"
@@ -31,20 +33,26 @@
 #include "media/filters/shell_video_decoder_impl.h"
 #include "media/player/web_media_player_impl.h"
 #include "starboard/media.h"
+#include "starboard/window.h"
 
 namespace cobalt {
 namespace media {
 
 namespace {
 
+using ::base::polymorphic_downcast;
 using ::media::FilterCollection;
 using ::media::MessageLoopFactory;
+using system_window::SystemWindowStarboard;
 
 class MediaModuleStarboard : public MediaModule {
  public:
-  MediaModuleStarboard(render_tree::ResourceProvider* resource_provider,
+  MediaModuleStarboard(system_window::SystemWindow* system_window,
+                       render_tree::ResourceProvider* resource_provider,
                        const Options& options)
-      : options_(options), media_platform_(resource_provider) {}
+      : options_(options),
+        system_window_(system_window),
+        media_platform_(resource_provider) {}
 
   std::string CanPlayType(const std::string& mime_type,
                           const std::string& key_system) OVERRIDE {
@@ -76,25 +84,31 @@
       DLOG(INFO) << "Use Pulse audio";
       streamer = ::media::ShellAudioStreamer::Instance();
     }
+    SbWindow window = kSbWindowInvalid;
+    if (system_window_) {
+      window = polymorphic_downcast<SystemWindowStarboard*>(system_window_)
+                   ->GetSbWindow();
+    }
     return make_scoped_ptr<WebMediaPlayer>(new ::media::WebMediaPlayerImpl(
-        client, this, media_platform_.GetVideoFrameProvider(),
+        window, client, this, media_platform_.GetVideoFrameProvider(),
         filter_collection.Pass(), new ::media::ShellAudioSink(streamer),
         message_loop_factory.Pass(), new ::media::MediaLog));
   }
 
  private:
   const Options options_;
+  system_window::SystemWindow* system_window_;
   ::media::ShellMediaPlatformStarboard media_platform_;
 };
 
 }  // namespace
 
 scoped_ptr<MediaModule> MediaModule::Create(
-    const math::Size& output_size,
+    system_window::SystemWindow* system_window, const math::Size& output_size,
     render_tree::ResourceProvider* resource_provider, const Options& options) {
   UNREFERENCED_PARAMETER(output_size);
   return make_scoped_ptr<MediaModule>(
-      new MediaModuleStarboard(resource_provider, options));
+      new MediaModuleStarboard(system_window, resource_provider, options));
 }
 
 }  // namespace media
diff --git a/src/cobalt/media/media_module_win.cc b/src/cobalt/media/media_module_win.cc
index dffc6a5..0f614e0 100644
--- a/src/cobalt/media/media_module_win.cc
+++ b/src/cobalt/media/media_module_win.cc
@@ -27,8 +27,9 @@
 // There is no media stack on Windows and the XB1 media stack cannot be used
 // directly on Windows. So MediaModule on windows does nothing.
 scoped_ptr<MediaModule> MediaModule::Create(
-    const math::Size& output_size,
+    system_window::SystemWindow* system_window, const math::Size& output_size,
     render_tree::ResourceProvider* resource_provider, const Options& options) {
+  UNREFERENCED_PARAMETER(system_window);
   UNREFERENCED_PARAMETER(output_size);
   UNREFERENCED_PARAMETER(resource_provider);
   UNREFERENCED_PARAMETER(options);
diff --git a/src/cobalt/media/sandbox/fuzzer_app.cc b/src/cobalt/media/sandbox/fuzzer_app.cc
index 4495e34..1620e5a 100644
--- a/src/cobalt/media/sandbox/fuzzer_app.cc
+++ b/src/cobalt/media/sandbox/fuzzer_app.cc
@@ -42,18 +42,24 @@
   DCHECK_GT(number_of_iterations_, 0);
 
   for (int i = 0; i < number_of_iterations_; ++i) {
-    for (size_t file_index = 0; file_index < file_entries_.size();
-         ++file_index) {
-      LOG(INFO) << "Fuzzing \"" << file_entries_[file_index].file_name << "\" "
-                << "with seed " << file_entries_[file_index].fuzzer.seed();
+    for (FileEntries::iterator iter = file_entries_.begin();
+         iter != file_entries_.end(); ++iter) {
+      LOG(INFO) << "Fuzzing \"" << iter->first << "\" "
+                << "with seed " << iter->second.fuzzer.seed();
 
-      Fuzz(file_entries_[file_index].file_name,
-           file_entries_[file_index].fuzzer.GetFuzzedContent());
-      file_entries_[file_index].fuzzer.AdvanceSeed();
+      Fuzz(iter->first, iter->second.fuzzer.GetFuzzedContent());
+      iter->second.fuzzer.AdvanceSeed();
     }
   }
 }
 
+const std::vector<uint8>& FuzzerApp::GetFileContent(
+    const std::string& filename) const {
+  FileEntries::const_iterator iter = file_entries_.find(filename);
+  DCHECK(iter != file_entries_.end());
+  return iter->second.file_content;
+}
+
 bool FuzzerApp::ParseInitialSeedAndNumberOfIterations(int argc, char* argv[],
                                                       int* initial_seed) {
   DCHECK(initial_seed);
@@ -137,17 +143,16 @@
   if (parsed_content.empty()) {
     return;
   }
-  file_entries_.push_back(FileEntry(file_name, uint8_content, parsed_content,
-                                    min_ratio, max_ratio, initial_seed));
+  file_entries_.insert(
+      std::make_pair(file_name, FileEntry(uint8_content, parsed_content,
+                                          min_ratio, max_ratio, initial_seed)));
 }
 
-FuzzerApp::FileEntry::FileEntry(const std::string& file_name,
-                                const std::vector<uint8>& file_content,
+FuzzerApp::FileEntry::FileEntry(const std::vector<uint8>& file_content,
                                 const std::vector<uint8>& fuzz_content,
                                 double min_ratio, double max_ratio,
                                 int initial_seed)
-    : file_name(file_name),
-      file_content(file_content),
+    : file_content(file_content),
       fuzzer(fuzz_content, min_ratio, max_ratio, initial_seed) {}
 
 }  // namespace sandbox
diff --git a/src/cobalt/media/sandbox/fuzzer_app.h b/src/cobalt/media/sandbox/fuzzer_app.h
index 03292a3..ab4a791 100644
--- a/src/cobalt/media/sandbox/fuzzer_app.h
+++ b/src/cobalt/media/sandbox/fuzzer_app.h
@@ -17,6 +17,7 @@
 #ifndef COBALT_MEDIA_SANDBOX_FUZZER_APP_H_
 #define COBALT_MEDIA_SANDBOX_FUZZER_APP_H_
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -52,18 +53,20 @@
  protected:
   ~FuzzerApp() {}
 
+  const std::vector<uint8>& GetFileContent(const std::string& filename) const;
+
  private:
   struct FileEntry {
-    std::string file_name;
     std::vector<uint8> file_content;
     ZzufFuzzer fuzzer;
 
-    FileEntry(const std::string& file_name,
-              const std::vector<uint8>& file_content,
+    FileEntry(const std::vector<uint8>& file_content,
               const std::vector<uint8>& fuzz_content, double min_ratio,
               double max_ratio, int initial_seed);
   };
 
+  typedef std::map<std::string, FileEntry> FileEntries;
+
   bool ParseInitialSeedAndNumberOfIterations(int argc, char* argv[],
                                              int* initial_seed);
   void CollectFiles(const std::string& path_name, double min_ratio,
@@ -72,7 +75,8 @@
                int initial_seed);
 
   int number_of_iterations_;
-  std::vector<FileEntry> file_entries_;
+  // Map from filename to file data.
+  FileEntries file_entries_;
 };
 
 }  // namespace sandbox
diff --git a/src/cobalt/media/sandbox/media_sandbox.cc b/src/cobalt/media/sandbox/media_sandbox.cc
index 4f3a1a3..3a023e5 100644
--- a/src/cobalt/media/sandbox/media_sandbox.cc
+++ b/src/cobalt/media/sandbox/media_sandbox.cc
@@ -99,10 +99,10 @@
   }
 #endif  // defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
 
-  media_module_ =
-      MediaModule::Create(renderer_module_->render_target()->GetSize(),
-                          renderer_module_->pipeline()->GetResourceProvider(),
-                          media_module_options);
+  media_module_ = MediaModule::Create(
+      system_window_.get(), renderer_module_->render_target()->GetSize(),
+      renderer_module_->pipeline()->GetResourceProvider(),
+      media_module_options);
   SetupAndSubmitScene();
 }
 
diff --git a/src/cobalt/media/sandbox/media_source_demuxer.cc b/src/cobalt/media/sandbox/media_source_demuxer.cc
index b657f27..0044342 100644
--- a/src/cobalt/media/sandbox/media_source_demuxer.cc
+++ b/src/cobalt/media/sandbox/media_source_demuxer.cc
@@ -24,6 +24,7 @@
 #include "base/file_util.h"
 #include "base/logging.h"
 #include "base/message_loop.h"
+#include "base/sys_byteorder.h"
 #include "media/base/bind_to_loop.h"
 #include "media/base/demuxer.h"
 #include "media/base/pipeline_status.h"
@@ -41,6 +42,8 @@
 using ::media::DemuxerStream;
 using ::media::ChunkDemuxer;
 
+typedef base::Callback<void(::media::Buffer*)> AppendBufferCB;
+
 const char kSourceId[] = "id";
 
 // Stub log function.
@@ -80,8 +83,6 @@
 // every frame.
 class Loader : public ::media::DemuxerHost {
  public:
-  typedef base::Callback<void(::media::Buffer*)> AppendBufferCB;
-
   Loader(const std::vector<uint8>& content,
          const AppendBufferCB& append_buffer_cb)
       : valid_(true),
@@ -214,10 +215,48 @@
   ::media::VideoDecoderConfig config_;
 };
 
+// This is a very loose IVF parser for fuzzing purpose and it ignores any
+// invalid structure and just retrieves the frame data.
+// IVF format (all data is little endian):
+//   32 bytes file header starts with DKIF
+//     (4 bytes frame size + 8 bytes timestamp + <size> bytes frame data)*
+bool LoadIVF(const std::vector<uint8>& content,
+             const AppendBufferCB& append_buffer_cb) {
+  const size_t kIVFFileHeaderSize = 32;
+  const size_t kIVFFrameHeaderSize = 12;
+  if (content.size() < kIVFFileHeaderSize ||
+      memcmp(&content[0], "DKIF", 4) != 0) {
+    return false;
+  }
+  size_t offset = kIVFFileHeaderSize;
+  while (offset + kIVFFrameHeaderSize < content.size()) {
+    uint32 frame_size = base::ByteSwapToLE32(
+        *reinterpret_cast<const uint32*>(&content[offset]));
+    offset += kIVFFrameHeaderSize;
+    if (offset + frame_size > content.size()) {
+      break;
+    }
+    append_buffer_cb.Run(::media::StreamParserBuffer::CopyFrom(
+        &content[offset], frame_size, false));
+    offset += frame_size;
+  }
+  return true;
+}
+
 }  // namespace
 
 MediaSourceDemuxer::MediaSourceDemuxer(const std::vector<uint8>& content)
     : valid_(true) {
+  // Try to load it as an ivf first.
+  if (LoadIVF(content, Bind(&MediaSourceDemuxer::AppendBuffer,
+                            base::Unretained(this)))) {
+    config_.Initialize(::media::kCodecVP9, ::media::VP9PROFILE_MAIN,
+                       ::media::VideoFrame::YV12, gfx::Size(1, 1),
+                       gfx::Rect(1, 1), gfx::Size(1, 1), NULL, 0, false, false);
+    valid_ = descs_.size() > 0;
+    return;
+  }
+
   Loader loader(
       content, Bind(&MediaSourceDemuxer::AppendBuffer, base::Unretained(this)));
   valid_ = loader.valid();
diff --git a/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc b/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc
index 724287e..d0f37ef 100644
--- a/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc
+++ b/src/cobalt/media/sandbox/raw_video_decoder_fuzzer.cc
@@ -134,9 +134,13 @@
 // This function replace the original data inside the original file with the
 // fuzzed data to created a valid container with fuzzed AUs.  |filename| should
 // contain a file that inside a path readable by the host.
+// The following statement can be used inside RawVideoDecoderFuzzerApp::Fuzz()
+// to save the fuzzing content back into its original container format.
+//   DumpFuzzedData(filename, GetFileContent(file_name), *demuxers_[file_name],
+//                  fuzzing_content);
 void DumpFuzzedData(const std::string& filename, std::vector<uint8> container,
                     const MediaSourceDemuxer& demuxer,
-                    const ZzufFuzzer& fuzzer) {
+                    const std::vector<uint8>& fuzzing_content) {
   std::vector<uint8>::iterator last_found = container.begin();
   for (size_t i = 0; i < demuxer.GetFrameCount(); ++i) {
     MediaSourceDemuxer::AUDescriptor desc = demuxer.GetFrame(i);
@@ -145,9 +149,8 @@
     std::vector<uint8>::const_iterator end = begin + desc.size;
     std::vector<uint8>::iterator offset =
         std::search(last_found, container.end(), begin, end);
-    std::copy(fuzzer.GetFuzzedContent().begin() + desc.offset,
-              fuzzer.GetFuzzedContent().begin() + desc.offset + desc.size,
-              offset);
+    std::copy(fuzzing_content.begin() + desc.offset,
+              fuzzing_content.begin() + desc.offset + desc.size, offset);
     last_found = offset + desc.size + 1;
   }
   file_util::WriteFile(FilePath(filename),
@@ -170,7 +173,7 @@
       const std::string& file_name,
       const std::vector<uint8>& file_content) OVERRIDE {
     std::string ext = FilePath(file_name).Extension();
-    if (ext != ".webm" && ext != ".mp4") {
+    if (ext != ".webm" && ext != ".mp4" && ext != ".ivf") {
       LOG(ERROR) << "Skip unsupported file " << file_name;
       return std::vector<uint8>();
     }
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 6fdc38e..a9e2aac 100644
--- a/src/cobalt/render_tree/dump_render_tree_to_string.cc
+++ b/src/cobalt/render_tree/dump_render_tree_to_string.cc
@@ -141,8 +141,41 @@
   result_ << "\n";
 }
 
+namespace {
+class BrushPrinterVisitor : public render_tree::BrushVisitor {
+ public:
+  BrushPrinterVisitor() {}
+
+  void Visit(
+      const cobalt::render_tree::SolidColorBrush* solid_color_brush) OVERRIDE {
+    UNREFERENCED_PARAMETER(solid_color_brush);
+    brush_type_ = "(SolidColorBrush)";
+  }
+  void Visit(const cobalt::render_tree::LinearGradientBrush*
+                 linear_gradient_brush) OVERRIDE {
+    UNREFERENCED_PARAMETER(linear_gradient_brush);
+    brush_type_ = "(LinearGradientBrush)";
+  }
+  void Visit(const cobalt::render_tree::RadialGradientBrush*
+                 radial_gradient_brush) OVERRIDE {
+    UNREFERENCED_PARAMETER(radial_gradient_brush);
+    brush_type_ = "(RadialGradientBrush)";
+  }
+
+  const std::string& brush_type() const { return brush_type_; }
+
+ private:
+  std::string brush_type_;
+};
+}  // namespace
+
 void DebugTreePrinter::Visit(RectNode* rect) {
-  AddNamedNodeString(rect, "RectNode");
+  AddNamedNodeString(rect, "RectNode ");
+  if (rect->data().background_brush) {
+    BrushPrinterVisitor printer_brush_visitor;
+    rect->data().background_brush->Accept(&printer_brush_visitor);
+    result_ << printer_brush_visitor.brush_type();
+  }
   result_ << "\n";
 }
 
diff --git a/src/cobalt/render_tree/filter_node.cc b/src/cobalt/render_tree/filter_node.cc
index e4cfc50..bca254e 100644
--- a/src/cobalt/render_tree/filter_node.cc
+++ b/src/cobalt/render_tree/filter_node.cc
@@ -35,6 +35,10 @@
                              const scoped_refptr<render_tree::Node>& source)
     : source(source), blur_filter(blur_filter) {}
 
+FilterNode::Builder::Builder(const MapToMeshFilter& map_to_mesh_filter,
+                             const scoped_refptr<render_tree::Node>& source)
+    : source(source), map_to_mesh_filter(map_to_mesh_filter) {}
+
 FilterNode::FilterNode(const OpacityFilter& opacity_filter,
                        const scoped_refptr<render_tree::Node>& source)
     : data_(opacity_filter, source) {}
@@ -47,6 +51,10 @@
                        const scoped_refptr<render_tree::Node>& source)
     : data_(blur_filter, source) {}
 
+FilterNode::FilterNode(const MapToMeshFilter& map_to_mesh_filter,
+                       const scoped_refptr<render_tree::Node>& source)
+    : data_(map_to_mesh_filter, source) {}
+
 void FilterNode::Accept(NodeVisitor* visitor) { visitor->Visit(this); }
 
 math::RectF FilterNode::Builder::GetBounds() const {
diff --git a/src/cobalt/render_tree/filter_node.h b/src/cobalt/render_tree/filter_node.h
index 7e2a941..f5b3b2d 100644
--- a/src/cobalt/render_tree/filter_node.h
+++ b/src/cobalt/render_tree/filter_node.h
@@ -21,6 +21,7 @@
 #include "base/optional.h"
 #include "cobalt/base/type_id.h"
 #include "cobalt/render_tree/blur_filter.h"
+#include "cobalt/render_tree/map_to_mesh_filter.h"
 #include "cobalt/render_tree/node.h"
 #include "cobalt/render_tree/opacity_filter.h"
 #include "cobalt/render_tree/shadow.h"
@@ -47,6 +48,9 @@
     Builder(const BlurFilter& blur_filter,
             const scoped_refptr<render_tree::Node>& source);
 
+    Builder(const MapToMeshFilter& map_to_mesh_filter,
+            const scoped_refptr<render_tree::Node>& source);
+
     math::RectF GetBounds() const;
 
     // The source tree, which will be used as the input to the filters specified
@@ -65,6 +69,11 @@
     // If set, then a Gaussian blur will be applied to the source with a
     // Gaussian kernel of standard deviation |blur_sigma|.
     base::optional<BlurFilter> blur_filter;
+
+    // If set, indicates that the rasterized output of the source content should
+    // be used as a texture which is then mapped onto a 3D mesh specified by the
+    // filter.
+    base::optional<MapToMeshFilter> map_to_mesh_filter;
   };
 
   explicit FilterNode(const Builder& builder) : data_(builder) {}
@@ -78,6 +87,9 @@
   FilterNode(const BlurFilter& blur_filter,
              const scoped_refptr<render_tree::Node>& source);
 
+  FilterNode(const MapToMeshFilter& map_to_mesh_filter,
+             const scoped_refptr<render_tree::Node>& source);
+
   void Accept(NodeVisitor* visitor) OVERRIDE;
   math::RectF GetBounds() const OVERRIDE { return data_.GetBounds(); }
 
diff --git a/src/cobalt/render_tree/map_to_mesh_filter.h b/src/cobalt/render_tree/map_to_mesh_filter.h
new file mode 100644
index 0000000..5451c11
--- /dev/null
+++ b/src/cobalt/render_tree/map_to_mesh_filter.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_RENDER_TREE_MAP_TO_MESH_FILTER_H_
+#define COBALT_RENDER_TREE_MAP_TO_MESH_FILTER_H_
+
+namespace cobalt {
+namespace render_tree {
+
+// A MapToMeshFilter can be used to map source content onto a 3D mesh, within a
+// specified well-defined viewport.
+class MapToMeshFilter {
+ public:
+  MapToMeshFilter() {}
+};
+
+}  // namespace render_tree
+}  // namespace cobalt
+
+#endif  // COBALT_RENDER_TREE_MAP_TO_MESH_FILTER_H_
diff --git a/src/cobalt/render_tree/node_visitor_test.cc b/src/cobalt/render_tree/node_visitor_test.cc
index 7a24cc4..ad7c3b2 100644
--- a/src/cobalt/render_tree/node_visitor_test.cc
+++ b/src/cobalt/render_tree/node_visitor_test.cc
@@ -18,6 +18,7 @@
 
 #include <string>
 
+#include "base/bind.h"
 #include "cobalt/math/rect_f.h"
 #include "cobalt/math/size.h"
 #include "cobalt/render_tree/animations/animate_node.h"
@@ -100,6 +101,8 @@
   }
 };
 
+void SetBounds(const cobalt::math::Rect&) {}
+
 }  // namespace
 
 TEST(NodeVisitorTest, VisitsAnimate) {
@@ -128,8 +131,10 @@
 }
 
 TEST(NodeVisitorTest, VisitsPunchThroughVideo) {
+  PunchThroughVideoNode::Builder builder(cobalt::math::RectF(),
+                                         base::Bind(SetBounds));
   scoped_refptr<PunchThroughVideoNode> punch_through_video_node(
-      new PunchThroughVideoNode(cobalt::math::RectF()));
+      new PunchThroughVideoNode(builder));
   MockNodeVisitor mock_visitor;
   EXPECT_CALL(mock_visitor, Visit(punch_through_video_node.get()));
   punch_through_video_node->Accept(&mock_visitor);
diff --git a/src/cobalt/render_tree/punch_through_video_node.h b/src/cobalt/render_tree/punch_through_video_node.h
index 99f02b0..7261ab7 100644
--- a/src/cobalt/render_tree/punch_through_video_node.h
+++ b/src/cobalt/render_tree/punch_through_video_node.h
@@ -17,8 +17,10 @@
 #ifndef COBALT_RENDER_TREE_PUNCH_THROUGH_VIDEO_NODE_H_
 #define COBALT_RENDER_TREE_PUNCH_THROUGH_VIDEO_NODE_H_
 
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "cobalt/base/type_id.h"
+#include "cobalt/math/rect.h"
 #include "cobalt/math/rect_f.h"
 #include "cobalt/render_tree/node.h"
 
@@ -39,15 +41,17 @@
 //          support punch out video rendering.
 class PunchThroughVideoNode : public Node {
  public:
-  class Builder {
-   public:
-    explicit Builder(const math::RectF& rect) : rect(rect) {}
+  typedef base::Callback<void(const math::Rect&)> SetBoundsCB;
+
+  struct Builder {
+    Builder(const math::RectF& rect, const SetBoundsCB& set_bounds_cb)
+        : rect(rect), set_bounds_cb(set_bounds_cb) {}
 
     // The destination rectangle (size includes border).
     math::RectF rect;
+    const SetBoundsCB set_bounds_cb;
   };
 
-  explicit PunchThroughVideoNode(const math::RectF& rect) : data_(rect) {}
   explicit PunchThroughVideoNode(const Builder& builder) : data_(builder) {}
 
   void Accept(NodeVisitor* visitor) OVERRIDE;
diff --git a/src/cobalt/render_tree/render_tree.gyp b/src/cobalt/render_tree/render_tree.gyp
index 6e7c6a7..5d6f1a6 100644
--- a/src/cobalt/render_tree/render_tree.gyp
+++ b/src/cobalt/render_tree/render_tree.gyp
@@ -25,6 +25,7 @@
       'target_name': 'render_tree',
       'type': 'static_library',
       'sources': [
+        'blur_filter.h',
         'border.cc',
         'border.h',
         'brush.cc',
@@ -43,6 +44,7 @@
         'glyph_buffer.h',
         'image_node.cc',
         'image_node.h',
+        'map_to_mesh_filter.h',
         'matrix_transform_node.cc',
         'matrix_transform_node.h',
         'node.h',
diff --git a/src/cobalt/renderer/backend/egl/graphics_context.cc b/src/cobalt/renderer/backend/egl/graphics_context.cc
index a418417..3482472 100644
--- a/src/cobalt/renderer/backend/egl/graphics_context.cc
+++ b/src/cobalt/renderer/backend/egl/graphics_context.cc
@@ -14,12 +14,11 @@
  * limitations under the License.
  */
 
-#include "cobalt/renderer/backend/egl/graphics_context.h"
-
 #include <GLES2/gl2.h>
-
 #include <algorithm>
 
+#include "cobalt/renderer/backend/egl/graphics_context.h"
+
 #include "base/debug/trace_event.h"
 #include "cobalt/base/polymorphic_downcast.h"
 #include "cobalt/renderer/backend/egl/graphics_system.h"
@@ -155,16 +154,14 @@
   blit_program_ = glCreateProgram();
 
   blit_vertex_shader_ = glCreateShader(GL_VERTEX_SHADER);
-  const char* blit_vertex_shader_source = "\
-      attribute vec2 a_position;\
-      attribute vec2 a_tex_coord;\
-      varying vec2 v_tex_coord;\
-      \
-      void main() {\
-        gl_Position = vec4(a_position.x, a_position.y, 0, 1);\
-        v_tex_coord = a_tex_coord;\
-      }\
-      ";
+  const char* blit_vertex_shader_source =
+      "attribute vec2 a_position;"
+      "attribute vec2 a_tex_coord;"
+      "varying vec2 v_tex_coord;"
+      "void main() {"
+      "  gl_Position = vec4(a_position.x, a_position.y, 0, 1);"
+      "  v_tex_coord = a_tex_coord;"
+      "}";
   int blit_vertex_shader_source_length = strlen(blit_vertex_shader_source);
   GL_CALL(glShaderSource(blit_vertex_shader_, 1, &blit_vertex_shader_source,
                          &blit_vertex_shader_source_length));
@@ -172,15 +169,13 @@
   GL_CALL(glAttachShader(blit_program_, blit_vertex_shader_));
 
   blit_fragment_shader_ = glCreateShader(GL_FRAGMENT_SHADER);
-  const char* blit_fragment_shader_source = "\
-      precision mediump float;\
-      varying vec2 v_tex_coord;\
-      uniform sampler2D texture;\
-      \
-      void main() {\
-      gl_FragColor = texture2D(texture, v_tex_coord);\
-      }\
-      ";
+  const char* blit_fragment_shader_source =
+      "precision mediump float;"
+      "varying vec2 v_tex_coord;"
+      "uniform sampler2D texture;"
+      "void main() {"
+      "  gl_FragColor = texture2D(texture, v_tex_coord);"
+      "}";
   int blit_fragment_shader_source_length = strlen(blit_fragment_shader_source);
   GL_CALL(glShaderSource(blit_fragment_shader_, 1, &blit_fragment_shader_source,
                          &blit_fragment_shader_source_length));
@@ -202,7 +197,7 @@
     float tex_coord_u;
     float tex_coord_v;
   };
-  const QuadVertex kQuadVerts[4] = {
+  const QuadVertex kBlitQuadVerts[4] = {
       {-1.0f, -1.0f, 0.0f, 1.0f},
       {-1.0f, 1.0f, 0.0f, 0.0f},
       {1.0f, -1.0f, 1.0f, 1.0f},
@@ -210,13 +205,12 @@
   };
   GL_CALL(glGenBuffers(1, &blit_vertex_buffer_));
   GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, blit_vertex_buffer_));
-  GL_CALL(glBufferData(
-      GL_ARRAY_BUFFER, sizeof(kQuadVerts), kQuadVerts, GL_STATIC_DRAW));
+  GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(kBlitQuadVerts), kBlitQuadVerts,
+                       GL_STATIC_DRAW));
 }
 
 GraphicsContextEGL::~GraphicsContextEGL() {
   MakeCurrent();
-
   GL_CALL(glDeleteBuffers(1, &blit_vertex_buffer_));
   GL_CALL(glDeleteProgram(blit_program_));
   GL_CALL(glDeleteShader(blit_fragment_shader_));
@@ -399,8 +393,8 @@
 }
 
 void GraphicsContextEGL::SecurityClear() {
-  // Clear the screen to a color that is bright and gross to exagerate that this
-  // is a problem if it is witnessed.
+  // Clear the screen to a color that is bright and gross to exaggerate that
+  // this is a problem if it is witnessed.
   GL_CALL(glClearColor(1.0f, 0.4f, 1.0f, 1.0f));
   GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
 }
diff --git a/src/cobalt/renderer/default_options_starboard.gyp b/src/cobalt/renderer/default_options_starboard.gyp
new file mode 100644
index 0000000..990ffa6
--- /dev/null
+++ b/src/cobalt/renderer/default_options_starboard.gyp
@@ -0,0 +1,28 @@
+# 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.
+
+{
+  'targets': [
+    {
+     'target_name': 'default_options',
+      'type': 'static_library',
+      'includes': [
+        'renderer_parameters_setup.gypi',
+      ],
+      'sources': [
+        '<(DEPTH)/cobalt/renderer/renderer_module_default_options_starboard.cc',
+      ],
+    },
+  ],
+}
diff --git a/src/cobalt/renderer/pipeline.cc b/src/cobalt/renderer/pipeline.cc
index a5f38e7..a1c5aba 100644
--- a/src/cobalt/renderer/pipeline.cc
+++ b/src/cobalt/renderer/pipeline.cc
@@ -21,6 +21,7 @@
 #include "base/file_path.h"
 #include "base/file_util.h"
 #include "base/path_service.h"
+#include "cobalt/base/address_sanitizer.h"
 #include "cobalt/base/cobalt_paths.h"
 #include "cobalt/base/polymorphic_downcast.h"
 #include "cobalt/render_tree/dump_render_tree_to_string.h"
@@ -45,7 +46,8 @@
 
 // The stack size to be used for the renderer thread.  This is must be large
 // enough to support recursing on the render tree.
-const int kRendererThreadStackSize = 128 * 1024;
+const int kRendererThreadStackSize =
+    128 * 1024 + base::kAsanAdditionalStackSize;
 
 // How frequently the CVal stats for rasterize current tree timing should
 // update. The time interval is in milliseconds.
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 3f37aeb..12475b8 100644
--- a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
@@ -242,9 +242,16 @@
     render_tree::PunchThroughVideoNode* punch_through_video_node) {
   SbBlitterSetColor(context_, SbBlitterColorFromRGBA(0, 0, 0, 0));
   SbBlitterSetBlending(context_, false);
-  SbBlitterFillRect(context_,
-                    RectFToBlitterRect(render_state_.transform.TransformRect(
-                        punch_through_video_node->data().rect)));
+  SbBlitterRect blitter_rect =
+      RectFToBlitterRect(render_state_.transform.TransformRect(
+          punch_through_video_node->data().rect));
+  SbBlitterFillRect(context_, blitter_rect);
+
+  if (!punch_through_video_node->data().set_bounds_cb.is_null()) {
+    punch_through_video_node->data().set_bounds_cb.Run(
+        math::Rect(blitter_rect.x, blitter_rect.y, blitter_rect.width,
+                   blitter_rect.height));
+  }
 }
 
 namespace {
diff --git a/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.cc b/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.cc
index d9b3790..d1d4292 100644
--- a/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/scratch_surface_cache.cc
@@ -55,10 +55,13 @@
 
 common::ScratchSurfaceCache::Surface*
 ScratchSurfaceCache::Delegate::CreateSurface(const math::Size& size) {
-  return new BlitterSurface(
-      SbBlitterCreateRenderTargetSurface(device_, size.width(), size.height(),
-                                         kSbBlitterSurfaceFormatRGBA8),
-      size);
+  SbBlitterSurface blitter_surface = SbBlitterCreateRenderTargetSurface(
+      device_, size.width(), size.height(), kSbBlitterSurfaceFormatRGBA8);
+  if (SbBlitterIsSurfaceValid(blitter_surface)) {
+    return new BlitterSurface(blitter_surface, size);
+  } else {
+    return NULL;
+  }
 }
 
 void ScratchSurfaceCache::Delegate::DestroySurface(
@@ -80,9 +83,13 @@
 }
 
 SbBlitterSurface CachedScratchSurface::GetSurface() {
-  return base::polymorphic_downcast<BlitterSurface*>(
-             common_scratch_surface_.GetSurface())
-      ->blitter_surface();
+  if (common_scratch_surface_.GetSurface()) {
+    return base::polymorphic_downcast<BlitterSurface*>(
+               common_scratch_surface_.GetSurface())
+        ->blitter_surface();
+  } else {
+    return NULL;
+  }
 }
 
 }  // namespace blitter
diff --git a/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.cc b/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.cc
index dac975b..6c6b358 100644
--- a/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.cc
+++ b/src/cobalt/renderer/rasterizer/common/scratch_surface_cache.cc
@@ -54,6 +54,17 @@
   TRACE_EVENT2("cobalt::renderer",
                "ScratchSurfaceCache::AcquireScratchSurface()", "width",
                size.width(), "height", size.height());
+  if (cache_capacity_in_bytes_ == 0) {
+    // If scratch surface caching is disabled, just create and immediately
+    // return a surface.
+    Surface* surface = delegate_->CreateSurface(size);
+    if (surface) {
+      delegate_->PrepareForUse(surface, size);
+      return surface;
+    } else {
+      return NULL;
+    }
+  }
 
   // First check if we can find a suitable surface in our cache that is at
   // least the size requested.
@@ -93,6 +104,12 @@
                "ScratchSurfaceCache::ReleaseScratchSurface()", "width",
                surface->GetSize().width(), "height",
                surface->GetSize().height());
+  if (cache_capacity_in_bytes_ == 0) {
+    // If scratch surface caching is disabled, immediately destroy the surface
+    // and return.
+    delegate_->DestroySurface(surface);
+    return;
+  }
 
   DCHECK_EQ(surface_stack_.back(), surface);
   surface_stack_.pop_back();
diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc
index 5fde5c2..6dc87b7 100644
--- a/src/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -16,6 +16,7 @@
 
 #include <cmath>
 
+#include "base/bind.h"
 #include "cobalt/math/matrix3_f.h"
 #include "cobalt/math/rect_f.h"
 #include "cobalt/math/size_f.h"
@@ -110,6 +111,12 @@
 namespace renderer {
 namespace rasterizer {
 
+namespace {
+
+void SetBounds(const math::Rect&) {}
+
+}  // namespace
+
 TEST_F(PixelTest, RedFillRectOnEntireSurface) {
   // Create a test render tree that will fill the entire output surface
   // with a solid color rectangle.
@@ -2748,7 +2755,8 @@
                                 scoped_ptr<Brush>(new SolidColorBrush(
                                     ColorRGBA(0.5f, 0.5f, 1.0f, 1.0f)))));
 
-  builder.AddChild(new PunchThroughVideoNode(RectF(50, 50, 100, 100)));
+  builder.AddChild(new PunchThroughVideoNode(PunchThroughVideoNode::Builder(
+      RectF(50, 50, 100, 100), base::Bind(SetBounds))));
 
   TestTree(new CompositionNode(builder.Pass()));
 }
diff --git a/src/cobalt/renderer/rasterizer/skia/rasterizer.gyp b/src/cobalt/renderer/rasterizer/skia/rasterizer.gyp
index 43555a0..cd5c0c0 100644
--- a/src/cobalt/renderer/rasterizer/skia/rasterizer.gyp
+++ b/src/cobalt/renderer/rasterizer/skia/rasterizer.gyp
@@ -40,4 +40,4 @@
       ],
     },
   ],
-}
\ No newline at end of file
+}
diff --git a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
index 1f8996b..8a34aff 100644
--- a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
@@ -74,7 +74,7 @@
     const CreateScratchSurfaceFunction* create_scratch_surface_function,
     SurfaceCacheDelegate* surface_cache_delegate,
     common::SurfaceCache* surface_cache, Type visitor_type)
-    : render_target_(render_target),
+    : draw_state_(render_target),
       create_scratch_surface_function_(create_scratch_surface_function),
       surface_cache_delegate_(surface_cache_delegate),
       surface_cache_(surface_cache),
@@ -82,11 +82,9 @@
   DCHECK_EQ(surface_cache_delegate_ == NULL, surface_cache_ == NULL);
   if (surface_cache_delegate_) {
     // Update our surface cache delegate to point to this render tree node
-    // visitor and our canvas.
-    surface_cache_scoped_context_.emplace(
-        surface_cache_delegate_, render_target_,
-        base::Bind(&RenderTreeNodeVisitor::SetRenderTarget,
-                   base::Unretained(this)));
+    // visitor and our draw state.
+    surface_cache_scoped_context_.emplace(surface_cache_delegate_,
+                                          &draw_state_);
   }
 }
 
@@ -124,8 +122,8 @@
     return;
   }
 
-  render_target_->translate(composition_node->data().offset().x(),
-                            composition_node->data().offset().y());
+  draw_state_.render_target->translate(composition_node->data().offset().x(),
+                                       composition_node->data().offset().y());
 
   // If we have more than one child (there is little to be gained by performing
   // these calculations otherwise since our bounding rectangle is equal to
@@ -136,9 +134,9 @@
   base::optional<SkMatrix> total_matrix;
   if (children.size() > 1) {
     SkIRect canvas_boundsi;
-    render_target_->getClipDeviceBounds(&canvas_boundsi);
+    draw_state_.render_target->getClipDeviceBounds(&canvas_boundsi);
     canvas_bounds = SkRect::Make(canvas_boundsi);
-    total_matrix = render_target_->getTotalMatrix();
+    total_matrix = draw_state_.render_target->getTotalMatrix();
   }
 
   for (render_tree::CompositionNode::Children::const_iterator iter =
@@ -152,11 +150,11 @@
     }
   }
 
-  render_target_->translate(-composition_node->data().offset().x(),
-                            -composition_node->data().offset().y());
+  draw_state_.render_target->translate(-composition_node->data().offset().x(),
+                                       -composition_node->data().offset().y());
 
 #if ENABLE_FLUSH_AFTER_EVERY_NODE
-  render_target_->flush();
+  draw_state_.render_target->flush();
 #endif
 }
 
@@ -224,11 +222,12 @@
 
 void RenderTreeNodeVisitor::RenderFilterViaOffscreenSurface(
     const render_tree::FilterNode::Builder& filter_node) {
-  const SkMatrix& total_matrix_skia = render_target_->getTotalMatrix();
+  const SkMatrix& total_matrix_skia =
+      draw_state_.render_target->getTotalMatrix();
   math::Matrix3F total_matrix = SkiaMatrixToCobalt(total_matrix_skia);
 
   SkIRect canvas_boundsi;
-  render_target_->getClipDeviceBounds(&canvas_boundsi);
+  draw_state_.render_target->getClipDeviceBounds(&canvas_boundsi);
 
   common::OffscreenRenderCoordinateMapping coord_mapping =
       common::GetOffscreenRenderCoordinateMapping(
@@ -282,13 +281,13 @@
   // destination rectangles should be exactly equal.
   paint.setFilterLevel(SkPaint::kNone_FilterLevel);
 
-  // We've already used the render_target_'s scale when rendering to the
-  // offscreen surface, so reset the scale for now.
-  render_target_->save();
+  // We've already used the draw_state_.render_target's scale when rendering to
+  // the offscreen surface, so reset the scale for now.
+  draw_state_.render_target->save();
   ApplyBlurFilterToPaint(&paint, filter_node.blur_filter);
-  ApplyViewportMask(render_target_, filter_node.viewport_filter);
+  ApplyViewportMask(draw_state_.render_target, filter_node.viewport_filter);
 
-  render_target_->setMatrix(CobaltMatrixToSkia(
+  draw_state_.render_target->setMatrix(CobaltMatrixToSkia(
       math::TranslateMatrix(coord_mapping.output_pre_translate) * total_matrix *
       math::ScaleMatrix(coord_mapping.output_post_scale)));
 
@@ -304,11 +303,12 @@
   SkRect source_rect = SkRect::MakeWH(coord_mapping.output_bounds.width(),
                                       coord_mapping.output_bounds.height());
 
-  render_target_->drawImageRect(image, &source_rect, dest_rect, &paint);
+  draw_state_.render_target->drawImageRect(image, &source_rect, dest_rect,
+                                           &paint);
 
   // Finally restore our parent render target's original transform for the
   // next draw call.
-  render_target_->restore();
+  draw_state_.render_target->restore();
 }
 
 namespace {
@@ -341,9 +341,33 @@
 
   return false;
 }
+
+bool SourceCanRenderWithOpacity(render_tree::Node* source) {
+  if (source->GetTypeId() == base::GetTypeId<render_tree::ImageNode>() ||
+      source->GetTypeId() == base::GetTypeId<render_tree::RectNode>()) {
+    return true;
+  } else if (source->GetTypeId() ==
+             base::GetTypeId<render_tree::CompositionNode>()) {
+    // If we are a composition of valid sources, then we also allow
+    // rendering through a viewport here.
+    render_tree::CompositionNode* composition_node =
+        base::polymorphic_downcast<render_tree::CompositionNode*>(source);
+    typedef render_tree::CompositionNode::Children Children;
+    const Children& children = composition_node->data().children();
+    if (children.size() == 1 && SourceCanRenderWithOpacity(children[0].get())) {
+      return true;
+    }
+  }
+  return false;
+}
 }  // namespace
 
 void RenderTreeNodeVisitor::Visit(render_tree::FilterNode* filter_node) {
+  if (filter_node->data().map_to_mesh_filter) {
+    // TODO: Implement support for MapToMeshFilter.
+    return;
+  }
+
 #if ENABLE_RENDER_TREE_VISITOR_TRACING
   TRACE_EVENT0("cobalt::renderer", "Visit(FilterNode)");
 
@@ -379,7 +403,7 @@
     return;
   }
 
-  const SkMatrix& total_matrix = render_target_->getTotalMatrix();
+  const SkMatrix& total_matrix = draw_state_.render_target->getTotalMatrix();
 
   bool has_rounded_corners =
       filter_node->data().viewport_filter &&
@@ -395,7 +419,8 @@
       !filter_node->data().blur_filter &&
       // If an opacity filter is being applied, we must render to a separate
       // texture first.
-      !filter_node->data().opacity_filter &&
+      (!filter_node->data().opacity_filter ||
+       SourceCanRenderWithOpacity(filter_node->data().source)) &&
       // If transforms are applied to the viewport, then we will render to
       // a separate texture first.
       total_matrix.rectStaysRect() &&
@@ -407,10 +432,18 @@
        SourceCanRenderWithRoundedCorners(filter_node->data().source));
 
   if (can_render_with_clip_mask_directly) {
-    render_target_->save();
-    ApplyViewportMask(render_target_, filter_node->data().viewport_filter);
+    RenderTreeNodeVisitorDrawState original_draw_state(draw_state_);
+
+    draw_state_.render_target->save();
+    ApplyViewportMask(draw_state_.render_target,
+                      filter_node->data().viewport_filter);
+
+    if (filter_node->data().opacity_filter) {
+      draw_state_.opacity *= filter_node->data().opacity_filter->opacity();
+    }
     filter_node->data().source->Accept(this);
-    render_target_->restore();
+    draw_state_.render_target->restore();
+    draw_state_ = original_draw_state;
   } else {
     common::SurfaceCache::Block cache_block(surface_cache_, filter_node);
     if (cache_block.Cached()) return;
@@ -418,7 +451,7 @@
     RenderFilterViaOffscreenSurface(filter_node->data());
   }
 #if ENABLE_FLUSH_AFTER_EVERY_NODE
-  render_target_->flush();
+  draw_state_.render_target->flush();
 #endif
 }
 
@@ -454,18 +487,23 @@
          mat.Get(1, 2) <= 0.0f && 1.0f - mat.Get(1, 2) <= mat.Get(1, 1);
 }
 
-SkPaint CreateSkPaintForImageRendering() {
+SkPaint CreateSkPaintForImageRendering(
+    const RenderTreeNodeVisitorDrawState& draw_state) {
   SkPaint paint;
   paint.setFilterLevel(SkPaint::kLow_FilterLevel);
 
+  if (draw_state.opacity < 1.0f) {
+    paint.setAlpha(draw_state.opacity * 255);
+  }
+
   return paint;
 }
 
 void RenderSinglePlaneImage(SinglePlaneImage* single_plane_image,
-                            SkCanvas* render_target,
+                            RenderTreeNodeVisitorDrawState* draw_state,
                             const math::RectF& destination_rect,
                             const math::Matrix3F* local_transform) {
-  SkPaint paint = CreateSkPaintForImageRendering();
+  SkPaint paint = CreateSkPaintForImageRendering(*draw_state);
 
   // In the most frequent by far case where the normalized transformed image
   // texture coordinates lie within the unit square, then we must ensure NOT
@@ -486,9 +524,9 @@
 
     SkRect src = SkRect::MakeXYWH(x, y, width, height);
 
-    render_target->drawBitmapRectToRect(single_plane_image->GetBitmap(), &src,
-                                        CobaltRectFToSkiaRect(destination_rect),
-                                        &paint);
+    draw_state->render_target->drawBitmapRectToRect(
+        single_plane_image->GetBitmap(), &src,
+        CobaltRectFToSkiaRect(destination_rect), &paint);
   } else {
     // Use the more general approach which allows arbitrary local texture
     // coordinate matrices.
@@ -502,12 +540,13 @@
         SkShader::kRepeat_TileMode, &skia_local_transform));
     paint.setShader(image_shader);
 
-    render_target->drawRect(CobaltRectFToSkiaRect(destination_rect), paint);
+    draw_state->render_target->drawRect(CobaltRectFToSkiaRect(destination_rect),
+                                        paint);
   }
 }
 
 void RenderMultiPlaneImage(MultiPlaneImage* multi_plane_image,
-                           SkCanvas* render_target,
+                           RenderTreeNodeVisitorDrawState* draw_state,
                            const math::RectF& destination_rect,
                            const math::Matrix3F* local_transform) {
   SkMatrix skia_local_transform = CobaltMatrixToSkia(*local_transform);
@@ -552,9 +591,10 @@
     }
   }
 
-  SkPaint paint = CreateSkPaintForImageRendering();
+  SkPaint paint = CreateSkPaintForImageRendering(*draw_state);
   paint.setShader(yuv2rgb_shader);
-  render_target->drawRect(CobaltRectFToSkiaRect(destination_rect), paint);
+  draw_state->render_target->drawRect(CobaltRectFToSkiaRect(destination_rect),
+                                      paint);
 }
 
 }  // namespace
@@ -588,18 +628,18 @@
   // depending on whether it's single or multi planed.
   if (image->GetTypeId() == base::GetTypeId<SinglePlaneImage>()) {
     RenderSinglePlaneImage(base::polymorphic_downcast<SinglePlaneImage*>(image),
-                           render_target_, image_node->data().destination_rect,
+                           &draw_state_, image_node->data().destination_rect,
                            &(image_node->data().local_transform));
   } else if (image->GetTypeId() == base::GetTypeId<MultiPlaneImage>()) {
     RenderMultiPlaneImage(base::polymorphic_downcast<MultiPlaneImage*>(image),
-                          render_target_, image_node->data().destination_rect,
+                          &draw_state_, image_node->data().destination_rect,
                           &(image_node->data().local_transform));
   } else {
     NOTREACHED();
   }
 
 #if ENABLE_FLUSH_AFTER_EVERY_NODE
-  render_target_->flush();
+  draw_state_.render_target->flush();
 #endif
 }
 
@@ -615,9 +655,9 @@
 
   // Concatenate the matrix transform to the render target and then continue
   // on with rendering our source.
-  render_target_->save();
+  draw_state_.render_target->save();
 
-  render_target_->concat(
+  draw_state_.render_target->concat(
       CobaltMatrixToSkia(matrix_transform_node->data().transform));
 
   // Since our scale may have changed, inform the surface cache system to update
@@ -628,10 +668,10 @@
 
   matrix_transform_node->data().source->Accept(this);
 
-  render_target_->restore();
+  draw_state_.render_target->restore();
 
 #if ENABLE_FLUSH_AFTER_EVERY_NODE
-  render_target_->flush();
+  draw_state_.render_target->flush();
 #endif
 }
 
@@ -651,16 +691,30 @@
     // We proceed anyway, just in case things happen to work out.
   }
 
-  const math::RectF& rect = punch_through_video_node->data().rect;
+  const math::RectF& math_rect = punch_through_video_node->data().rect;
 
   SkPaint paint;
   paint.setXfermodeMode(SkXfermode::kSrc_Mode);
   paint.setARGB(0, 0, 0, 0);
-  render_target_->drawRect(
-      SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()), paint);
+  SkRect sk_rect = SkRect::MakeXYWH(math_rect.x(), math_rect.y(),
+                                    math_rect.width(), math_rect.height());
+  SkMatrix total_matrix = draw_state_.render_target->getTotalMatrix();
+
+  SkRect sk_rect_transformed;
+  total_matrix.mapRect(&sk_rect_transformed, sk_rect);
+
+  if (!punch_through_video_node->data().set_bounds_cb.is_null()) {
+    punch_through_video_node->data().set_bounds_cb.Run(
+        math::Rect(static_cast<int>(sk_rect_transformed.x()),
+                   static_cast<int>(sk_rect_transformed.y()),
+                   static_cast<int>(sk_rect_transformed.width()),
+                   static_cast<int>(sk_rect_transformed.height())));
+  }
+
+  draw_state_.render_target->drawRect(sk_rect, paint);
 
 #if ENABLE_FLUSH_AFTER_EVERY_NODE
-  render_target_->flush();
+  draw_state_.render_target->flush();
 #endif
 }
 
@@ -668,7 +722,9 @@
 
 class SkiaBrushVisitor : public render_tree::BrushVisitor {
  public:
-  explicit SkiaBrushVisitor(SkPaint* paint) : paint_(paint) {}
+  explicit SkiaBrushVisitor(SkPaint* paint,
+                            const RenderTreeNodeVisitorDrawState& draw_state)
+      : paint_(paint), draw_state_(draw_state) {}
 
   void Visit(
       const cobalt::render_tree::SolidColorBrush* solid_color_brush) OVERRIDE;
@@ -679,19 +735,21 @@
 
  private:
   SkPaint* paint_;
+  const RenderTreeNodeVisitorDrawState& draw_state_;
 };
 
 void SkiaBrushVisitor::Visit(
     const cobalt::render_tree::SolidColorBrush* solid_color_brush) {
   const cobalt::render_tree::ColorRGBA& color = solid_color_brush->color();
 
-  if (color.a() == 1.0f) {
+  float alpha = color.a() * draw_state_.opacity;
+  if (alpha == 1.0f) {
     paint_->setXfermodeMode(SkXfermode::kSrc_Mode);
   } else {
     paint_->setXfermodeMode(SkXfermode::kSrcOver_Mode);
   }
 
-  paint_->setARGB(color.a() * 255, color.r() * 255, color.g() * 255,
+  paint_->setARGB(alpha * 255, color.r() * 255, color.g() * 255,
                   color.b() * 255);
 }
 
@@ -736,9 +794,12 @@
       SkGradientShader::kInterpolateColorsInPremul_Flag, NULL));
   paint_->setShader(shader);
 
-  if (!skia_color_stops.has_alpha) {
+  if (!skia_color_stops.has_alpha && draw_state_.opacity == 1.0f) {
     paint_->setXfermodeMode(SkXfermode::kSrc_Mode);
   } else {
+    if (draw_state_.opacity < 1.0f) {
+      paint_->setAlpha(255 * draw_state_.opacity);
+    }
     paint_->setXfermodeMode(SkXfermode::kSrcOver_Mode);
   }
 }
@@ -771,22 +832,26 @@
       SkGradientShader::kInterpolateColorsInPremul_Flag, &local_matrix));
   paint_->setShader(shader);
 
-  if (!skia_color_stops.has_alpha) {
+  if (!skia_color_stops.has_alpha && draw_state_.opacity == 1.0f) {
     paint_->setXfermodeMode(SkXfermode::kSrc_Mode);
   } else {
+    if (draw_state_.opacity < 1.0f) {
+      paint_->setAlpha(255 * draw_state_.opacity);
+    }
     paint_->setXfermodeMode(SkXfermode::kSrcOver_Mode);
   }
 }
 
-void DrawRectWithBrush(SkCanvas* render_target,
+void DrawRectWithBrush(RenderTreeNodeVisitorDrawState* draw_state,
                        cobalt::render_tree::Brush* brush,
                        const math::RectF& rect) {
   // Setup our paint object according to the brush parameters set on the
   // rectangle.
   SkPaint paint;
-  SkiaBrushVisitor brush_visitor(&paint);
+  SkiaBrushVisitor brush_visitor(&paint, *draw_state);
   brush->Accept(&brush_visitor);
-  render_target->drawRect(
+
+  draw_state->render_target->drawRect(
       SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()), paint);
 }
 
@@ -820,7 +885,8 @@
 }  // namespace
 
 void DrawRoundedRectWithBrush(
-    SkCanvas* render_target, render_tree::Brush* brush, const math::RectF& rect,
+    RenderTreeNodeVisitorDrawState* draw_state, render_tree::Brush* brush,
+    const math::RectF& rect,
     const render_tree::RoundedCorners& rounded_corners) {
   if (!CheckForSolidBrush(brush)) {
     NOTREACHED() << "Only solid brushes are currently supported for this shape "
@@ -829,23 +895,27 @@
   }
 
   SkPaint paint;
-  SkiaBrushVisitor brush_visitor(&paint);
+  SkiaBrushVisitor brush_visitor(&paint, *draw_state);
   brush->Accept(&brush_visitor);
 
   paint.setAntiAlias(true);
-  render_target->drawPath(RoundedRectToSkiaPath(rect, rounded_corners), paint);
+  draw_state->render_target->drawPath(
+      RoundedRectToSkiaPath(rect, rounded_corners), paint);
 }
 
-void DrawQuadWithColorIfBorderIsSolid(render_tree::BorderStyle border_style,
-                                      SkCanvas* render_target,
-                                      const render_tree::ColorRGBA& color,
-                                      const SkPoint* points, bool anti_alias) {
+void DrawQuadWithColorIfBorderIsSolid(
+    render_tree::BorderStyle border_style,
+    RenderTreeNodeVisitorDrawState* draw_state,
+    const render_tree::ColorRGBA& color, const SkPoint* points,
+    bool anti_alias) {
   if (border_style == render_tree::kBorderStyleSolid) {
     SkPaint paint;
-    paint.setARGB(color.a() * 255, color.r() * 255, color.g() * 255,
+    float alpha = color.a();
+    alpha *= draw_state->opacity;
+    paint.setARGB(alpha * 255, color.r() * 255, color.g() * 255,
                   color.b() * 255);
     paint.setAntiAlias(anti_alias);
-    if (color.a() == 1.0f) {
+    if (alpha == 1.0f) {
       paint.setXfermodeMode(SkXfermode::kSrc_Mode);
     } else {
       paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
@@ -853,7 +923,7 @@
 
     SkPath path;
     path.addPoly(points, 4, true);
-    render_target->drawPath(path, paint);
+    draw_state->render_target->drawPath(path, paint);
   } else {
     DCHECK_EQ(border_style, render_tree::kBorderStyleNone);
   }
@@ -867,26 +937,33 @@
 //        ||G_______H||
 //        |/_________\|
 //       C             D
-void DrawSolidNonRoundRectBorder(SkCanvas* render_target,
+void DrawSolidNonRoundRectBorder(RenderTreeNodeVisitorDrawState* draw_state,
                                  const math::RectF& rect,
                                  const render_tree::Border& border) {
-  bool anti_alias = true;
+  // Check if the border colors are the same or not to determine whether we
+  // should be using antialiasing.  If the border colors are different, then
+  // there will be visible diagonal edges in the output and so we would like to
+  // render with antialiasing enabled to smooth those diagonal edges.
+  bool border_colors_are_same = border.top.color == border.left.color &&
+                                border.top.color == border.bottom.color &&
+                                border.top.color == border.right.color;
 
-  if (border.top.color == border.left.color &&
-      border.top.color == border.bottom.color &&
-      border.top.color == border.right.color) {
-    // Disable the anti-alias when the borders have the same color.
-    anti_alias = false;
-  }
+  // If any of the border edges have width less than this threshold, they will
+  // use antialiasing as otherwise depending on the border's fractional
+  // position, it may have one extra pixel visible, which is a large percentage
+  // of its small width.
+  const float kAntiAliasWidthThreshold = 3.0f;
 
   // Top
   SkPoint top_points[4] = {
-      {rect.x(), rect.y()},                                              // A
-      {rect.x() + border.left.width, rect.y() + border.top.width},       // E
-      {rect.right() - border.right.width, rect.y() + border.top.width},  // F
-      {rect.right(), rect.y()}};                                         // B
-  DrawQuadWithColorIfBorderIsSolid(border.top.style, render_target,
-                                   border.top.color, top_points, anti_alias);
+      {rect.x(), rect.y()},                                                 // A
+      {rect.x() + border.left.width, rect.y() + border.top.width},          // E
+      {rect.right() - border.right.width, rect.y() + border.top.width},     // F
+      {rect.right(), rect.y()}};                                            // B
+  DrawQuadWithColorIfBorderIsSolid(
+      border.top.style, draw_state, border.top.color, top_points,
+      border.top.width < kAntiAliasWidthThreshold ? true
+                                                  : !border_colors_are_same);
 
   // Left
   SkPoint left_points[4] = {
@@ -894,8 +971,10 @@
       {rect.x(), rect.bottom()},                                            // C
       {rect.x() + border.left.width, rect.bottom() - border.bottom.width},  // G
       {rect.x() + border.left.width, rect.y() + border.top.width}};         // E
-  DrawQuadWithColorIfBorderIsSolid(border.left.style, render_target,
-                                   border.left.color, left_points, anti_alias);
+  DrawQuadWithColorIfBorderIsSolid(
+      border.left.style, draw_state, border.left.color, left_points,
+      border.left.width < kAntiAliasWidthThreshold ? true
+                                                   : !border_colors_are_same);
 
   // Bottom
   SkPoint bottom_points[4] = {
@@ -903,25 +982,27 @@
       {rect.x(), rect.bottom()},                                            // C
       {rect.right(), rect.bottom()},                                        // D
       {rect.right() - border.right.width,
-       rect.bottom() - border.bottom.width}};  // H
-  DrawQuadWithColorIfBorderIsSolid(border.bottom.style, render_target,
-                                   border.bottom.color, bottom_points,
-                                   anti_alias);
+       rect.bottom() - border.bottom.width}};                               // H
+  DrawQuadWithColorIfBorderIsSolid(
+      border.bottom.style, draw_state, border.bottom.color, bottom_points,
+      border.bottom.width < kAntiAliasWidthThreshold ? true
+                                                     : !border_colors_are_same);
 
   // Right
   SkPoint right_points[4] = {
-      {rect.right() - border.right.width, rect.y() + border.top.width},  // F
+      {rect.right() - border.right.width, rect.y() + border.top.width},     // F
       {rect.right() - border.right.width,
-       rect.bottom() - border.bottom.width},  // H
-      {rect.right(), rect.bottom()},          // D
-      {rect.right(), rect.y()}};              // B
-  DrawQuadWithColorIfBorderIsSolid(border.right.style, render_target,
-                                   border.right.color, right_points,
-                                   anti_alias);
+       rect.bottom() - border.bottom.width},                                // H
+      {rect.right(), rect.bottom()},                                        // D
+      {rect.right(), rect.y()}};                                            // B
+  DrawQuadWithColorIfBorderIsSolid(
+      border.right.style, draw_state, border.right.color, right_points,
+      border.right.width < kAntiAliasWidthThreshold ? true
+                                                    : !border_colors_are_same);
 }
 
 void DrawSolidRoundedRectBorderToRenderTarget(
-    SkCanvas* render_target, const math::RectF& rect,
+    RenderTreeNodeVisitorDrawState* draw_state, const math::RectF& rect,
     const render_tree::RoundedCorners& rounded_corners,
     const math::RectF& content_rect,
     const render_tree::RoundedCorners& inner_rounded_corners,
@@ -930,21 +1011,22 @@
   paint.setAntiAlias(true);
 
   const render_tree::ColorRGBA& color = border.top.color;
-  paint.setARGB(color.a() * 255, color.r() * 255, color.g() * 255,
-                color.b() * 255);
-  if (color.a() == 1.0f) {
+  float alpha = color.a();
+  alpha *= draw_state->opacity;
+  paint.setARGB(alpha * 255, color.r() * 255, color.g() * 255, color.b() * 255);
+  if (alpha == 1.0f) {
     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
   } else {
     paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
   }
 
-  render_target->drawDRRect(
+  draw_state->render_target->drawDRRect(
       RoundedRectToSkia(rect, rounded_corners),
       RoundedRectToSkia(content_rect, inner_rounded_corners), paint);
 }
 
 void DrawSolidRoundedRectBorderSoftware(
-    SkCanvas* render_target, const math::RectF& rect,
+    RenderTreeNodeVisitorDrawState* draw_state, const math::RectF& rect,
     const render_tree::RoundedCorners& rounded_corners,
     const math::RectF& content_rect,
     const render_tree::RoundedCorners& inner_rounded_corners,
@@ -960,14 +1042,19 @@
   math::RectF canvas_rect(rect.size());
   math::RectF canvas_content_rect(content_rect);
   canvas_content_rect.Offset(-rect.OffsetFromOrigin());
-  DrawSolidRoundedRectBorderToRenderTarget(&canvas, canvas_rect,
+
+  RenderTreeNodeVisitorDrawState sub_draw_state(*draw_state);
+  sub_draw_state.render_target = &canvas;
+
+  DrawSolidRoundedRectBorderToRenderTarget(&sub_draw_state, canvas_rect,
                                            rounded_corners, canvas_content_rect,
                                            inner_rounded_corners, border);
   canvas.flush();
 
   SkPaint render_target_paint;
   render_target_paint.setFilterLevel(SkPaint::kNone_FilterLevel);
-  render_target->drawBitmap(bitmap, rect.x(), rect.y(), &render_target_paint);
+  draw_state->render_target->drawBitmap(bitmap, rect.x(), rect.y(),
+                                        &render_target_paint);
 }
 
 namespace {
@@ -999,7 +1086,7 @@
 }  // namespace
 
 void DrawSolidRoundedRectBorder(
-    SkCanvas* render_target, const math::RectF& rect,
+    RenderTreeNodeVisitorDrawState* draw_state, const math::RectF& rect,
     const render_tree::RoundedCorners& rounded_corners,
     const math::RectF& content_rect,
     const render_tree::RoundedCorners& inner_rounded_corners,
@@ -1011,8 +1098,8 @@
   if (IsCircle(rect.size(), rounded_corners)) {
     // We are able to render circular borders using hardware, so introduce
     // a special case for them.
-    DrawSolidRoundedRectBorderToRenderTarget(render_target, rect,
-                                             rounded_corners, content_rect,
+    DrawSolidRoundedRectBorderToRenderTarget(draw_state, rect, rounded_corners,
+                                             content_rect,
                                              inner_rounded_corners, border);
   } else {
     // For now we fallback to software for drawing most rounded corner borders,
@@ -1020,7 +1107,7 @@
     // do this is to limit then number of shaders that need to be implemented.
     NOTIMPLEMENTED() << "Warning: Software rasterizing a solid rectangle "
                         "border.";
-    DrawSolidRoundedRectBorderSoftware(render_target, rect, rounded_corners,
+    DrawSolidRoundedRectBorderSoftware(draw_state, rect, rounded_corners,
                                        content_rect, inner_rounded_corners,
                                        border);
   }
@@ -1057,28 +1144,28 @@
 
   if (rect_node->data().background_brush) {
     if (inner_rounded_corners && !inner_rounded_corners->AreSquares()) {
-      DrawRoundedRectWithBrush(render_target_,
+      DrawRoundedRectWithBrush(&draw_state_,
                                rect_node->data().background_brush.get(),
                                content_rect, *inner_rounded_corners);
     } else {
-      DrawRectWithBrush(render_target_,
-                        rect_node->data().background_brush.get(), content_rect);
+      DrawRectWithBrush(&draw_state_, rect_node->data().background_brush.get(),
+                        content_rect);
     }
   }
 
   if (rect_node->data().border) {
     if (rect_node->data().rounded_corners) {
       DrawSolidRoundedRectBorder(
-          render_target_, rect, *rect_node->data().rounded_corners,
-          content_rect, *inner_rounded_corners, *rect_node->data().border);
+          &draw_state_, rect, *rect_node->data().rounded_corners, content_rect,
+          *inner_rounded_corners, *rect_node->data().border);
     } else {
-      DrawSolidNonRoundRectBorder(render_target_, rect,
+      DrawSolidNonRoundRectBorder(&draw_state_, rect,
                                   *rect_node->data().border);
     }
   }
 
 #if ENABLE_FLUSH_AFTER_EVERY_NODE
-  render_target_->flush();
+  draw_state_.render_target->flush();
 #endif
 }
 
@@ -1250,21 +1337,22 @@
 #if ENABLE_RENDER_TREE_VISITOR_TRACING
   TRACE_EVENT0("cobalt::renderer", "Visit(RectShadowNode)");
 #endif
+  DCHECK_EQ(1.0f, draw_state_.opacity);
   common::SurfaceCache::Block cache_block(surface_cache_, rect_shadow_node);
   if (cache_block.Cached()) return;
 
   if (rect_shadow_node->data().rounded_corners) {
-    DrawRoundedRectShadowNode(rect_shadow_node, render_target_);
+    DrawRoundedRectShadowNode(rect_shadow_node, draw_state_.render_target);
   } else {
     if (rect_shadow_node->data().inset) {
-      DrawInsetRectShadowNode(rect_shadow_node, render_target_);
+      DrawInsetRectShadowNode(rect_shadow_node, draw_state_.render_target);
     } else {
-      DrawOutsetRectShadowNode(rect_shadow_node, render_target_);
+      DrawOutsetRectShadowNode(rect_shadow_node, draw_state_.render_target);
     }
   }
 
 #if ENABLE_FLUSH_AFTER_EVERY_NODE
-  render_target_->flush();
+  draw_state_.render_target->flush();
 #endif
 }
 
@@ -1312,6 +1400,7 @@
 #if ENABLE_RENDER_TREE_VISITOR_TRACING
   TRACE_EVENT0("cobalt::renderer", "Visit(TextNode)");
 #endif
+  DCHECK_EQ(1.0f, draw_state_.opacity);
   common::SurfaceCache::Block cache_block(surface_cache_, text_node);
   if (cache_block.Cached()) return;
 
@@ -1341,20 +1430,21 @@
       const render_tree::Shadow& shadow = shadows[i];
 
       RenderText(
-          render_target_, text_node->data().glyph_buffer, shadow.color,
-          math::PointAtOffsetFromOrigin(text_node->data().offset +
-                                        shadow.offset),
+          draw_state_.render_target, text_node->data().glyph_buffer,
+          shadow.color, math::PointAtOffsetFromOrigin(text_node->data().offset +
+                                                      shadow.offset),
           shadow.blur_sigma == 0.0f ? blur_zero_sigma : shadow.blur_sigma);
     }
   }
 
   // Finally render the main text.
-  RenderText(
-      render_target_, text_node->data().glyph_buffer, text_node->data().color,
-      math::PointAtOffsetFromOrigin(text_node->data().offset), blur_zero_sigma);
+  RenderText(draw_state_.render_target, text_node->data().glyph_buffer,
+             text_node->data().color,
+             math::PointAtOffsetFromOrigin(text_node->data().offset),
+             blur_zero_sigma);
 
 #if ENABLE_FLUSH_AFTER_EVERY_NODE
-  render_target_->flush();
+  draw_state_.render_target->flush();
 #endif
 }
 
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 b325107..3efa3c6 100644
--- a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.h
+++ b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.h
@@ -29,6 +29,7 @@
 #include "cobalt/render_tree/rect_node.h"
 #include "cobalt/render_tree/text_node.h"
 #include "cobalt/renderer/rasterizer/common/surface_cache.h"
+#include "cobalt/renderer/rasterizer/skia/render_tree_node_visitor_draw_state.h"
 #include "cobalt/renderer/rasterizer/skia/surface_cache_delegate.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 
@@ -93,11 +94,8 @@
   // then apply the filter to the offscreen surface.
   void RenderFilterViaOffscreenSurface(
       const render_tree::FilterNode::Builder& filter_node);
-  void SetRenderTarget(SkCanvas* render_target) {
-    render_target_ = render_target;
-  }
 
-  SkCanvas* render_target_;
+  RenderTreeNodeVisitorDrawState draw_state_;
   const CreateScratchSurfaceFunction* create_scratch_surface_function_;
   Type visitor_type_;
 
diff --git a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor_draw_state.h b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor_draw_state.h
new file mode 100644
index 0000000..01a5d62
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor_draw_state.h
@@ -0,0 +1,40 @@
+/*
+ * 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_SKIA_RENDER_TREE_NODE_VISITOR_DRAW_STATE_H_
+#define COBALT_RENDERER_RASTERIZER_SKIA_RENDER_TREE_NODE_VISITOR_DRAW_STATE_H_
+
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace cobalt {
+namespace renderer {
+namespace rasterizer {
+namespace skia {
+
+struct RenderTreeNodeVisitorDrawState {
+  explicit RenderTreeNodeVisitorDrawState(SkCanvas* render_target)
+      : render_target(render_target), opacity(1.0f) {}
+
+  SkCanvas* render_target;
+  float opacity;
+};
+
+}  // namespace skia
+}  // namespace rasterizer
+}  // namespace renderer
+}  // namespace cobalt
+
+#endif  // COBALT_RENDERER_RASTERIZER_SKIA_RENDER_TREE_NODE_VISITOR_DRAW_STATE_H_
diff --git a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
index f959c8b..7de5fdc 100644
--- a/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
+++ b/src/cobalt/renderer/rasterizer/skia/scratch_surface_cache.cc
@@ -53,7 +53,12 @@
 
 common::ScratchSurfaceCache::Surface*
 ScratchSurfaceCache::Delegate::CreateSurface(const math::Size& size) {
-  return new SkiaSurface(create_sk_surface_function_.Run(size), size);
+  SkSurface* sk_surface = create_sk_surface_function_.Run(size);
+  if (sk_surface) {
+    return new SkiaSurface(sk_surface, size);
+  } else {
+    return NULL;
+  }
 }
 
 void ScratchSurfaceCache::Delegate::DestroySurface(
@@ -89,9 +94,13 @@
 }
 
 SkSurface* CachedScratchSurface::GetSurface() {
-  return base::polymorphic_downcast<SkiaSurface*>(
-             common_scratch_surface_.GetSurface())
-      ->sk_surface();
+  if (common_scratch_surface_.GetSurface()) {
+    return base::polymorphic_downcast<SkiaSurface*>(
+               common_scratch_surface_.GetSurface())
+        ->sk_surface();
+  } else {
+    return NULL;
+  }
 }
 
 }  // namespace skia
diff --git a/src/cobalt/renderer/rasterizer/skia/software_rasterizer.cc b/src/cobalt/renderer/rasterizer/skia/software_rasterizer.cc
index 208d179..d1cafc6 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/skia/software_rasterizer.cc
@@ -39,8 +39,8 @@
 
 class SoftwareScratchSurface : public RenderTreeNodeVisitor::ScratchSurface {
  public:
-  explicit SoftwareScratchSurface(const math::Size& size)
-      : surface_(CreateScratchSkSurface(size)) {}
+  explicit SoftwareScratchSurface(SkSurface* sk_surface)
+      : surface_(sk_surface) {}
   SkSurface* GetSurface() OVERRIDE { return surface_.get(); }
 
  private:
@@ -51,8 +51,13 @@
     const math::Size& size) {
   TRACE_EVENT2("cobalt::renderer", "CreateScratchSurface()", "width",
                size.width(), "height", size.height());
-  return scoped_ptr<RenderTreeNodeVisitor::ScratchSurface>(
-      new SoftwareScratchSurface(size));
+  SkSurface* sk_surface = CreateScratchSkSurface(size);
+  if (sk_surface) {
+    return scoped_ptr<RenderTreeNodeVisitor::ScratchSurface>(
+        new SoftwareScratchSurface(sk_surface));
+  } else {
+    return scoped_ptr<RenderTreeNodeVisitor::ScratchSurface>();
+  }
 }
 
 void ReturnScratchImage(SkSurface* surface) { surface->unref(); }
diff --git a/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.cc b/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.cc
index 447ab7a..598de2c 100644
--- a/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.cc
+++ b/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.cc
@@ -35,7 +35,7 @@
     const math::Size& max_surface_size)
     : create_sk_surface_function_(create_sk_surface_function),
       max_surface_size_(max_surface_size),
-      canvas_(NULL)
+      draw_state_(NULL)
 #if defined(ENABLE_DEBUG_CONSOLE)
       ,
       toggle_cache_highlights_(false),
@@ -51,7 +51,8 @@
 }
 
 void SurfaceCacheDelegate::UpdateCanvasScale() {
-  math::Matrix3F total_matrix = SkiaMatrixToCobalt(canvas_->getTotalMatrix());
+  math::Matrix3F total_matrix =
+      SkiaMatrixToCobalt(draw_state_->render_target->getTotalMatrix());
   math::Vector3dF column_0(total_matrix.column(0));
   math::Vector3dF column_1(total_matrix.column(1));
   scale_ = math::Vector2dF(column_0.Length(), column_1.Length());
@@ -73,8 +74,8 @@
     return;
   }
 
-  canvas_->save();
-  SkMatrix total_matrix = canvas_->getTotalMatrix();
+  draw_state_->render_target->save();
+  SkMatrix total_matrix = draw_state_->render_target->getTotalMatrix();
   // We "preScale()" the "post scale" because skia uses "pre" to mean that the
   // transform will be applied before the other transforms, whereas
   // common::OffscreenRenderCoordinateMapping() uses "post" to mean that the
@@ -83,10 +84,13 @@
                         skia_surface->output_post_scale().y());
   total_matrix.postTranslate(skia_surface->output_pre_translate().x(),
                              skia_surface->output_pre_translate().y());
-  canvas_->setMatrix(total_matrix);
+  draw_state_->render_target->setMatrix(total_matrix);
 
   SkPaint paint;
   paint.setFilterLevel(SkPaint::kLow_FilterLevel);
+  if (draw_state_->opacity < 1.0f) {
+    paint.setAlpha(draw_state_->opacity * 255);
+  }
 
   SkRect dest_rect = SkRect::MakeXYWH(skia_surface->output_bounds().x(),
                                       skia_surface->output_bounds().y(),
@@ -99,15 +103,15 @@
 #if defined(ENABLE_DEBUG_CONSOLE)
   if (toggle_cache_highlights_) {
     paint.setARGB(128, 255, 128, 128);
-    canvas_->drawRect(dest_rect, paint);
+    draw_state_->render_target->drawRect(dest_rect, paint);
   } else  // NOLINT(readability/braces)
 #endif
   {
-    canvas_->drawImageRect(skia_surface->image(), &source_rect, dest_rect,
-                           &paint);
+    draw_state_->render_target->drawImageRect(skia_surface->image(),
+                                              &source_rect, dest_rect, &paint);
   }
 
-  canvas_->restore();
+  draw_state_->render_target->restore();
 }
 
 void SurfaceCacheDelegate::StartRecording(const math::RectF& local_bounds) {
@@ -121,8 +125,9 @@
   // suffer.
   math::Vector2dF inv_scale(scale_.x() < 1.0f ? 1.0f / scale_.x() : 1.0f,
                             scale_.y() < 1.0f ? 1.0f / scale_.y() : 1.0f);
-  math::Matrix3F total_matrix = SkiaMatrixToCobalt(canvas_->getTotalMatrix()) *
-                                math::ScaleMatrix(inv_scale);
+  math::Matrix3F total_matrix =
+      SkiaMatrixToCobalt(draw_state_->render_target->getTotalMatrix()) *
+      math::ScaleMatrix(inv_scale);
 
   // Figure where we should render to the offscreen surface and then how to map
   // that later to the onscreen surface when applying the cached surface.  We
@@ -133,7 +138,7 @@
   // If the output has an area of 0 then there is nothing to cache.  This should
   // not be common.
   if (coord_mapping.output_bounds.size().GetArea() == 0) {
-    recording_data_.emplace(canvas_, coord_mapping,
+    recording_data_.emplace(*draw_state_, coord_mapping,
                             static_cast<SkSurface*>(NULL));
     return;
   }
@@ -145,17 +150,17 @@
                  coord_mapping.output_bounds.height()));
   CHECK(surface);
 
-  recording_data_.emplace(canvas_, coord_mapping, surface);
+  recording_data_.emplace(*draw_state_, coord_mapping, surface);
 
   SkCanvas* offscreen_canvas = surface->getCanvas();
-  set_canvas_function_.Run(offscreen_canvas);
-  canvas_ = offscreen_canvas;
+  draw_state_->render_target = offscreen_canvas;
+  draw_state_->opacity = 1.0f;
 
   // Clear the draw area to RGBA(0, 0, 0, 0) for a fresh scratch surface before
   // returning.
-  canvas_->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
+  draw_state_->render_target->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
 
-  offscreen_canvas->setMatrix(
+  draw_state_->render_target->setMatrix(
       CobaltMatrixToSkia(coord_mapping.sub_render_transform));
 }
 
@@ -163,8 +168,7 @@
   TRACE_EVENT0("cobalt::renderer", "SurfaceCacheDelegate::EndRecording()");
   DCHECK(recording_data_);
 
-  set_canvas_function_.Run(recording_data_->original_canvas);
-  canvas_ = recording_data_->original_canvas;
+  *draw_state_ = recording_data_->original_draw_state;
 
   // Save the results as a CachedSurface and return them.
   CachedSurface* cached_surface =
diff --git a/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.h b/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.h
index 9e5fb69..7d0a045 100644
--- a/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.h
+++ b/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.h
@@ -26,7 +26,7 @@
 #endif
 #include "cobalt/renderer/rasterizer/common/offscreen_render_coordinate_mapping.h"
 #include "cobalt/renderer/rasterizer/common/surface_cache.h"
-#include "third_party/skia/include/core/SkCanvas.h"
+#include "cobalt/renderer/rasterizer/skia/render_tree_node_visitor_draw_state.h"
 #include "third_party/skia/include/core/SkSurface.h"
 
 namespace cobalt {
@@ -76,7 +76,6 @@
 
  public:
   typedef base::Callback<SkSurface*(const math::Size&)> CreateSkSurfaceFunction;
-  typedef base::Callback<void(SkCanvas*)> SetCanvasFunction;
 
   // Creating a ScopedContext object declares a render tree visitor context,
   // and so there should be one ScopedContext per render tree visitor.  Since
@@ -85,35 +84,28 @@
   // SurfaceCacheDelegate object.
   class ScopedContext {
    public:
-    ScopedContext(SurfaceCacheDelegate* delegate, SkCanvas* canvas,
-                  const SetCanvasFunction& set_canvas_function)
-        : delegate_(delegate),
-          old_canvas_(delegate_->canvas_),
-          old_set_canvas_function_(delegate_->set_canvas_function_) {
-      // Setup our new canvas to the provided one.  Remember a new method
-      // to set the canvas for the current rendering context in case we need
-      // to start recording on a offscreen surface.
-      delegate_->canvas_ = canvas;
-      delegate_->set_canvas_function_ = set_canvas_function;
+    ScopedContext(SurfaceCacheDelegate* delegate,
+                  RenderTreeNodeVisitorDrawState* draw_state)
+        : delegate_(delegate), old_draw_state_(delegate_->draw_state_) {
+      // Setup our new draw state (including render target) to the provided one.
+      delegate_->draw_state_ = draw_state;
 
       // A new canvas may mean a new total matrix, so inform our delegate to
       // refresh its scale.
       delegate_->UpdateCanvasScale();
     }
     ~ScopedContext() {
-      // Restore the canvas to the old setting.
-      delegate_->set_canvas_function_ = old_set_canvas_function_;
-      delegate_->canvas_ = old_canvas_;
+      // Restore the draw state to the old setting.
+      delegate_->draw_state_ = old_draw_state_;
 
-      if (delegate_->canvas_) {
+      if (delegate_->draw_state_) {
         delegate_->UpdateCanvasScale();
       }
     }
 
    private:
     SurfaceCacheDelegate* delegate_;
-    SkCanvas* old_canvas_;
-    SetCanvasFunction old_set_canvas_function_;
+    RenderTreeNodeVisitorDrawState* old_draw_state_;
   };
 
   SurfaceCacheDelegate(
@@ -134,16 +126,17 @@
  private:
   // Defines a set of data that is relevant only while recording.
   struct RecordingData {
-    RecordingData(SkCanvas* original_canvas,
+    RecordingData(const RenderTreeNodeVisitorDrawState& original_draw_state,
                   const common::OffscreenRenderCoordinateMapping& coord_mapping,
                   SkSurface* surface)
-        : original_canvas(original_canvas),
+        : original_draw_state(original_draw_state),
           coord_mapping(coord_mapping),
           surface(surface) {}
 
-    // The original canvas that the recorded draw calls would have otherwise
-    // targeted if we were not recording.
-    SkCanvas* original_canvas;
+    // The original draw state (including render target/canvas) that the
+    // recorded draw calls would have otherwise targeted if we were not
+    // recording.
+    RenderTreeNodeVisitorDrawState original_draw_state;
 
     // Information about how to map the offscreen cached surface to the main
     // render target.
@@ -161,25 +154,21 @@
   // something new.
   CreateSkSurfaceFunction create_sk_surface_function_;
 
-  // A function that can be used to change the current canvas in order to
-  // redirect Skia rasterization commands to an offscreen cached surface.
-  SetCanvasFunction set_canvas_function_;
-
   // The maximum size of an SkSurface.
   math::Size max_surface_size_;
 
-  // The current canvas that is being targeted, whether its the main onscreen
-  // surface or a cached surface.
-  SkCanvas* canvas_;
+  // The current draw state (including the SkCanvas) that is being targeted,
+  // whether its the main onscreen surface or a cached surface.
+  RenderTreeNodeVisitorDrawState* draw_state_;
 
   // If we are currently recording, this will contain all of the data relevant
   // to that recording.
   base::optional<RecordingData> recording_data_;
 
-  // The current scale of canvas_->getTotalMatrix().  This lets us quickly check
-  // if the scale of a render node changes from the last time we observed it,
-  // which may happen if an animation is targeting a MatrixTransformNode render
-  // tree node.
+  // The current scale of draw_state_->render_target->getTotalMatrix().  This
+  // lets us quickly check if the scale of a render node changes from the last
+  // time we observed it, which may happen if an animation is targeting a
+  // MatrixTransformNode render tree node.
   math::Vector2dF scale_;
 
 #if defined(ENABLE_DEBUG_CONSOLE)
diff --git a/src/cobalt/renderer/renderer.gyp b/src/cobalt/renderer/renderer.gyp
index 657e39e..5a1253e 100644
--- a/src/cobalt/renderer/renderer.gyp
+++ b/src/cobalt/renderer/renderer.gyp
@@ -36,13 +36,6 @@
       'includes': [
         'copy_font_data.gypi',
       ],
-
-      'defines': [
-        'COBALT_SKIA_CACHE_SIZE_IN_BYTES=<(skia_cache_size_in_bytes)',
-        'COBALT_SCRATCH_SURFACE_CACHE_SIZE_IN_BYTES=<(scratch_surface_cache_size_in_bytes)',
-        'COBALT_SURFACE_CACHE_SIZE_IN_BYTES=<(surface_cache_size_in_bytes)',
-      ],
-
       'dependencies': [
         '<(DEPTH)/cobalt/base/base.gyp:base',
         '<(DEPTH)/cobalt/math/math.gyp:math',
@@ -53,21 +46,14 @@
         '<(DEPTH)/cobalt/system_window/system_window.gyp:system_window',
       ],
       'conditions': [
-        ['rasterizer_type == "software"', {
-          'defines': [
-            'COBALT_FORCE_SOFTWARE_RASTERIZER',
-          ],
-        }],
-        ['rasterizer_type == "stub"', {
-          'defines': [
-            'COBALT_FORCE_STUB_RASTERIZER',
-          ],
-        }],
         ['OS=="starboard"', {
-          'sources': [
-            'renderer_module_default_options_starboard.cc',
+          'dependencies': [
+            '<(default_renderer_options_dependency)',
           ],
         }, {
+          'includes': [
+            'renderer_parameters_setup.gypi',
+          ],
           'sources': [
             'renderer_module_default_options_<(actual_target_arch).cc',
           ],
diff --git a/src/cobalt/renderer/renderer_parameters_setup.gypi b/src/cobalt/renderer/renderer_parameters_setup.gypi
new file mode 100644
index 0000000..95724f6
--- /dev/null
+++ b/src/cobalt/renderer/renderer_parameters_setup.gypi
@@ -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.
+
+{
+  'defines': [
+    'COBALT_SKIA_CACHE_SIZE_IN_BYTES=<(skia_cache_size_in_bytes)',
+    'COBALT_SCRATCH_SURFACE_CACHE_SIZE_IN_BYTES=<(scratch_surface_cache_size_in_bytes)',
+    'COBALT_SURFACE_CACHE_SIZE_IN_BYTES=<(surface_cache_size_in_bytes)',
+  ],
+  'conditions': [
+    ['rasterizer_type == "software"', {
+      'defines': [
+        'COBALT_FORCE_SOFTWARE_RASTERIZER',
+      ],
+    }],
+    ['rasterizer_type == "stub"', {
+      'defines': [
+        'COBALT_FORCE_STUB_RASTERIZER',
+      ],
+    }],
+  ],
+}
diff --git a/src/cobalt/script/exception_message.cc b/src/cobalt/script/exception_message.cc
new file mode 100644
index 0000000..73ac903
--- /dev/null
+++ b/src/cobalt/script/exception_message.cc
@@ -0,0 +1,68 @@
+/*
+ * 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/exception_message.h"
+
+namespace cobalt {
+namespace script {
+
+ExceptionMessage kMessages[kNumMessageTypes] = {
+    {kSimpleError, kError, " "},
+    {kSimpleTypeError, kTypeError, " "},
+    {kSimpleRangeError, kRangeError, " "},
+    {kSimpleReferenceError, kReferenceError, " "},
+    {kNotNullableType, kTypeError, "Value is null but type is not nullable."},
+    {kNotObjectType, kTypeError, "Value is not an object."},
+    {kNotObjectOrFunction, kTypeError, "Value is not an object or function."},
+    {kNotInt64Type, kTypeError, "Value is not int64."},
+    {kNotUint64Type, kTypeError, "Value is not uint64."},
+    {kNotNumberType, kTypeError, "Value is not a number."},
+    {kDoesNotImplementInterface, kTypeError,
+     "Value does not implement the interface type."},
+    {kConvertToStringFailed, kTypeError,
+     "JS value cannot be converted to string."},
+    {kNotFinite, kTypeError, "Non-finite floating-point value."},
+    {kNotSupportedType, kTypeError, "Value is null but type is not nullable."},
+    {kConvertToUTF8Failed, kTypeError, "Failed to convert JS value to utf8."},
+    {kConvertToEnumFailed, kTypeError, "Failed to convert JS value to enum."},
+    {kStringifierProblem, kTypeError, "Stringifier problem."},
+    {kNotFunctionValue, kTypeError, "Value is not a function."},
+    {kInvalidNumberOfArguments, kRangeError, "Invalid number of arguments."},
+    {kNotUnionType, kTypeError, "Value is not a member of the union type."},
+    {kOutsideBounds, kRangeError, "Offset is outside the object's bounds."},
+    {kInvalidLength, kRangeError, "Invalid length."},
+    {kNotAnArrayBuffer, kTypeError, "Value is not an ArrayBuffer."},
+    {kWrongByteOffsetMultiple, kRangeError,
+     "Byte offset should be a multiple of %d."},
+    {kWrongByteLengthMultiple, kRangeError,
+     "Byte length should be a multiple of %d."},
+    {kPropertySyntaxError, kSyntaxError, "%s."},
+};
+
+const char* GetExceptionMessageFormat(MessageType message_type) {
+  DCHECK_GT(message_type, kNoError);
+  DCHECK_LT(message_type, kNumMessageTypes);
+  return kMessages[message_type].format;
+}
+
+SimpleExceptionType GetSimpleExceptionType(MessageType message_type) {
+  DCHECK_GT(message_type, kNoError);
+  DCHECK_LT(message_type, kNumMessageTypes);
+  return kMessages[message_type].exception_type;
+}
+
+}  // namespace script
+}  // namespace cobalt
diff --git a/src/cobalt/script/exception_message.h b/src/cobalt/script/exception_message.h
new file mode 100644
index 0000000..928c790
--- /dev/null
+++ b/src/cobalt/script/exception_message.h
@@ -0,0 +1,87 @@
+/*
+ * 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_EXCEPTION_MESSAGE_H_
+#define COBALT_SCRIPT_EXCEPTION_MESSAGE_H_
+
+#include <string>
+
+#include "cobalt/script/script_exception.h"
+
+namespace cobalt {
+namespace script {
+
+// Simple exceptions as defined in:
+// http://heycam.github.io/webidl/#dfn-simple-exception
+enum SimpleExceptionType {
+  kError,
+  kTypeError,
+  kRangeError,
+  kReferenceError,
+  kSyntaxError,
+  kURIError
+};
+
+// Custom exception message type.
+enum MessageType {
+  kNoError = -1,
+
+  kSimpleError,
+  kSimpleTypeError,
+  kSimpleRangeError,
+  kSimpleReferenceError,
+  kNotNullableType,
+  kNotObjectType,
+  kNotObjectOrFunction,
+  kNotInt64Type,
+  kNotUint64Type,
+  kNotNumberType,
+  kDoesNotImplementInterface,
+  kConvertToStringFailed,
+  kNotFinite,
+  kNotSupportedType,
+  kConvertToUTF8Failed,
+  kConvertToEnumFailed,
+  kStringifierProblem,
+  kNotFunctionValue,
+  kInvalidNumberOfArguments,
+  kNotUnionType,
+  kOutsideBounds,
+  kInvalidLength,
+  kNotAnArrayBuffer,
+  kWrongByteOffsetMultiple,
+  kWrongByteLengthMultiple,
+  kPropertySyntaxError,
+
+  kNumMessageTypes,
+};
+
+// Exception message contains an exception information. It includes a
+// |message_type| which is the index of each exception message, a
+// |exception_type| which is based on the spec. of simple exception, and a
+//  message |format|.
+struct ExceptionMessage {
+  MessageType message_type;
+  SimpleExceptionType exception_type;
+  const char* format;
+};
+
+const char* GetExceptionMessageFormat(MessageType message_type);
+SimpleExceptionType GetSimpleExceptionType(MessageType message_type);
+
+}  // namespace script
+}  // namespace cobalt
+
+#endif  // COBALT_SCRIPT_EXCEPTION_MESSAGE_H_
diff --git a/src/cobalt/script/exception_state.h b/src/cobalt/script/exception_state.h
index 897ac04..cd4e7f7 100644
--- a/src/cobalt/script/exception_state.h
+++ b/src/cobalt/script/exception_state.h
@@ -18,6 +18,7 @@
 
 #include <string>
 
+#include "cobalt/script/exception_message.h"
 #include "cobalt/script/script_exception.h"
 
 namespace cobalt {
@@ -25,21 +26,10 @@
 
 class ExceptionState {
  public:
-  // Simple exceptions as defined in:
-  // http://heycam.github.io/webidl/#dfn-simple-exception
-  enum SimpleExceptionType {
-    kError,
-    kTypeError,
-    kRangeError,
-    kReferenceError,
-    kSyntaxError,
-    kURIError
-  };
   // IDL for this object must be an exception interface.
   virtual void SetException(
       const scoped_refptr<ScriptException>& exception) = 0;
-  virtual void SetSimpleException(SimpleExceptionType simple_error,
-                                  const std::string& message) = 0;
+  virtual void SetSimpleException(MessageType message_type, ...) = 0;
 };
 
 }  // namespace script
diff --git a/src/cobalt/script/javascriptcore/conversion_helpers.h b/src/cobalt/script/javascriptcore/conversion_helpers.h
index 4642fc9..3b30135 100644
--- a/src/cobalt/script/javascriptcore/conversion_helpers.h
+++ b/src/cobalt/script/javascriptcore/conversion_helpers.h
@@ -45,14 +45,6 @@
 namespace script {
 namespace javascriptcore {
 
-const char kNotAnObject[] = "Value is not an object.";
-const char kNotAnObjectOrFunction[] = "Value is not an object or function.";
-const char kNotAFunction[] = "Value is not a function.";
-const char kNotNullableType[] = "Value is null but type is not nullable.";
-const char kNotObjectType[] = "Value is not an object.";
-const char kDoesNotImplementInterface[] =
-    "Value does not implement the interface type.";
-
 // Flags that can be used as a bitmask for special conversion behaviour.
 enum ConversionFlags {
   kNoConversionFlags = 0,
@@ -128,8 +120,7 @@
         global_object->wrapper_factory()->GetClassInfo(base::GetTypeId<T>());
   } else {
     // This is not a platform object. Return a type error.
-    out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                      kDoesNotImplementInterface);
+    out_exception->SetSimpleException(kDoesNotImplementInterface);
     return NULL;
   }
 
@@ -137,8 +128,7 @@
   if (js_object->inherits(class_info)) {
     return base::polymorphic_downcast<T*>(wrappable);
   } else {
-    out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                      kDoesNotImplementInterface);
+    out_exception->SetSimpleException(kDoesNotImplementInterface);
     return NULL;
   }
 }
@@ -388,8 +378,7 @@
   double double_value = jsvalue.toNumber(exec_state);
   if (!isfinite(double_value) &&
       (conversion_flags & kConversionFlagRestricted)) {
-    out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                      "Non-finite floating-point value.");
+    out_exception->SetSimpleException(kNotFinite);
     return;
   }
   *out_number = double_value;
@@ -423,16 +412,14 @@
   JSC::JSObject* js_object = NULL;
   if (jsvalue.isNull()) {
     if (!(conversion_flags & kConversionFlagNullable)) {
-      out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                        kNotNullableType);
+      out_exception->SetSimpleException(kNotNullableType);
       return;
     }
   } else {
     // Returns NULL if jsvalue is not an object.
     js_object = jsvalue.getObject();
     if (!js_object) {
-      out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                        kNotObjectType);
+      out_exception->SetSimpleException(kNotObjectType);
       return;
     }
   }
@@ -485,8 +472,7 @@
       << "No conversion flags supported.";
   if (jsvalue.isNull()) {
     if (!(conversion_flags & kConversionFlagNullable)) {
-      out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                        kNotNullableType);
+      out_exception->SetSimpleException(kNotNullableType);
     }
     // If it is a nullable type, just return.
     return;
@@ -498,8 +484,7 @@
   // https://www.w3.org/TR/WebIDL/#es-callback-function
   // 1. If V is not a Function object, throw a TypeError
   if (!jsvalue.isFunction()) {
-    out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                      kNotAFunction);
+    out_exception->SetSimpleException(kNotFunctionValue);
     return;
   }
 
@@ -522,8 +507,7 @@
       << "No conversion flags supported.";
   if (jsvalue.isNull()) {
     if (!(conversion_flags & kConversionFlagNullable)) {
-      out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                        kNotNullableType);
+      out_exception->SetSimpleException(kNotNullableType);
     }
     // If it is a nullable type, just return.
     return;
@@ -538,8 +522,7 @@
   // on the callback interface is run.
 
   if (!jsvalue.isFunction() && !jsvalue.isObject()) {
-    out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                      kNotAnObjectOrFunction);
+    out_exception->SetSimpleException(kNotObjectOrFunction);
     return;
   }
 
@@ -559,8 +542,7 @@
   JSC::JSObject* js_object = NULL;
   if (jsvalue.isNull()) {
     if (!(conversion_flags & kConversionFlagNullable)) {
-      out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                        kNotNullableType);
+      out_exception->SetSimpleException(kNotNullableType);
     }
     // Return here whether an exception was set or not.
     return;
@@ -569,8 +551,7 @@
     // 1. If Type(V) is not Object, throw a TypeError
     js_object = jsvalue.getObject();
     if (!js_object) {
-      out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                        kNotObjectType);
+      out_exception->SetSimpleException(kNotObjectType);
       return;
     }
   }
diff --git a/src/cobalt/script/javascriptcore/javascriptcore.gyp b/src/cobalt/script/javascriptcore/javascriptcore.gyp
index 0504492..9cee381 100644
--- a/src/cobalt/script/javascriptcore/javascriptcore.gyp
+++ b/src/cobalt/script/javascriptcore/javascriptcore.gyp
@@ -70,6 +70,7 @@
       'all_dependent_settings': {
         'defines': [
           'ENGINE_DEFINES_ATTRIBUTES_ON_OBJECT',
+          'ENGINE_USES_CONSERVATIVE_ROOTING',
         ],
       },
       'msvs_disabled_warnings': [
diff --git a/src/cobalt/script/javascriptcore/jsc_exception_state.cc b/src/cobalt/script/javascriptcore/jsc_exception_state.cc
index 657a11b..b1c63d2 100644
--- a/src/cobalt/script/javascriptcore/jsc_exception_state.cc
+++ b/src/cobalt/script/javascriptcore/jsc_exception_state.cc
@@ -34,12 +34,17 @@
   DCHECK(exception_->isErrorInstance());
 }
 
-void JSCExceptionState::SetSimpleException(SimpleExceptionType simple_exception,
-                                           const std::string& message) {
+void JSCExceptionState::SetSimpleException(MessageType message_type, ...) {
   DCHECK(thread_checker_.CalledOnValidThread());
   JSC::JSLockHolder lock(&global_object_->globalData());
-  WTF::String error_string = ToWTFString(message);
-  switch (simple_exception) {
+
+  va_list arguments;
+  va_start(arguments, message_type);
+  WTF::String error_string = ToWTFString(
+      base::StringPrintV(GetExceptionMessageFormat(message_type), arguments));
+  va_end(arguments);
+
+  switch (GetSimpleExceptionType(message_type)) {
     case kError:
       exception_ = JSC::createError(global_object_, error_string);
       break;
diff --git a/src/cobalt/script/javascriptcore/jsc_exception_state.h b/src/cobalt/script/javascriptcore/jsc_exception_state.h
index e5e3a22..1dfd273 100644
--- a/src/cobalt/script/javascriptcore/jsc_exception_state.h
+++ b/src/cobalt/script/javascriptcore/jsc_exception_state.h
@@ -31,8 +31,7 @@
       : global_object_(global_object), exception_(NULL) {}
   // ExceptionState interface
   void SetException(const scoped_refptr<ScriptException>& exception) OVERRIDE;
-  void SetSimpleException(SimpleExceptionType simple_exception,
-                          const std::string& message) OVERRIDE;
+  void SetSimpleException(MessageType message_type, ...) OVERRIDE;
 
   bool is_exception_set() const { return (exception_ != NULL); }
   JSC::JSObject* exception_object() { return exception_; }
diff --git a/src/cobalt/script/javascriptcore/numeric_conversion_test.cc b/src/cobalt/script/javascriptcore/numeric_conversion_test.cc
index 66e6653..04c9481 100644
--- a/src/cobalt/script/javascriptcore/numeric_conversion_test.cc
+++ b/src/cobalt/script/javascriptcore/numeric_conversion_test.cc
@@ -205,7 +205,6 @@
   const double kInfinity = std::numeric_limits<double>::infinity();
   const double kNegativeInfinity = -std::numeric_limits<double>::infinity();
 
-
   // Unrestricted non-finite floating point conversions
   EXPECT_EQ(kInfinity, JSValueToNumber<TypeParam>(
                            this->exec_state_, JSC::jsNumber(kInfinity),
@@ -220,8 +219,7 @@
 
   // Restricted non-finite floating point conversions. These should throw a
   // TypeError.
-  EXPECT_CALL(this->exception_state_,
-              SetSimpleException(ExceptionState::kTypeError, _))
+  EXPECT_CALL(this->exception_state_, SetSimpleExceptionVA(kNotFinite, _))
       .Times(3);
   JSValueToNumber<TypeParam>(this->exec_state_, JSC::jsNumber(kInfinity),
                              kConversionFlagRestricted,
@@ -234,7 +232,6 @@
                              &this->exception_state_);
 }
 
-
 // ToNumber (http://es5.github.io/#x9.3) calls the ToPrimitive operation:
 //     http://es5.github.io/#x9.1
 // ToPrimitive calls the [[DefaultValue]] method of the object:
diff --git a/src/cobalt/script/javascriptcore/union_type_conversion_impl.h b/src/cobalt/script/javascriptcore/union_type_conversion_impl.h
index 7aa589d..9122056 100644
--- a/src/cobalt/script/javascriptcore/union_type_conversion_impl.h
+++ b/src/cobalt/script/javascriptcore/union_type_conversion_impl.h
@@ -101,9 +101,9 @@
     }
   }
 
-  // TODO: Support Date, RegExp, DOMException, Error, ArrayBuffer
-  //     DataView, TypedArrayName, callback functions, dictionary, array type.
-  //     and sequences if necessary.
+  // TODO: Support Date, RegExp, DOMException, Error, ArrayBuffer, DataView,
+  //       TypedArrayName, callback functions, dictionary, array type.
+  //       And sequences if necessary.
 
   // 14. If V is a Boolean value, then:
   //   1. If types includes a boolean, then return the result of converting V
@@ -182,8 +182,7 @@
   }
 
   // 19. Throw a TypeError.
-  exception_state->SetSimpleException(
-      ExceptionState::kTypeError, "Value is not a member of the union type.");
+  exception_state->SetSimpleException(kNotUnionType);
 }
 
 template <typename T1, typename T2, typename T3>
@@ -270,9 +269,9 @@
     }
   }
 
-  // TODO: Support Date, RegExp, DOMException, Error, ArrayBuffer
-  //     DataView, TypedArrayName, callback functions, dictionary, array type.
-  //     and sequences if necessary.
+  // TODO: Support Date, RegExp, DOMException, Error, ArrayBuffer, DataView,
+  //       TypedArrayName, callback functions, dictionary, array type.
+  //       And sequences if necessary.
 
   // 14. If V is a Boolean value, then:
   //   1. If types includes a boolean, then return the result of converting V
@@ -379,8 +378,7 @@
   }
 
   // 19. Throw a TypeError.
-  exception_state->SetSimpleException(
-      ExceptionState::kTypeError, "Value is not a member of the union type.");
+  exception_state->SetSimpleException(kNotUnionType);
 }
 
 template <typename T1, typename T2, typename T3, typename T4>
@@ -480,9 +478,9 @@
     }
   }
 
-  // TODO: Support Date, RegExp, DOMException, Error, ArrayBuffer
-  //     DataView, TypedArrayName, callback functions, dictionary, array type.
-  //     and sequences if necessary.
+  // TODO: Support Date, RegExp, DOMException, Error, ArrayBuffer, DataView,
+  //       TypedArrayName, callback functions, dictionary, array type.
+  //       And sequences if necessary.
 
   // 14. If V is a Boolean value, then:
   //   1. If types includes a boolean, then return the result of converting V
@@ -617,8 +615,7 @@
   }
 
   // 19. Throw a TypeError.
-  exception_state->SetSimpleException(
-      ExceptionState::kTypeError, "Value is not a member of the union type.");
+  exception_state->SetSimpleException(kNotUnionType);
 }
 
 }  // namespace javascriptcore
diff --git a/src/cobalt/script/javascriptcore/union_type_conversion_impl.h.pump b/src/cobalt/script/javascriptcore/union_type_conversion_impl.h.pump
index 34dcb30..54eae9a 100644
--- a/src/cobalt/script/javascriptcore/union_type_conversion_impl.h.pump
+++ b/src/cobalt/script/javascriptcore/union_type_conversion_impl.h.pump
@@ -23,8 +23,8 @@
  * limitations under the License.
  */
 
-#ifndef SCRIPT_JAVASCRIPTCORE_UNION_TYPE_CONVERSION_IMPL_H_
-#define SCRIPT_JAVASCRIPTCORE_UNION_TYPE_CONVERSION_IMPL_H_
+#ifndef COBALT_SCRIPT_JAVASCRIPTCORE_UNION_TYPE_CONVERSION_IMPL_H_
+#define COBALT_SCRIPT_JAVASCRIPTCORE_UNION_TYPE_CONVERSION_IMPL_H_
 
 #include "cobalt/script/javascriptcore/jsc_global_object.h"
 #include "cobalt/script/union_type.h"
@@ -187,8 +187,7 @@
 
 
   // 19. Throw a TypeError.
-  exception_state->SetSimpleException(
-      ExceptionState::kTypeError, "Value is not a member of the union type.");
+  exception_state->SetSimpleException(kNotUnionType);
 }
 
 ]]  $$ for NUM_MEMBERS
@@ -197,4 +196,4 @@
 }  // namespace script
 }  // namespace cobalt
 
-#endif  // SCRIPT_JAVASCRIPTCORE_UNION_TYPE_CONVERSION_IMPL_H_
+#endif  // COBALT_SCRIPT_JAVASCRIPTCORE_UNION_TYPE_CONVERSION_IMPL_H_
diff --git a/src/cobalt/script/logging_exception_state.h b/src/cobalt/script/logging_exception_state.h
index d72acfd..abe79d7 100644
--- a/src/cobalt/script/logging_exception_state.h
+++ b/src/cobalt/script/logging_exception_state.h
@@ -19,6 +19,7 @@
 #include <string>
 
 #include "base/logging.h"
+#include "base/stringprintf.h"
 #include "cobalt/script/exception_state.h"
 
 namespace cobalt {
@@ -30,9 +31,14 @@
   void SetException(const scoped_refptr<ScriptException>& exception) OVERRIDE {
     LogException(exception->name(), exception->message());
   }
-  void SetSimpleException(SimpleExceptionType simple_error,
-                          const std::string& message) OVERRIDE {
-    LogException(SimpleExceptionToString(simple_error), message);
+
+  void SetSimpleException(MessageType message_type, ...) OVERRIDE {
+    va_list arguments;
+    va_start(arguments, message_type);
+    LogException(
+        SimpleExceptionToString(GetSimpleExceptionType(message_type)),
+        base::StringPrintV(GetExceptionMessageFormat(message_type), arguments));
+    va_end(arguments);
   }
 
   bool is_exception_set() const { return is_exception_set_; }
diff --git a/src/cobalt/script/mozjs/callback_function_conversion.h b/src/cobalt/script/mozjs/callback_function_conversion.h
index 1e0966d..85fd73a 100644
--- a/src/cobalt/script/mozjs/callback_function_conversion.h
+++ b/src/cobalt/script/mozjs/callback_function_conversion.h
@@ -64,8 +64,7 @@
 
   if (value.isNull()) {
     if (!(conversion_flags & kConversionFlagNullable)) {
-      exception_state->SetSimpleException(ExceptionState::kTypeError,
-                                          kNotNullableType);
+      exception_state->SetSimpleException(kNotNullableType);
     }
     // If it is a nullable type, just return.
     return;
@@ -78,8 +77,7 @@
     object = JSVAL_TO_OBJECT(value);
   }
   if (!object || !JS_ObjectIsFunction(context, object)) {
-    exception_state->SetSimpleException(ExceptionState::kTypeError,
-                                        "Value is not a function.");
+    exception_state->SetSimpleException(kNotFunctionValue);
     return;
   }
 
diff --git a/src/cobalt/script/mozjs/conversion_helpers.cc b/src/cobalt/script/mozjs/conversion_helpers.cc
index c469d26..5eb537d 100644
--- a/src/cobalt/script/mozjs/conversion_helpers.cc
+++ b/src/cobalt/script/mozjs/conversion_helpers.cc
@@ -43,16 +43,14 @@
 
   JS::RootedString string(context, JS_ValueToString(context, value));
   if (!string) {
-    exception_state->SetSimpleException(ExceptionState::kTypeError,
-                                        "Not supported type.");
+    exception_state->SetSimpleException(kConvertToStringFailed);
     return;
   }
 
   JSAutoByteString auto_byte_string;
   char* utf8_chars = auto_byte_string.encodeUtf8(context, string);
   if (!utf8_chars) {
-    exception_state->SetSimpleException(ExceptionState::kTypeError,
-                                        "Failed to convert to utf8.");
+    exception_state->SetSimpleException(kConvertToUTF8Failed);
     return;
   }
 
@@ -86,8 +84,7 @@
   // 1. If Type(V) is not Object, throw a TypeError
   // We'll handle the null case below.
   if (!value.isObjectOrNull()) {
-    exception_state->SetSimpleException(ExceptionState::kTypeError,
-                                        kNotObjectType);
+    exception_state->SetSimpleException(kNotObjectType);
     return;
   }
 
@@ -95,8 +92,7 @@
   if (!js_object) {
     // Set an exception if this is not nullable.
     if (!(conversion_flags & kConversionFlagNullable)) {
-      exception_state->SetSimpleException(ExceptionState::kTypeError,
-                                          kNotNullableType);
+      exception_state->SetSimpleException(kNotNullableType);
     }
     // Return here even for the non-exception case.
     return;
diff --git a/src/cobalt/script/mozjs/conversion_helpers.h b/src/cobalt/script/mozjs/conversion_helpers.h
index 5aa53ed..ef3c581 100644
--- a/src/cobalt/script/mozjs/conversion_helpers.h
+++ b/src/cobalt/script/mozjs/conversion_helpers.h
@@ -40,11 +40,6 @@
 namespace script {
 namespace mozjs {
 
-const char kNotNullableType[] = "Value is null but type is not nullable.";
-const char kNotObjectType[] = "Value is not an object.";
-const char kDoesNotImplementInterface[] =
-    "Value does not implement the interface type.";
-
 // Flags that can be used as a bitmask for special conversion behaviour.
 enum ConversionFlags {
   kNoConversionFlags = 0,
@@ -177,9 +172,7 @@
   JSBool success = JS_ValueToInt64(context, value, &out);
   DCHECK(success);
   if (!success) {
-    exception_state->SetSimpleException(
-        ExceptionState::kTypeError,
-        "Cannot convert a JavaScript value to int64_t.");
+    exception_state->SetSimpleException(kNotInt64Type);
     return;
   }
   *out_number = static_cast<T>(out);
@@ -251,9 +244,7 @@
   JSBool success = JS_ValueToUint64(context, value, &out);
   DCHECK(success);
   if (!success) {
-    exception_state->SetSimpleException(
-        ExceptionState::kTypeError,
-        "Cannot convert a JavaScript value to uint64_t.");
+    exception_state->SetSimpleException(kNotUint64Type);
     return;
   }
   *out_number = static_cast<T>(out);
@@ -294,16 +285,13 @@
   DCHECK(out_number);
   double double_value;
   if (!JS::ToNumber(context, value, &double_value)) {
-    exception_state->SetSimpleException(
-        ExceptionState::kError,
-        "Cannot convert a JavaScript value to a number.");
+    exception_state->SetSimpleException(kNotNumberType);
     return;
   }
 
   if (!mozilla::IsFinite(double_value) &&
       (conversion_flags & kConversionFlagRestricted)) {
-    exception_state->SetSimpleException(ExceptionState::kTypeError,
-                                        "Non-finite floating-point value.");
+    exception_state->SetSimpleException(kNotFinite);
     return;
   }
 
@@ -395,15 +383,12 @@
   JS::RootedObject js_object(context);
   if (value.isNull() || value.isUndefined()) {
     if (!(conversion_flags & kConversionFlagNullable)) {
-      exception_state->SetSimpleException(ExceptionState::kTypeError,
-                                          kNotNullableType);
+      exception_state->SetSimpleException(kNotNullableType);
     }
     return;
   }
   if (!JS_ValueToObject(context, value, js_object.address())) {
-    exception_state->SetSimpleException(
-        ExceptionState::kTypeError,
-        "Cannot convert a JavaScript value to an object.");
+    exception_state->SetSimpleException(kNotObjectType);
     return;
   }
   DCHECK(js_object);
@@ -418,8 +403,7 @@
           wrapper_factory->DoesObjectImplementInterface(js_object,
                                                         base::GetTypeId<T>());
       if (!object_implements_interface) {
-        exception_state->SetSimpleException(ExceptionState::kTypeError,
-                                            kDoesNotImplementInterface);
+        exception_state->SetSimpleException(kDoesNotImplementInterface);
         return;
       }
       WrapperPrivate* wrapper_private =
@@ -429,8 +413,7 @@
     }
   }
   // This is not a platform object. Return a type error.
-  exception_state->SetSimpleException(ExceptionState::kTypeError,
-                                      kDoesNotImplementInterface);
+  exception_state->SetSimpleException(kDoesNotImplementInterface);
 }
 
 // CallbackInterface -> JSValue
@@ -473,8 +456,7 @@
       << "No conversion flags supported.";
   if (value.isNull()) {
     if (!(conversion_flags & kConversionFlagNullable)) {
-      out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                        kNotNullableType);
+      out_exception->SetSimpleException(kNotNullableType);
     }
     // If it is a nullable type, just return.
     return;
@@ -485,8 +467,7 @@
   // checking if the correct properties exist will happen when the operation
   // on the callback interface is run.
   if (!value.isObject()) {
-    out_exception->SetSimpleException(ExceptionState::kTypeError,
-                                      kNotObjectType);
+    out_exception->SetSimpleException(kNotObjectType);
     return;
   }
 
diff --git a/src/cobalt/script/mozjs/mozjs.gyp b/src/cobalt/script/mozjs/mozjs.gyp
index 23ec990..76f11c1 100644
--- a/src/cobalt/script/mozjs/mozjs.gyp
+++ b/src/cobalt/script/mozjs/mozjs.gyp
@@ -43,10 +43,13 @@
       'defines': [ 'ENGINE_SUPPORTS_INT64', ],
       'all_dependent_settings': {
         'defines': [
-        # SpiderMonkey bindings implements indexed deleters.
-        'ENGINE_SUPPORTS_INDEXED_DELETERS',
-        'ENGINE_SUPPORTS_INT64',
-        'ENGINE_SUPPORTS_STACK_TRACE_COLUMNS', ],
+          # SpiderMonkey bindings implements indexed deleters.
+          'ENGINE_SUPPORTS_INDEXED_DELETERS',
+          'ENGINE_SUPPORTS_INT64',
+          'ENGINE_SUPPORTS_STACK_TRACE_COLUMNS',
+          # TODO: Remove this when exact rooting and generational GC is enabled.
+          'ENGINE_USES_CONSERVATIVE_ROOTING',
+        ],
       },
       'conditions' :[
         ['cobalt_enable_jit == 1', {
diff --git a/src/cobalt/script/mozjs/mozjs_callback_function.h b/src/cobalt/script/mozjs/mozjs_callback_function.h
index 2994166..a2714de 100644
--- a/src/cobalt/script/mozjs/mozjs_callback_function.h
+++ b/src/cobalt/script/mozjs/mozjs_callback_function.h
@@ -57,12 +57,16 @@
 
   CallbackResult<R> Run()
       const OVERRIDE {
-    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
-    if (function) {
+    JS::RootedObject function(context_, weak_function_.Get());
+    if (!function) {
+      DLOG(WARNING) << "Function was garbage collected.";
+      callback_result.exception = true;
+    } else {
       JSAutoRequest auto_request(context_);
       JSAutoCompartment auto_compartment(context_, function);
+      JSExceptionState* previous_exception_state =
+          JS_SaveExceptionState(context_);
 
       // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
       // Callback 'this' is set to null, unless overridden by other
@@ -79,6 +83,7 @@
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
       }
+      JS_RestoreExceptionState(context_, previous_exception_state);
     }
     return callback_result;
   }
@@ -105,12 +110,16 @@
   CallbackResult<R> Run(
       typename base::internal::CallbackParamTraits<A1>::ForwardType a1)
       const OVERRIDE {
-    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
-    if (function) {
+    JS::RootedObject function(context_, weak_function_.Get());
+    if (!function) {
+      DLOG(WARNING) << "Function was garbage collected.";
+      callback_result.exception = true;
+    } else {
       JSAutoRequest auto_request(context_);
       JSAutoCompartment auto_compartment(context_, function);
+      JSExceptionState* previous_exception_state =
+          JS_SaveExceptionState(context_);
 
       // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
       // Callback 'this' is set to null, unless overridden by other
@@ -132,6 +141,7 @@
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
       }
+      JS_RestoreExceptionState(context_, previous_exception_state);
     }
     return callback_result;
   }
@@ -159,12 +169,16 @@
       typename base::internal::CallbackParamTraits<A1>::ForwardType a1,
       typename base::internal::CallbackParamTraits<A2>::ForwardType a2)
       const OVERRIDE {
-    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
-    if (function) {
+    JS::RootedObject function(context_, weak_function_.Get());
+    if (!function) {
+      DLOG(WARNING) << "Function was garbage collected.";
+      callback_result.exception = true;
+    } else {
       JSAutoRequest auto_request(context_);
       JSAutoCompartment auto_compartment(context_, function);
+      JSExceptionState* previous_exception_state =
+          JS_SaveExceptionState(context_);
 
       // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
       // Callback 'this' is set to null, unless overridden by other
@@ -187,6 +201,7 @@
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
       }
+      JS_RestoreExceptionState(context_, previous_exception_state);
     }
     return callback_result;
   }
@@ -215,12 +230,16 @@
       typename base::internal::CallbackParamTraits<A2>::ForwardType a2,
       typename base::internal::CallbackParamTraits<A3>::ForwardType a3)
       const OVERRIDE {
-    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
-    if (function) {
+    JS::RootedObject function(context_, weak_function_.Get());
+    if (!function) {
+      DLOG(WARNING) << "Function was garbage collected.";
+      callback_result.exception = true;
+    } else {
       JSAutoRequest auto_request(context_);
       JSAutoCompartment auto_compartment(context_, function);
+      JSExceptionState* previous_exception_state =
+          JS_SaveExceptionState(context_);
 
       // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
       // Callback 'this' is set to null, unless overridden by other
@@ -244,6 +263,7 @@
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
       }
+      JS_RestoreExceptionState(context_, previous_exception_state);
     }
     return callback_result;
   }
@@ -273,12 +293,16 @@
       typename base::internal::CallbackParamTraits<A3>::ForwardType a3,
       typename base::internal::CallbackParamTraits<A4>::ForwardType a4)
       const OVERRIDE {
-    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
-    if (function) {
+    JS::RootedObject function(context_, weak_function_.Get());
+    if (!function) {
+      DLOG(WARNING) << "Function was garbage collected.";
+      callback_result.exception = true;
+    } else {
       JSAutoRequest auto_request(context_);
       JSAutoCompartment auto_compartment(context_, function);
+      JSExceptionState* previous_exception_state =
+          JS_SaveExceptionState(context_);
 
       // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
       // Callback 'this' is set to null, unless overridden by other
@@ -303,6 +327,7 @@
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
       }
+      JS_RestoreExceptionState(context_, previous_exception_state);
     }
     return callback_result;
   }
@@ -334,12 +359,16 @@
       typename base::internal::CallbackParamTraits<A4>::ForwardType a4,
       typename base::internal::CallbackParamTraits<A5>::ForwardType a5)
       const OVERRIDE {
-    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
-    if (function) {
+    JS::RootedObject function(context_, weak_function_.Get());
+    if (!function) {
+      DLOG(WARNING) << "Function was garbage collected.";
+      callback_result.exception = true;
+    } else {
       JSAutoRequest auto_request(context_);
       JSAutoCompartment auto_compartment(context_, function);
+      JSExceptionState* previous_exception_state =
+          JS_SaveExceptionState(context_);
 
       // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
       // Callback 'this' is set to null, unless overridden by other
@@ -365,6 +394,7 @@
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
       }
+      JS_RestoreExceptionState(context_, previous_exception_state);
     }
     return callback_result;
   }
@@ -397,12 +427,16 @@
       typename base::internal::CallbackParamTraits<A5>::ForwardType a5,
       typename base::internal::CallbackParamTraits<A6>::ForwardType a6)
       const OVERRIDE {
-    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
-    if (function) {
+    JS::RootedObject function(context_, weak_function_.Get());
+    if (!function) {
+      DLOG(WARNING) << "Function was garbage collected.";
+      callback_result.exception = true;
+    } else {
       JSAutoRequest auto_request(context_);
       JSAutoCompartment auto_compartment(context_, function);
+      JSExceptionState* previous_exception_state =
+          JS_SaveExceptionState(context_);
 
       // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
       // Callback 'this' is set to null, unless overridden by other
@@ -429,6 +463,7 @@
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
       }
+      JS_RestoreExceptionState(context_, previous_exception_state);
     }
     return callback_result;
   }
@@ -462,12 +497,16 @@
       typename base::internal::CallbackParamTraits<A6>::ForwardType a6,
       typename base::internal::CallbackParamTraits<A7>::ForwardType a7)
       const OVERRIDE {
-    JS::RootedObject function(context_, weak_function_.Get());
     CallbackResult<R> callback_result;
-    DLOG_IF(WARNING, !function) << "Function was garbage collected.";
-    if (function) {
+    JS::RootedObject function(context_, weak_function_.Get());
+    if (!function) {
+      DLOG(WARNING) << "Function was garbage collected.";
+      callback_result.exception = true;
+    } else {
       JSAutoRequest auto_request(context_);
       JSAutoCompartment auto_compartment(context_, function);
+      JSExceptionState* previous_exception_state =
+          JS_SaveExceptionState(context_);
 
       // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
       // Callback 'this' is set to null, unless overridden by other
@@ -495,6 +534,7 @@
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
       }
+      JS_RestoreExceptionState(context_, previous_exception_state);
     }
     return callback_result;
   }
diff --git a/src/cobalt/script/mozjs/mozjs_callback_function.h.pump b/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
index 6ea3efe..810dcc5 100644
--- a/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
+++ b/src/cobalt/script/mozjs/mozjs_callback_function.h.pump
@@ -84,6 +84,8 @@
     } else {
       JSAutoRequest auto_request(context_);
       JSAutoCompartment auto_compartment(context_, function);
+      JSExceptionState* previous_exception_state =
+          JS_SaveExceptionState(context_);
 
       // https://www.w3.org/TR/WebIDL/#es-invoking-callback-functions
       // Callback 'this' is set to null, unless overridden by other specifications
@@ -112,6 +114,7 @@
       } else {
         callback_result = ConvertCallbackReturnValue<R>(context_, return_value);
       }
+      JS_RestoreExceptionState(context_, previous_exception_state);
     }
     return callback_result;
   }
diff --git a/src/cobalt/script/mozjs/mozjs_exception_state.cc b/src/cobalt/script/mozjs/mozjs_exception_state.cc
index e7839c4..111b56e 100644
--- a/src/cobalt/script/mozjs/mozjs_exception_state.cc
+++ b/src/cobalt/script/mozjs/mozjs_exception_state.cc
@@ -16,34 +16,42 @@
 #include "cobalt/script/mozjs/mozjs_exception_state.h"
 
 #include <string>
+#include <vector>
 
 #include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
 #include "cobalt/script/mozjs/conversion_helpers.h"
-#include "third_party/mozjs/js/src/jsapi.h"
 
 namespace cobalt {
 namespace script {
 namespace mozjs {
 
 namespace {
-std::string SimpleExceptionToString(ExceptionState::SimpleExceptionType type) {
+
+JSExnType ConvertToMozjsExceptionType(SimpleExceptionType type) {
   switch (type) {
-    case ExceptionState::kError:
-      return "Error";
-    case ExceptionState::kTypeError:
-      return "TypeError";
-    case ExceptionState::kRangeError:
-      return "RangeError";
-    case ExceptionState::kReferenceError:
-      return "ReferenceError";
-    case ExceptionState::kSyntaxError:
-      return "SyntaxError";
-    case ExceptionState::kURIError:
-      return "URIError";
+    case kError:
+      return JSEXN_ERR;
+    case kTypeError:
+      return JSEXN_TYPEERR;
+    case kRangeError:
+      return JSEXN_RANGEERR;
+    case kReferenceError:
+      return JSEXN_REFERENCEERR;
+    case kSyntaxError:
+      return JSEXN_SYNTAXERR;
+    case kURIError:
+      return JSEXN_URIERR;
   }
-  NOTREACHED();
-  return "";
 }
+
+// JSErrorCallback.
+const JSErrorFormatString* GetErrorMessage(void* user_ref, const char* locale,
+                                           const unsigned error_number) {
+  return static_cast<JSErrorFormatString*>(user_ref);
+}
+
 }  // namespace
 
 void MozjsExceptionState::SetException(
@@ -63,17 +71,28 @@
   is_exception_set_ = true;
 }
 
-void MozjsExceptionState::SetSimpleException(
-    SimpleExceptionType simple_exception, const std::string& message) {
+void MozjsExceptionState::SetSimpleException(MessageType message_type, ...) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!is_exception_set_);
 
-  std::stringstream stream;
-  stream << SimpleExceptionToString(simple_exception) << ": " << message;
-  // JS_ReportError first builds an error message from the given sprintf-style
-  // format string and any additional arguments passed after it. The resulting
-  // error message is passed to the context's JSErrorReporter callback.
-  JS_ReportError(context_, stream.str().c_str());
+  va_list arguments;
+  va_start(arguments, message_type);
+  std::string error_message =
+      base::StringPrintV(GetExceptionMessageFormat(message_type), arguments);
+  JSErrorFormatString format_string;
+  format_string.format = error_message.c_str();
+  // Already fed arguments for format.
+  format_string.argCount = 0;
+  format_string.exnType =
+      ConvertToMozjsExceptionType(GetSimpleExceptionType(message_type));
+
+  // This function creates a JSErrorReport, populate it with an error message
+  // obtained from the given JSErrorCallback. The resulting error message is
+  // passed to the context's JSErrorReporter callback.
+  JS_ReportErrorNumber(context_, GetErrorMessage,
+                       static_cast<void*>(&format_string), message_type);
+  va_end(arguments);
+
   is_exception_set_ = true;
 }
 
diff --git a/src/cobalt/script/mozjs/mozjs_exception_state.h b/src/cobalt/script/mozjs/mozjs_exception_state.h
index 4a3c11d..361dc70 100644
--- a/src/cobalt/script/mozjs/mozjs_exception_state.h
+++ b/src/cobalt/script/mozjs/mozjs_exception_state.h
@@ -32,8 +32,7 @@
       : is_exception_set_(false), context_(context) {}
   // ExceptionState interface
   void SetException(const scoped_refptr<ScriptException>& exception) OVERRIDE;
-  void SetSimpleException(SimpleExceptionType simple_exception,
-                          const std::string& message) OVERRIDE;
+  void SetSimpleException(MessageType message_type, ...) OVERRIDE;
 
   bool is_exception_set() const { return is_exception_set_; }
 
diff --git a/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc b/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
index d25e1b7..273f328 100644
--- a/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
+++ b/src/cobalt/script/mozjs/mozjs_global_object_proxy.cc
@@ -147,9 +147,6 @@
   js::SetDOMProxyInformation(0 /*domProxyHandlerFamily*/, kJSProxySlotExpando,
                              DOMProxyShadowsCheck);
 #endif
-#if !defined(COBALT_BUILD_TYPE_GOLD) && !defined(COBALT_BUILD_TYPE_QA)
-  options |= JSOPTION_EXTRA_WARNINGS;
-#endif
   JS_SetOptions(context_, options);
 
   JS_SetErrorReporter(context_, &MozjsGlobalObjectProxy::ReportErrorHandler);
@@ -202,7 +199,8 @@
   const base::SourceLocation location = mozjs_source_code->location();
 
   JSAutoRequest auto_request(context_);
-  JSAutoCompartment auto_comparment(context_, global_object_proxy_);
+  JSAutoCompartment auto_compartment(context_, global_object_proxy_);
+  JSExceptionState* previous_exception_state = JS_SaveExceptionState(context_);
   JS::RootedValue result_value(context_);
   std::string error_message;
   last_error_message_ = &error_message;
@@ -230,6 +228,7 @@
       *out_result_utf8 = *last_error_message_;
     }
   }
+  JS_RestoreExceptionState(context_, previous_exception_state);
   last_error_message_ = NULL;
   return success;
 }
@@ -239,6 +238,29 @@
   return util::GetStackTrace(context_, max_frames);
 }
 
+void MozjsGlobalObjectProxy::PreventGarbageCollection(
+    const scoped_refptr<Wrappable>& wrappable) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  JSAutoRequest auto_request(context_);
+  JSAutoCompartment auto_compartment(context_, global_object_proxy_);
+  WrapperPrivate* wrapper_private =
+      WrapperPrivate::GetFromWrappable(wrappable, context_, wrapper_factory());
+  JS::RootedObject proxy(context_, wrapper_private->js_object_proxy());
+  kept_alive_objects_.insert(CachedWrapperMultiMap::value_type(
+      wrappable.get(), JS::Heap<JSObject*>(proxy)));
+}
+
+void MozjsGlobalObjectProxy::AllowGarbageCollection(
+    const scoped_refptr<Wrappable>& wrappable) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  CachedWrapperMultiMap::iterator it =
+      kept_alive_objects_.find(wrappable.get());
+  DCHECK(it != kept_alive_objects_.end());
+  if (it != kept_alive_objects_.end()) {
+    kept_alive_objects_.erase(it);
+  }
+}
+
 void MozjsGlobalObjectProxy::DisableEval(const std::string& message) {
   DCHECK(thread_checker_.CalledOnValidThread());
   eval_disabled_message_.emplace(message);
@@ -260,7 +282,7 @@
 void MozjsGlobalObjectProxy::Bind(const std::string& identifier,
                                   const scoped_refptr<Wrappable>& impl) {
   JSAutoRequest auto_request(context_);
-  JSAutoCompartment auto_comparment(context_, global_object_proxy_);
+  JSAutoCompartment auto_compartment(context_, global_object_proxy_);
 
   JS::RootedObject wrapper_proxy(context_,
                                  wrapper_factory_->GetWrapperProxy(impl));
@@ -365,6 +387,11 @@
                               "MozjsGlobalObjectProxy");
     }
   }
+  for (CachedWrapperMultiMap::iterator it =
+           global_object_environment->kept_alive_objects_.begin();
+       it != global_object_environment->kept_alive_objects_.end(); ++it) {
+    JS_CallHeapObjectTracer(trace, &it->second, "MozjsGlobalObjectProxy");
+  }
 }
 
 JSBool MozjsGlobalObjectProxy::CheckEval(JSContext* context) {
diff --git a/src/cobalt/script/mozjs/mozjs_global_object_proxy.h b/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
index fc0b760..de36ae6 100644
--- a/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
+++ b/src/cobalt/script/mozjs/mozjs_global_object_proxy.h
@@ -63,14 +63,10 @@
   std::vector<StackFrame> GetStackTrace(int max_frames = 0) OVERRIDE;
 
   void PreventGarbageCollection(
-      const scoped_refptr<Wrappable>& wrappable) OVERRIDE {
-    NOTIMPLEMENTED();
-  }
+      const scoped_refptr<Wrappable>& wrappable) OVERRIDE;
 
   void AllowGarbageCollection(
-      const scoped_refptr<Wrappable>& wrappable) OVERRIDE {
-    NOTIMPLEMENTED();
-  }
+      const scoped_refptr<Wrappable>& wrappable) OVERRIDE;
 
   void DisableEval(const std::string& message) OVERRIDE;
 
@@ -144,10 +140,13 @@
   };
 
   typedef base::hash_map<intptr_t, InterfaceData*> CachedInterfaceData;
+  typedef base::hash_multimap<Wrappable*, JS::Heap<JSObject*> >
+      CachedWrapperMultiMap;
 
   base::ThreadChecker thread_checker_;
   JSContext* context_;
   WeakHeapObjectManager weak_object_manager_;
+  CachedWrapperMultiMap kept_alive_objects_;
   scoped_ptr<ReferencedObjectMap> referenced_objects_;
   CachedInterfaceData cached_interface_data_;
   STLValueDeleter<CachedInterfaceData> cached_interface_data_deleter_;
diff --git a/src/cobalt/script/mozjs/union_type_conversion_impl.h b/src/cobalt/script/mozjs/union_type_conversion_impl.h
index 5d0076f..a8f7e6f 100644
--- a/src/cobalt/script/mozjs/union_type_conversion_impl.h
+++ b/src/cobalt/script/mozjs/union_type_conversion_impl.h
@@ -187,8 +187,7 @@
     return;
   }
   // 19. Throw a TypeError.
-  exception_state->SetSimpleException(
-      ExceptionState::kTypeError, "Value is not a member of the union type.");
+  exception_state->SetSimpleException(kNotUnionType);
 }
 
 template <typename T1, typename T2, typename T3>
@@ -385,8 +384,7 @@
     return;
   }
   // 19. Throw a TypeError.
-  exception_state->SetSimpleException(
-      ExceptionState::kTypeError, "Value is not a member of the union type.");
+  exception_state->SetSimpleException(kNotUnionType);
 }
 
 template <typename T1, typename T2, typename T3, typename T4>
@@ -624,8 +622,7 @@
     return;
   }
   // 19. Throw a TypeError.
-  exception_state->SetSimpleException(
-      ExceptionState::kTypeError, "Value is not a member of the union type.");
+  exception_state->SetSimpleException(kNotUnionType);
 }
 
 }  // namespace mozjs
diff --git a/src/cobalt/script/mozjs/union_type_conversion_impl.h.pump b/src/cobalt/script/mozjs/union_type_conversion_impl.h.pump
index 046f822..d4103ca 100644
--- a/src/cobalt/script/mozjs/union_type_conversion_impl.h.pump
+++ b/src/cobalt/script/mozjs/union_type_conversion_impl.h.pump
@@ -46,12 +46,15 @@
 $range TYPE 1..NUM_MEMBERS
 
 template <$for TYPE , [[typename T$(TYPE)]]>
-void ToJSValue(JSContext* context, const script::UnionType$(NUM_MEMBERS)<$for TYPE , [[T$(TYPE)]]>& in_union, JS::MutableHandleValue out_value) {
+void ToJSValue(
+    JSContext* context,
+    const script::UnionType$(NUM_MEMBERS)<$for TYPE , [[T$(TYPE)]]>& in_union,
+    JS::MutableHandleValue out_value) {
 $for TYPE [[
 
   if (in_union.template IsType<T$(TYPE)>()) {
-      ToJSValue(context, in_union.template AsType<T$(TYPE)>(), out_value);
-      return;
+    ToJSValue(context, in_union.template AsType<T$(TYPE)>(), out_value);
+    return;
   }
 ]]
 
@@ -110,8 +113,8 @@
         global_object_proxy->wrapper_factory();
 
 $for TYPE [[
-    if (UnionTypeTraitsT$(TYPE)::is_interface_type
-        && wrapper_factory->DoesObjectImplementInterface(
+    if (UnionTypeTraitsT$(TYPE)::is_interface_type &&
+        wrapper_factory->DoesObjectImplementInterface(
             rooted_object, UnionTypeTraitsT$(TYPE)::GetTypeID())) {
       FromJSValue(context, value, conversion_flags, exception_state, &t$(TYPE));
       *out_union = script::UnionType$(NUM_MEMBERS)<$for TYPE , [[T$(TYPE)]]>(t$(TYPE));
@@ -192,8 +195,7 @@
 ]]
 
   // 19. Throw a TypeError.
-  exception_state->SetSimpleException(
-      ExceptionState::kTypeError, "Value is not a member of the union type.");
+  exception_state->SetSimpleException(kNotUnionType);
 }
 
 ]]  $$ for NUM_MEMBERS
diff --git a/src/cobalt/script/script.gyp b/src/cobalt/script/script.gyp
index dce7d46..c827de2 100644
--- a/src/cobalt/script/script.gyp
+++ b/src/cobalt/script/script.gyp
@@ -21,6 +21,8 @@
       'type': 'static_library',
       'sources': [
         'call_frame.h',
+        'exception_message.cc',
+        'exception_message.h',
         'execution_state.cc',
         'execution_state.h',
         'global_object_proxy.h',
diff --git a/src/cobalt/script/testing/mock_exception_state.h b/src/cobalt/script/testing/mock_exception_state.h
index 1d8516c..c99c946 100644
--- a/src/cobalt/script/testing/mock_exception_state.h
+++ b/src/cobalt/script/testing/mock_exception_state.h
@@ -29,8 +29,14 @@
 class MockExceptionState : public ExceptionState {
  public:
   MOCK_METHOD1(SetException, void(const scoped_refptr<ScriptException>&));
-  MOCK_METHOD2(SetSimpleException,
-               void(SimpleExceptionType, const std::string&));
+  MOCK_METHOD2(SetSimpleExceptionVA, void(MessageType, va_list));
+
+  void SetSimpleException(MessageType message_type, ...) {
+    va_list arguments;
+    va_start(arguments, message_type);
+    SetSimpleExceptionVA(message_type, arguments);
+    va_end(arguments);
+  }
 };
 
 }  // namespace testing
diff --git a/src/cobalt/storage/virtual_file_system.cc b/src/cobalt/storage/virtual_file_system.cc
index 8b67f27..70e1556 100644
--- a/src/cobalt/storage/virtual_file_system.cc
+++ b/src/cobalt/storage/virtual_file_system.cc
@@ -21,6 +21,8 @@
 #include "base/synchronization/lock.h"
 #include "cobalt/storage/virtual_file.h"
 
+#include "starboard/client_porting/poem/string_poem.h"
+
 namespace cobalt {
 namespace storage {
 
@@ -126,6 +128,21 @@
   base::AutoLock lock(file_table_lock_);
   ClearFileTable();
 
+  if (buffer_size < 0) {
+    DLOG(ERROR) << "Buffer size must be positive: "
+                << buffer_size << " < 0.";
+    return;
+  }
+
+  // The size of the buffer must be checked before copying the beginning of it
+  // into a SerializedHeader.
+  if (static_cast<size_t>(buffer_size) < sizeof(SerializedHeader)) {
+    DLOG(ERROR) << "Buffer size " << buffer_size
+                << " is too small to contain a SerializedHeader of size "
+                << sizeof(SerializedHeader) << "; operation aborted.";
+    return;
+  }
+
   // Read in expected number of files
   SerializedHeader header;
   memcpy(&header, buffer, sizeof(SerializedHeader));
diff --git a/src/cobalt/webdriver/web_driver_module.cc b/src/cobalt/webdriver/web_driver_module.cc
index 8884ddb..46a77e8 100644
--- a/src/cobalt/webdriver/web_driver_module.cc
+++ b/src/cobalt/webdriver/web_driver_module.cc
@@ -403,7 +403,12 @@
                             base::Unretained(this), server_port));
 }
 
-WebDriverModule::~WebDriverModule() { webdriver_thread_.Stop(); }
+WebDriverModule::~WebDriverModule() {
+  webdriver_thread_.message_loop()->PostTask(
+      FROM_HERE, base::Bind(&WebDriverModule::StopServer,
+                            base::Unretained(this)));
+  webdriver_thread_.Stop();
+}
 
 void WebDriverModule::OnWindowRecreated() {
   if (MessageLoop::current() != webdriver_thread_.message_loop()) {
@@ -427,6 +432,10 @@
                  base::Unretained(webdriver_dispatcher_.get()))));
 }
 
+void WebDriverModule::StopServer() {
+  webdriver_server_.reset();
+}
+
 SessionDriver* WebDriverModule::GetSessionDriver(
     const protocol::SessionId& session_id) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/src/cobalt/webdriver/web_driver_module.h b/src/cobalt/webdriver/web_driver_module.h
index c18e7df..2df30dd 100644
--- a/src/cobalt/webdriver/web_driver_module.h
+++ b/src/cobalt/webdriver/web_driver_module.h
@@ -66,6 +66,7 @@
 
  private:
   void StartServer(int server_port);
+  void StopServer();
   void GetServerStatus(
       const base::Value* parameters,
       const WebDriverDispatcher::PathVariableMap* path_variables,
diff --git a/src/cobalt/xhr/xml_http_request.cc b/src/cobalt/xhr/xml_http_request.cc
index 5db9c13..04b02e1 100644
--- a/src/cobalt/xhr/xml_http_request.cc
+++ b/src/cobalt/xhr/xml_http_request.cc
@@ -911,7 +911,7 @@
   // well-formedness error, etc.), return null.
   scoped_refptr<dom::XMLDocument> xml_document = new dom::XMLDocument();
   dom_parser::XMLDecoder xml_decoder(
-      xml_document, xml_document, NULL,
+      xml_document, xml_document, NULL, settings_->max_dom_element_depth(),
       base::SourceLocation("[object XMLHttpRequest]", 1, 1), base::Closure(),
       base::Bind(&XMLHttpRequest::XMLDecoderErrorCallback,
                  base::Unretained(this)));
diff --git a/src/cobalt/xhr/xml_http_request_test.cc b/src/cobalt/xhr/xml_http_request_test.cc
index d944d42..ac3b5c1 100644
--- a/src/cobalt/xhr/xml_http_request_test.cc
+++ b/src/cobalt/xhr/xml_http_request_test.cc
@@ -92,7 +92,7 @@
 
 class FakeSettings : public dom::DOMSettings {
  public:
-  FakeSettings() : dom::DOMSettings(NULL, NULL, NULL, NULL, NULL, NULL) {}
+  FakeSettings() : dom::DOMSettings(0, NULL, NULL, NULL, NULL, NULL, NULL) {}
   GURL base_url() const OVERRIDE { return GURL("http://example.com"); }
 };
 
diff --git a/src/media/base/pipeline.h b/src/media/base/pipeline.h
index 4315f75..3f5aaf6 100644
--- a/src/media/base/pipeline.h
+++ b/src/media/base/pipeline.h
@@ -15,6 +15,7 @@
 #ifndef MEDIA_BASE_PIPELINE_H_
 #define MEDIA_BASE_PIPELINE_H_
 
+#include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop_proxy.h"
 #include "base/time.h"
@@ -23,8 +24,24 @@
 #include "media/base/media_export.h"
 #include "media/base/pipeline_status.h"
 #include "media/base/ranges.h"
+#include "ui/gfx/rect.h"
 #include "ui/gfx/size.h"
 
+#if defined(OS_STARBOARD)
+#if SB_HAS(PLAYER)
+
+#define COBALT_USE_SBPLAYER_PIPELINE
+
+#endif  // SB_HAS(PLAYER)
+#endif  // defined(OS_STARBOARD)
+
+#if defined(COBALT_USE_SBPLAYER_PIPELINE)
+#include "starboard/window.h"
+typedef SbWindow PipelineWindow;
+#else   // defined(COBALT_USE_SBPLAYER_PIPELINE)
+typedef void* PipelineWindow;
+#endif  // defined(COBALT_USE_SBPLAYER_PIPELINE)
+
 namespace media {
 
 class MediaLog;
@@ -34,6 +51,8 @@
 // playing.
 class MEDIA_EXPORT Pipeline : public base::RefCountedThreadSafe<Pipeline> {
  public:
+  typedef base::Callback<void(const gfx::Rect&)> SetBoundsCB;
+
   // Buffering states the pipeline transitions between during playback.
   // kHaveMetadata:
   //   Indicates that the following things are known:
@@ -50,6 +69,7 @@
   typedef base::Callback<void(BufferingState)> BufferingStateCB;
 
   static scoped_refptr<Pipeline> Create(
+      PipelineWindow window,
       const scoped_refptr<base::MessageLoopProxy>& message_loop,
       MediaLog* media_log);
 
@@ -151,6 +171,9 @@
 
   // Gets the current pipeline statistics.
   virtual PipelineStatistics GetStatistics() const = 0;
+
+  // Get the SetBoundsCB used to set the bounds of the video frame.
+  virtual SetBoundsCB GetSetBoundsCB() { return SetBoundsCB(); }
 };
 
 }  // namespace media
diff --git a/src/media/base/pipeline_impl.cc b/src/media/base/pipeline_impl.cc
index 6857cf6..b34ae13 100644
--- a/src/media/base/pipeline_impl.cc
+++ b/src/media/base/pipeline_impl.cc
@@ -68,8 +68,10 @@
 }
 
 scoped_refptr<Pipeline> Pipeline::Create(
+    PipelineWindow window,
     const scoped_refptr<base::MessageLoopProxy>& message_loop,
     MediaLog* media_log) {
+  UNREFERENCED_PARAMETER(window);
   return new PipelineImpl(message_loop, media_log);
 }
 
diff --git a/src/media/base/sbplayer_pipeline.cc b/src/media/base/sbplayer_pipeline.cc
index edc8565..2424340 100644
--- a/src/media/base/sbplayer_pipeline.cc
+++ b/src/media/base/sbplayer_pipeline.cc
@@ -120,12 +120,35 @@
   }
 }
 
+class SetBoundsCaller : public base::RefCountedThreadSafe<SetBoundsCaller> {
+ public:
+  SetBoundsCaller() : player_(kSbPlayerInvalid) {}
+  void SetPlayer(SbPlayer player) {
+    base::Lock lock_;
+    player_ = player;
+  }
+  void SetBounds(const gfx::Rect& rect) {
+    base::AutoLock auto_lock(lock_);
+    if (SbPlayerIsValid(player_)) {
+      SbPlayerSetBounds(player_, rect.x(), rect.y(), rect.width(),
+                        rect.height());
+    }
+  }
+
+ private:
+  base::Lock lock_;
+  SbPlayer player_;
+
+  DISALLOW_COPY_AND_ASSIGN(SetBoundsCaller);
+};
+
 // SbPlayerPipeline is a PipelineBase implementation that uses the SbPlayer
 // interface internally.
 class MEDIA_EXPORT SbPlayerPipeline : public Pipeline, public DemuxerHost {
  public:
   // Constructs a media pipeline that will execute on |message_loop|.
-  SbPlayerPipeline(const scoped_refptr<base::MessageLoopProxy>& message_loop,
+  SbPlayerPipeline(PipelineWindow window,
+                   const scoped_refptr<base::MessageLoopProxy>& message_loop,
                    MediaLog* media_log);
   ~SbPlayerPipeline() OVERRIDE;
 
@@ -155,8 +178,16 @@
 
   bool DidLoadingProgress() const OVERRIDE;
   PipelineStatistics GetStatistics() const OVERRIDE;
+  SetBoundsCB GetSetBoundsCB() OVERRIDE;
 
  private:
+  // A map from raw data pointer returned by DecoderBuffer::GetData() to the
+  // DecoderBuffer and a reference count.  The reference count indicates how
+  // many instances of the DecoderBuffer is currently being decoded in the
+  // pipeline.
+  typedef std::map<const void*, std::pair<scoped_refptr<DecoderBuffer>, int> >
+      DecodingBuffers;
+
   void StartTask();
 
   // DataSourceHost (by way of DemuxerHost) implementation.
@@ -206,6 +237,9 @@
   // Lock used to serialize access for the following data members.
   mutable base::Lock lock_;
 
+  // The window this player associates with.
+  PipelineWindow window_;
+
   // Whether or not the pipeline is running.
   bool running_;
 
@@ -276,15 +310,19 @@
 
   SbPlayer player_;
 
-  std::map<const void*, scoped_refptr<DecoderBuffer> > decoding_buffers_;
+  DecodingBuffers decoding_buffers_;
+
+  scoped_refptr<SetBoundsCaller> set_bounds_caller_;
 
   DISALLOW_COPY_AND_ASSIGN(SbPlayerPipeline);
 };
 
 SbPlayerPipeline::SbPlayerPipeline(
+    PipelineWindow window,
     const scoped_refptr<base::MessageLoopProxy>& message_loop,
     MediaLog* media_log)
-    : message_loop_(message_loop),
+    : window_(window),
+      message_loop_(message_loop),
       media_log_(media_log),
       total_bytes_(0),
       natural_size_(0, 0),
@@ -295,7 +333,8 @@
       ticket_(SB_PLAYER_INITIAL_TICKET),
       audio_read_in_progress_(false),
       video_read_in_progress_(false),
-      player_(kSbPlayerInvalid) {}
+      player_(kSbPlayerInvalid),
+      set_bounds_caller_(new SetBoundsCaller) {}
 
 SbPlayerPipeline::~SbPlayerPipeline() {
   DCHECK(player_ == kSbPlayerInvalid);
@@ -339,6 +378,7 @@
   DCHECK(!stop_cb.is_null());
 
   if (SbPlayerIsValid(player_)) {
+    set_bounds_caller_->SetPlayer(kSbPlayerInvalid);
     SbPlayerDestroy(player_);
     player_ = kSbPlayerInvalid;
   }
@@ -480,6 +520,14 @@
   return statistics_;
 }
 
+Pipeline::SetBoundsCB SbPlayerPipeline::GetSetBoundsCB() {
+#if SB_IS(PLAYER_PUNCHED_OUT)
+  return base::Bind(&SetBoundsCaller::SetBounds, set_bounds_caller_);
+#else   // SB_IS(PLAYER_PUNCHED_OUT)
+  return Pipeline::SetBoundsCB();
+#endif  // SB_IS(PLAYER_PUNCHED_OUT)
+}
+
 void SbPlayerPipeline::StartTask() {
   DCHECK(message_loop_->BelongsToCurrentThread());
 
@@ -528,9 +576,10 @@
   audio_header.bits_per_sample = audio_config.bits_per_channel();
   audio_header.audio_specific_config_size = 0;
   player_ =
-      SbPlayerCreate(kSbMediaVideoCodecH264, kSbMediaAudioCodecAac,
+      SbPlayerCreate(window_, kSbMediaVideoCodecH264, kSbMediaAudioCodecAac,
                      SB_PLAYER_NO_DURATION, drm_system, &audio_header,
                      DeallocateSampleCB, DecoderStatusCB, PlayerStatusCB, this);
+  set_bounds_caller_->SetPlayer(player_);
 }
 
 void SbPlayerPipeline::SetDecryptor(Decryptor* decryptor) {
@@ -663,9 +712,12 @@
       SbPlayerWriteEndOfStream(player_, kSbMediaTypeAudio);
       return;
     }
-    DCHECK(decoding_buffers_.find(buffer->GetData()) ==
-           decoding_buffers_.end());
-    decoding_buffers_[buffer->GetData()] = buffer;
+    DecodingBuffers::iterator iter = decoding_buffers_.find(buffer->GetData());
+    if (iter == decoding_buffers_.end()) {
+      decoding_buffers_[buffer->GetData()] = std::make_pair(buffer, 1);
+    } else {
+      ++iter->second.second;
+    }
     SbPlayerWriteSample(player_, kSbMediaTypeAudio, buffer->GetData(),
                         buffer->GetDataSize(),
                         TimeDeltaToSbMediaTime(buffer->GetTimestamp()), NULL,
@@ -683,8 +735,12 @@
   video_info.is_key_frame = false;
   video_info.frame_width = 1;
   video_info.frame_height = 1;
-  DCHECK(decoding_buffers_.find(buffer->GetData()) == decoding_buffers_.end());
-  decoding_buffers_[buffer->GetData()] = buffer;
+  DecodingBuffers::iterator iter = decoding_buffers_.find(buffer->GetData());
+  if (iter == decoding_buffers_.end()) {
+    decoding_buffers_[buffer->GetData()] = std::make_pair(buffer, 1);
+  } else {
+    ++iter->second.second;
+  }
   SbPlayerWriteSample(player_, kSbMediaTypeVideo, buffer->GetData(),
                       buffer->GetDataSize(),
                       TimeDeltaToSbMediaTime(buffer->GetTimestamp()),
@@ -768,8 +824,17 @@
 
 void SbPlayerPipeline::OnDeallocateSample(const void* sample_buffer) {
   DCHECK(message_loop_->BelongsToCurrentThread());
-  DCHECK(decoding_buffers_.find(sample_buffer) != decoding_buffers_.end());
-  decoding_buffers_.erase(decoding_buffers_.find(sample_buffer));
+  DecodingBuffers::iterator iter = decoding_buffers_.find(sample_buffer);
+  DCHECK(iter != decoding_buffers_.end());
+  if (iter == decoding_buffers_.end()) {
+    LOG(ERROR) << "SbPlayerPipeline::OnDeallocateSample encounters unknown "
+               << "sample_buffer " << sample_buffer;
+    return;
+  }
+  --iter->second.second;
+  if (iter->second.second == 0) {
+    decoding_buffers_.erase(iter);
+  }
 }
 
 // static
@@ -791,7 +856,6 @@
                                       SbPlayerState state,
                                       int ticket) {
   SbPlayerPipeline* pipeline = reinterpret_cast<SbPlayerPipeline*>(context);
-  DCHECK_EQ(pipeline->player_, player);
   pipeline->message_loop_->PostTask(
       FROM_HERE,
       base::Bind(&SbPlayerPipeline::OnPlayerStatus, pipeline, state, ticket));
@@ -813,10 +877,11 @@
 #endif  // SB_HAS(PLAYER)
 
 scoped_refptr<Pipeline> Pipeline::Create(
+    PipelineWindow window,
     const scoped_refptr<base::MessageLoopProxy>& message_loop,
     MediaLog* media_log) {
 #if SB_HAS(PLAYER)
-  return new SbPlayerPipeline(message_loop, media_log);
+  return new SbPlayerPipeline(window, message_loop, media_log);
 #else
   return NULL;
 #endif
diff --git a/src/media/base/shell_video_frame_provider.cc b/src/media/base/shell_video_frame_provider.cc
index 589f886..7a9ddb2 100644
--- a/src/media/base/shell_video_frame_provider.cc
+++ b/src/media/base/shell_video_frame_provider.cc
@@ -28,21 +28,22 @@
 #endif  // !defined(__LB_SHELL__FOR_RELEASE__)
 }
 
-void ShellVideoFrameProvider::RegisterMediaTimeCB(
-    const MediaTimeCB& media_time_cb) {
-  DCHECK(!media_time_cb.is_null());
+void ShellVideoFrameProvider::RegisterMediaTimeAndSeekingStateCB(
+    const MediaTimeAndSeekingStateCB& media_time_and_seeking_state_cb) {
+  DCHECK(!media_time_and_seeking_state_cb.is_null());
   base::AutoLock auto_lock(frames_lock_);
-  media_time_cb_ = media_time_cb;
+  media_time_and_seeking_state_cb_ = media_time_and_seeking_state_cb;
 }
 
-void ShellVideoFrameProvider::UnregisterMediaTimeCB(
-    const MediaTimeCB& media_time_cb) {
+void ShellVideoFrameProvider::UnregisterMediaTimeAndSeekingStateCB(
+    const MediaTimeAndSeekingStateCB& media_time_and_seeking_state_cb) {
   base::AutoLock auto_lock(frames_lock_);
   // It is possible that the register of a new callback happens earlier than the
   // unregister of the previous callback.  Always ensure that the callback
   // passed in is the current one before resetting.
-  if (media_time_cb_.Equals(media_time_cb)) {
-    media_time_cb_.Reset();
+  if (media_time_and_seeking_state_cb_.Equals(
+          media_time_and_seeking_state_cb)) {
+    media_time_and_seeking_state_cb_.Reset();
   }
 }
 
@@ -57,7 +58,9 @@
 
   base::AutoLock auto_lock(frames_lock_);
 
-  base::TimeDelta media_time = GetMediaTime_Locked();
+  base::TimeDelta media_time;
+  bool is_seeking;
+  GetMediaTimeAndSeekingState_Locked(&media_time, &is_seeking);
   while (!frames_.empty()) {
     int64_t frame_time = frames_[0]->GetTimestamp().InMicroseconds();
     if (frame_time >= media_time.InMicroseconds())
@@ -66,7 +69,7 @@
         frame_time + kEpsilonInMicroseconds >= media_time.InMicroseconds())
       break;
 
-    if (current_frame_ != frames_[0]) {
+    if (current_frame_ != frames_[0] && !is_seeking) {
       ++dropped_frames_;
 
 #if !defined(__LB_SHELL__FOR_RELEASE__)
@@ -117,9 +120,18 @@
   return frames_.size();
 }
 
-base::TimeDelta ShellVideoFrameProvider::GetMediaTime_Locked() const {
+void ShellVideoFrameProvider::GetMediaTimeAndSeekingState_Locked(
+    base::TimeDelta* media_time,
+    bool* is_seeking) const {
+  DCHECK(media_time);
+  DCHECK(is_seeking);
   frames_lock_.AssertAcquired();
-  return media_time_cb_.is_null() ? base::TimeDelta() : media_time_cb_.Run();
+  if (media_time_and_seeking_state_cb_.is_null()) {
+    *media_time = base::TimeDelta();
+    *is_seeking = false;
+    return;
+  }
+  media_time_and_seeking_state_cb_.Run(media_time, is_seeking);
 }
 
 bool ShellVideoFrameProvider::QueryAndResetHasConsumedFrames() {
diff --git a/src/media/base/shell_video_frame_provider.h b/src/media/base/shell_video_frame_provider.h
index 47ab8da..7344e78 100644
--- a/src/media/base/shell_video_frame_provider.h
+++ b/src/media/base/shell_video_frame_provider.h
@@ -38,15 +38,21 @@
  public:
   explicit ShellVideoFrameProvider(scoped_refptr<VideoFrame> punch_out = NULL);
 
-  typedef base::Callback<base::TimeDelta()> MediaTimeCB;
+  // The calling back returns the current media time and a bool which is set to
+  // true when a seek is in progress.
+  typedef base::Callback<void(base::TimeDelta*, bool*)>
+      MediaTimeAndSeekingStateCB;
   // This class uses the media time to decide which frame is current.  It
   // retrieves the media time from the registered media_time_cb.  There can only
   // be one registered media_time_cb at a certain time, a call to
-  // RegisterMediaTimeCB() will overwrite the previously registered callback.
-  void RegisterMediaTimeCB(const MediaTimeCB& media_time_cb);
+  // RegisterMediaTimeAndSeekingStateCB() will overwrite the previously
+  // registered callback.
+  void RegisterMediaTimeAndSeekingStateCB(
+      const MediaTimeAndSeekingStateCB& media_time_and_seeking_state_cb);
   // This function unregisters the media time callback if it hasn't been
   // overwritten by another callback.
-  void UnregisterMediaTimeCB(const MediaTimeCB& media_time_cb);
+  void UnregisterMediaTimeAndSeekingStateCB(
+      const MediaTimeAndSeekingStateCB& media_time_and_seeking_state_cb);
 
   // Returns the current frame to be displayed if there is one. Otherwise it
   // returns NULL.
@@ -68,12 +74,13 @@
   int ResetAndReturnDroppedFrames();
 
  private:
-  base::TimeDelta GetMediaTime_Locked() const;
+  void GetMediaTimeAndSeekingState_Locked(base::TimeDelta* media_time,
+                                          bool* is_seeking) const;
 
   scoped_refptr<VideoFrame> punch_out_;
 
   mutable base::Lock frames_lock_;
-  MediaTimeCB media_time_cb_;
+  MediaTimeAndSeekingStateCB media_time_and_seeking_state_cb_;
   std::vector<scoped_refptr<VideoFrame> > frames_;
   scoped_refptr<VideoFrame> current_frame_;
   bool has_consumed_frames_;
diff --git a/src/media/player/web_media_player.h b/src/media/player/web_media_player.h
index 98a125f..77a9c0c 100644
--- a/src/media/player/web_media_player.h
+++ b/src/media/player/web_media_player.h
@@ -10,6 +10,7 @@
 
 #include <string>
 
+#include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
@@ -20,6 +21,7 @@
 #include "media/base/shell_video_frame_provider.h"
 #include "media/base/video_frame.h"
 #include "media/player/buffered_data_source.h"
+#include "ui/gfx/rect.h"
 #include "ui/gfx/size.h"
 
 // Disable `unreferenced formal parameter` as we have many stub functions in
@@ -30,6 +32,8 @@
 
 class WebMediaPlayer {
  public:
+  typedef base::Callback<void(const gfx::Rect&)> SetBoundsCB;
+
   enum NetworkState {
     kNetworkStateEmpty,
     kNetworkStateIdle,
@@ -184,6 +188,8 @@
     return kMediaKeyExceptionKeySystemNotSupported;
   }
 
+  virtual SetBoundsCB GetSetBoundsCB() { return SetBoundsCB(); }
+
   // Instruct WebMediaPlayer to enter/exit fullscreen.
   virtual void EnterFullscreen() {}
   virtual void ExitFullscreen() {}
diff --git a/src/media/player/web_media_player_impl.cc b/src/media/player/web_media_player_impl.cc
index 34bd3ac..42a2f87 100644
--- a/src/media/player/web_media_player_impl.cc
+++ b/src/media/player/web_media_player_impl.cc
@@ -18,13 +18,13 @@
 #include "base/string_number_conversions.h"
 #include "base/synchronization/waitable_event.h"
 #include "media/audio/shell_audio_sink.h"
-#include "media/filters/shell_audio_renderer.h"
 #include "media/base/bind_to_loop.h"
 #include "media/base/filter_collection.h"
 #include "media/base/limits.h"
 #include "media/base/media_log.h"
 #include "media/base/video_frame.h"
 #include "media/filters/chunk_demuxer.h"
+#include "media/filters/shell_audio_renderer.h"
 #include "media/filters/shell_demuxer.h"
 #include "media/filters/video_renderer_base.h"
 #include "media/player/web_media_player_proxy.h"
@@ -114,6 +114,7 @@
 }
 
 WebMediaPlayerImpl::WebMediaPlayerImpl(
+    PipelineWindow window,
     WebMediaPlayerClient* client,
     WebMediaPlayerDelegate* delegate,
     const scoped_refptr<ShellVideoFrameProvider>& video_frame_provider,
@@ -141,7 +142,7 @@
 
   scoped_refptr<base::MessageLoopProxy> pipeline_message_loop =
       message_loop_factory_->GetMessageLoop(MessageLoopFactory::kPipeline);
-  pipeline_ = Pipeline::Create(pipeline_message_loop, media_log_);
+  pipeline_ = Pipeline::Create(window, pipeline_message_loop, media_log_);
 
   // Also we want to be notified of |main_loop_| destruction.
   main_loop_->AddDestructionObserver(this);
@@ -173,8 +174,11 @@
 #endif  // defined(COBALT_USE_PUNCHOUT)
 
   if (video_frame_provider_) {
-    media_time_cb_ = base::Bind(&Pipeline::GetMediaTime, pipeline_);
-    video_frame_provider_->RegisterMediaTimeCB(media_time_cb_);
+    media_time_and_seeking_state_cb_ =
+        base::Bind(&WebMediaPlayerImpl::GetMediaTimeAndSeekingState,
+                   base::Unretained(this));
+    video_frame_provider_->RegisterMediaTimeAndSeekingStateCB(
+        media_time_and_seeking_state_cb_);
   }
   if (delegate_) {
     delegate_->RegisterPlayer(this);
@@ -189,9 +193,10 @@
   }
 
   if (video_frame_provider_) {
-    DCHECK(!media_time_cb_.is_null());
-    video_frame_provider_->UnregisterMediaTimeCB(media_time_cb_);
-    media_time_cb_.Reset();
+    DCHECK(!media_time_and_seeking_state_cb_.is_null());
+    video_frame_provider_->UnregisterMediaTimeAndSeekingStateCB(
+        media_time_and_seeking_state_cb_);
+    media_time_and_seeking_state_cb_.Reset();
   }
 
 #if defined(__LB_ANDROID__)
@@ -842,6 +847,12 @@
   return e;
 }
 
+WebMediaPlayerImpl::SetBoundsCB WebMediaPlayerImpl::GetSetBoundsCB() {
+  // |pipeline_| is always valid during WebMediaPlayerImpl's life time.  It is
+  // also reference counted so it lives after WebMediaPlayerImpl is destroyed.
+  return pipeline_->GetSetBoundsCB();
+}
+
 WebMediaPlayer::MediaKeyException WebMediaPlayerImpl::CancelKeyRequestInternal(
     const std::string& key_system,
     const std::string& session_id) {
@@ -1164,6 +1175,15 @@
   }
 }
 
+void WebMediaPlayerImpl::GetMediaTimeAndSeekingState(
+    base::TimeDelta* media_time,
+    bool* is_seeking) const {
+  DCHECK(media_time);
+  DCHECK(is_seeking);
+  *media_time = pipeline_->GetMediaTime();
+  *is_seeking = state_.seeking;
+}
+
 WebMediaPlayerClient* WebMediaPlayerImpl::GetClient() {
   DCHECK_EQ(main_loop_, MessageLoop::current());
   DCHECK(client_);
diff --git a/src/media/player/web_media_player_impl.h b/src/media/player/web_media_player_impl.h
index 7ef4c56..fcc1030 100644
--- a/src/media/player/web_media_player_impl.h
+++ b/src/media/player/web_media_player_impl.h
@@ -69,11 +69,12 @@
 #include "ui/gfx/size.h"
 
 #if defined(OS_STARBOARD)
+
 #if SB_HAS(PLAYER)
-#define COBALT_USE_SBPLAYER_PIPELINE
 #define COBALT_USE_PUNCHOUT
 #define COBALT_SKIP_SEEK_REQUEST_NEAR_END
 #endif  // SB_HAS(PLAYER)
+
 #endif  // defined(OS_STARBOARD)
 
 namespace media {
@@ -106,6 +107,7 @@
   // |audio_renderer_sink| arguments should be the same object.
 
   WebMediaPlayerImpl(
+      PipelineWindow window,
       WebMediaPlayerClient* client,
       WebMediaPlayerDelegate* delegate,
       const scoped_refptr<ShellVideoFrameProvider>& video_frame_provider,
@@ -203,6 +205,8 @@
   MediaKeyException CancelKeyRequest(const std::string& key_system,
                                      const std::string& session_id) OVERRIDE;
 
+  SetBoundsCB GetSetBoundsCB() OVERRIDE;
+
   // As we are closing the tab or even the browser, |main_loop_| is destroyed
   // even before this object gets destructed, so we need to know when
   // |main_loop_| is being destroyed and we can stop posting repaint task
@@ -247,6 +251,9 @@
   // Destroy resources held.
   void Destroy();
 
+  void GetMediaTimeAndSeekingState(base::TimeDelta* media_time,
+                                   bool* is_seeking) const;
+
   // Getter method to |client_|.
   WebMediaPlayerClient* GetClient();
 
@@ -365,7 +372,8 @@
   // unimportant.
   bool suppress_destruction_errors_;
 
-  base::Callback<base::TimeDelta()> media_time_cb_;
+  base::Callback<void(base::TimeDelta*, bool*)>
+      media_time_and_seeking_state_cb_;
 
   DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl);
 };
diff --git a/src/starboard/client_porting/poem/abs_tests.cc b/src/starboard/client_porting/poem/abs_tests.cc
index cfcc8c1..c4f2289 100644
--- a/src/starboard/client_porting/poem/abs_tests.cc
+++ b/src/starboard/client_porting/poem/abs_tests.cc
@@ -16,10 +16,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 
-#ifndef POEM_FULL_EMULATION
-#define POEM_FULL_EMULATION (1)
 #include "starboard/client_porting/poem/stdlib_poem.h"
-#endif
 
 namespace starboard {
 namespace nplb {
diff --git a/src/starboard/client_porting/poem/eztime_poem.h b/src/starboard/client_porting/poem/eztime_poem.h
index 280b0c6..31d301a 100644
--- a/src/starboard/client_porting/poem/eztime_poem.h
+++ b/src/starboard/client_porting/poem/eztime_poem.h
@@ -18,10 +18,12 @@
 #ifndef STARBOARD_CLIENT_PORTING_POEM_EZTIME_POEM_H_
 #define STARBOARD_CLIENT_PORTING_POEM_EZTIME_POEM_H_
 
-// #if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+#if defined(STARBOARD)
 
 #include "starboard/client_porting/eztime/eztime.h"
 
+#if !defined(POEM_NO_EMULATION)
+
 #undef time_t
 #define time_t EzTimeT
 
@@ -39,6 +41,8 @@
 #define timegm(x) EzTimeTImplodeUTC(x)
 #define timelocal(x) EzTimeTImplodeLocal(x)
 
-// #endif // POEM_FULL_EMULATION
+#endif  // POEM_NO_EMULATION
+
+#endif  // STARBOARD
 
 #endif  // STARBOARD_CLIENT_PORTING_POEM_EZTIME_POEM_H_
diff --git a/src/starboard/client_porting/poem/stdio_poem.h b/src/starboard/client_porting/poem/stdio_poem.h
index 761dff1..2500568 100644
--- a/src/starboard/client_porting/poem/stdio_poem.h
+++ b/src/starboard/client_porting/poem/stdio_poem.h
@@ -17,9 +17,12 @@
 #ifndef STARBOARD_CLIENT_PORTING_POEM_STDIO_POEM_H_
 #define STARBOARD_CLIENT_PORTING_POEM_STDIO_POEM_H_
 
-#if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+#if defined(STARBOARD)
+
+#if !defined(POEM_NO_EMULATION)
 
 #include "starboard/string.h"
+#include "starboard/memory.h"
 
 #define wcsncmp(s1, s2, c) SbStringCompareWide(s1, s2, c)
 
@@ -31,7 +34,12 @@
 #define sprintf SbStringFormatUnsafeF
 #define vsscanf SbStringScan
 #define sscanf SbStringScanF
+#define malloc(sz) SbMemoryAllocateUnchecked(sz)
+#define free(a) SbMemoryFree(a)
+#define realloc(m, sz) SbMemoryReallocateUnchecked(m, sz)
 
-#endif  // POEM_FULL_EMULATION
+#endif  // POEM_NO_EMULATION
+
+#endif  // STARBOARD
 
 #endif  // STARBOARD_CLIENT_PORTING_POEM_STDIO_POEM_H_
diff --git a/src/starboard/client_porting/poem/stdlib_poem.h b/src/starboard/client_porting/poem/stdlib_poem.h
index 54c028b..ac0a4ae 100644
--- a/src/starboard/client_porting/poem/stdlib_poem.h
+++ b/src/starboard/client_porting/poem/stdlib_poem.h
@@ -17,15 +17,25 @@
 #ifndef STARBOARD_CLIENT_PORTING_POEM_STDLIB_POEM_H_
 #define STARBOARD_CLIENT_PORTING_POEM_STDLIB_POEM_H_
 
+#if defined(STARBOARD)
+
 #include "starboard/configuration.h"
 
-SB_C_INLINE int PoemAbs(int x) {
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static SB_C_INLINE int PoemAbs(int x) {
   if (x < 0)
     return -x;
   return x;
 }
 
-#if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#if !defined(POEM_NO_EMULATION)
 
 #include "starboard/string.h"
 #include "starboard/system.h"
@@ -43,6 +53,8 @@
 
 #define abs(x) PoemAbs(x)
 
-#endif  // POEM_FULL_EMULATION
+#endif  // POEM_NO_EMULATION
+
+#endif  // STARBOARD
 
 #endif  // STARBOARD_CLIENT_PORTING_POEM_STDLIB_POEM_H_
diff --git a/src/starboard/client_porting/poem/string_poem.h b/src/starboard/client_porting/poem/string_poem.h
index 1d9ee57..97ef46d 100644
--- a/src/starboard/client_porting/poem/string_poem.h
+++ b/src/starboard/client_porting/poem/string_poem.h
@@ -17,9 +17,17 @@
 #ifndef STARBOARD_CLIENT_PORTING_POEM_STRING_POEM_H_
 #define STARBOARD_CLIENT_PORTING_POEM_STRING_POEM_H_
 
+#if defined(STARBOARD)
+
 #include "starboard/string.h"
+#include "starboard/memory.h"
 
 #ifdef __cplusplus
+
+// declaring the following 4 functions static inline is not necessary in C++
+// see:
+// http://stackoverflow.com/questions/10847176/should-i-define-static-inline-methods-in-header-file
+
 // Finds the last occurrence of |character| in |str|, returning a pointer to
 // the found character in the given string, or NULL if not found.
 // Meant to be a drop-in replacement for strchr, C++ signature
@@ -59,7 +67,7 @@
 // Finds the first occurrence of |character| in |str|, returning a pointer to
 // the found character in the given string, or NULL if not found.
 // Meant to be a drop-in replacement for strchr
-SB_C_INLINE char* PoemFindCharacter(const char* str, int character) {
+static SB_C_INLINE char* PoemFindCharacter(const char* str, int character) {
   // C-style cast used for C code
   return (char*)(SbStringFindCharacter(str, character));
 }
@@ -67,18 +75,22 @@
 // Finds the last occurrence of |character| in |str|, returning a pointer to
 // the found character in the given string, or NULL if not found.
 // Meant to be a drop-in replacement for strchr
-SB_C_INLINE char* PoemFindLastCharacter(const char* str, int character) {
+static SB_C_INLINE char* PoemFindLastCharacter(const char* str, int character) {
   // C-style cast used for C code
   return (char*)(SbStringFindLastCharacter(str, character));
 }
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 // Concatenates |source| onto the end of |out_destination|, presuming it has
 // |destination_size| total characters of storage available. Returns
 // |out_destination|.  This method is a drop-in replacement for strncat
-SB_C_INLINE char* PoemConcat(char* out_destination,
-                             const char* source,
-                             int destination_size) {
+static SB_C_INLINE char* PoemConcat(char* out_destination,
+                                    const char* source,
+                                    int destination_size) {
   SbStringConcat(out_destination, source, destination_size);
   return out_destination;
 }
@@ -91,7 +103,11 @@
   return PoemConcat(out_destination, source, INT_MAX);
 }
 
-#if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#if !defined(POEM_NO_EMULATION)
 
 #define strlen(s) SbStringGetLength(s)
 #define strcpy(o, s) SbStringCopyUnsafe(o, s)
@@ -105,6 +121,11 @@
 #define strncmp(s1, s2, c) SbStringCompare(s1, s2, c)
 #define strcmp(s1, s2) SbStringCompareAll(s1, s2)
 
+#define memset(s, c, n) SbMemorySet(s, c, n)
+#define memcpy(d, s, c) SbMemoryCopy(d, s, c)
+#define memcmp(s1, s2, n) SbMemoryCompare(s1, s2, n)
+#define memmove(d, s, n) SbMemoryMove(d, s, n)
+
 // number conversion functions
 #define strtol(s, o, b) SbStringParseSignedInteger(s, o, b)
 #define atoi(v) SbStringAToI(v)
@@ -114,6 +135,8 @@
 #define strtoull(s, o, b) SbStringParseUInt64(s, o, b)
 #define strtod(s, o) SbStringParseDouble(s, o)
 
-#endif  // POEM_FULL_EMULATION
+#endif  // POEM_NO_EMULATION
+
+#endif  // STARBOARD
 
 #endif  // STARBOARD_CLIENT_PORTING_POEM_STRING_POEM_H_
diff --git a/src/starboard/client_porting/poem/strings_poem.h b/src/starboard/client_porting/poem/strings_poem.h
index 9c77d36..8f98a06 100644
--- a/src/starboard/client_porting/poem/strings_poem.h
+++ b/src/starboard/client_porting/poem/strings_poem.h
@@ -17,13 +17,17 @@
 #ifndef STARBOARD_CLIENT_PORTING_POEM_STRINGS_POEM_H_
 #define STARBOARD_CLIENT_PORTING_POEM_STRINGS_POEM_H_
 
-#if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+#if defined(STARBOARD)
+
+#if !defined(POEM_NO_EMULATION)
 
 #include "starboard/string.h"
 
 #define strcasecmp(s1, s2) SbStringCompareNoCase(s1, s2)
 #define strncasecmp(s1, s2) SbStringCompareNoCaseN(s1, s2)
 
-#endif  // POEM_FULL_EMULATION
+#endif  // POEM_NO_EMULATION
+
+#endif  // STARBOARD
 
 #endif  // STARBOARD_CLIENT_PORTING_POEM_STRINGS_POEM_H_
diff --git a/src/starboard/client_porting/poem/wchar_poem.h b/src/starboard/client_porting/poem/wchar_poem.h
index c72ec8d..68af73c 100644
--- a/src/starboard/client_porting/poem/wchar_poem.h
+++ b/src/starboard/client_porting/poem/wchar_poem.h
@@ -17,13 +17,17 @@
 #ifndef STARBOARD_CLIENT_PORTING_POEM_WCHAR_POEM_H_
 #define STARBOARD_CLIENT_PORTING_POEM_WCHAR_POEM_H_
 
-#if defined(POEM_FULL_EMULATION) && (POEM_FULL_EMULATION)
+#if defined(STARBOARD)
+
+#if !defined(POEM_NO_EMULATION)
 
 #include "starboard/string.h"
 
 #define vswprintf SbStringFormatWide
 #define wcsncmp(s1, s2, c) SbStringCompareWide(s1, s2, c)
 
-#endif  // POEM_FULL_EMULATION
+#endif  // POEM_NO_EMULATION
+
+#endif  // STARBOARD
 
 #endif  // STARBOARD_CLIENT_PORTING_POEM_WCHAR_POEM_H_
diff --git a/src/starboard/linux/x64directfb/starboard_platform.gyp b/src/starboard/linux/x64directfb/starboard_platform.gyp
index 9d95ec2..25c0476 100644
--- a/src/starboard/linux/x64directfb/starboard_platform.gyp
+++ b/src/starboard/linux/x64directfb/starboard_platform.gyp
@@ -276,6 +276,7 @@
         '<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
         '<(DEPTH)/starboard/shared/starboard/player/player_seek.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/player_set_bounds.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_set_pause.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_set_volume.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_worker.cc',
diff --git a/src/starboard/linux/x64x11/starboard_platform.gyp b/src/starboard/linux/x64x11/starboard_platform.gyp
index 932e00e..65712a4 100644
--- a/src/starboard/linux/x64x11/starboard_platform.gyp
+++ b/src/starboard/linux/x64x11/starboard_platform.gyp
@@ -237,6 +237,7 @@
         '<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
         '<(DEPTH)/starboard/shared/starboard/player/player_seek.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/player_set_bounds.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_set_pause.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_set_volume.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_worker.cc',
diff --git a/src/starboard/nplb/memory_map_test.cc b/src/starboard/nplb/memory_map_test.cc
index 53ccd50..52cdc1c 100644
--- a/src/starboard/nplb/memory_map_test.cc
+++ b/src/starboard/nplb/memory_map_test.cc
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <algorithm>
+
 #include "starboard/memory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -57,10 +59,21 @@
     void* memory = SbMemoryMap(bytes_mapped, kSbMemoryMapProtectWrite, "test");
     ASSERT_NE(kFailed, memory);
 
-    // Force page commit.
+    // If this is the last iteration of the loop, then force a page commit for
+    // every single page.  For any other iteration, force a page commit for
+    // roughly 1000 of the pages.
+    bool last_iteration =
+        !(total_bytes_mapped + bytes_mapped < SbSystemGetTotalCPUMemory() * 4);
     uint8_t* first_page = static_cast<uint8_t*>(memory);
+    const size_t page_increment_factor =
+        (last_iteration)
+            ? size_t(1u)
+            : std::max(static_cast<size_t>(bytes_mapped /
+                                           (1000 * SB_MEMORY_PAGE_SIZE)),
+                       size_t(1u));
+
     for (uint8_t* page = first_page; page < first_page + bytes_mapped;
-         page += SB_MEMORY_PAGE_SIZE) {
+         page += SB_MEMORY_PAGE_SIZE * page_increment_factor) {
       *page = 0x55;
     }
 
diff --git a/src/starboard/nplb/player_create_test.cc b/src/starboard/nplb/player_create_test.cc
index a3ead76..d81c51c 100644
--- a/src/starboard/nplb/player_create_test.cc
+++ b/src/starboard/nplb/player_create_test.cc
@@ -13,6 +13,8 @@
 // limitations under the License.

 

 #include "starboard/player.h"

+

+#include "starboard/window.h"

 #include "testing/gtest/include/gtest/gtest.h"

 

 #if SB_HAS(PLAYER)

@@ -21,6 +23,12 @@
 namespace nplb {

 

 TEST(SbPlayerTest, SunnyDay) {

+  SbWindowOptions window_options;

+  SbWindowSetDefaultOptions(&window_options);

+

+  SbWindow window = SbWindowCreate(&window_options);

+  EXPECT_TRUE(SbWindowIsValid(window));

+

   SbMediaAudioHeader audio_header;

 

   audio_header.format_tag = 0xff;

@@ -33,11 +41,13 @@
                                           audio_header.number_of_channels *

                                           audio_header.bits_per_sample / 8;

 

-  SbPlayer player = SbPlayerCreate(

-      kSbMediaVideoCodecH264, kSbMediaAudioCodecAac, SB_PLAYER_NO_DURATION,

-      kSbDrmSystemInvalid, &audio_header, NULL, NULL, NULL, NULL);

+  SbPlayer player =

+      SbPlayerCreate(window, kSbMediaVideoCodecH264, kSbMediaAudioCodecAac,

+                     SB_PLAYER_NO_DURATION, kSbDrmSystemInvalid, &audio_header,

+                     NULL, NULL, NULL, NULL);

   EXPECT_TRUE(SbPlayerIsValid(player));

   SbPlayerDestroy(player);

+  SbWindowDestroy(window);

 }

 

 }  // namespace nplb

diff --git a/src/starboard/nplb/socket_is_connected_and_idle_test.cc b/src/starboard/nplb/socket_is_connected_and_idle_test.cc
index ffe83f5..74a082c 100644
--- a/src/starboard/nplb/socket_is_connected_and_idle_test.cc
+++ b/src/starboard/nplb/socket_is_connected_and_idle_test.cc
@@ -22,6 +22,16 @@
 namespace nplb {
 namespace {
 
+bool IsNonIdleWithin(SbSocket socket, SbTimeMonotonic timeout) {
+  SbTimeMonotonic deadline = SbTimeGetMonotonicNow() + timeout;
+  while (SbTimeGetMonotonicNow() < deadline) {
+    if (!SbSocketIsConnectedAndIdle(socket)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 TEST(SbSocketIsConnectedAndIdleTest, RainyDayInvalidSocket) {
   EXPECT_FALSE(SbSocketIsConnectedAndIdle(kSbSocketInvalid));
 }
@@ -39,15 +49,14 @@
 
   char buf[512] = {0};
   SbSocketSendTo(trio.server_socket, buf, sizeof(buf), NULL);
-  // Because I haven't called ReceiveFrom yet, this should stay false. The wait
-  // before the checking is for the delay on some platforms.
-  SbThreadSleep(kSocketTimeout);
-  EXPECT_FALSE(SbSocketIsConnectedAndIdle(trio.client_socket));
+  // It may take some time after this call for trio.client_socket to show up as
+  // having new data available, even though it is a loopback connection, so we
+  // give it a grace period.
+  EXPECT_TRUE(IsNonIdleWithin(trio.client_socket, kSocketTimeout));
 
   // Should be the same in the other direction.
   SbSocketSendTo(trio.client_socket, buf, sizeof(buf), NULL);
-  SbThreadSleep(kSocketTimeout);
-  EXPECT_FALSE(SbSocketIsConnectedAndIdle(trio.server_socket));
+  EXPECT_TRUE(IsNonIdleWithin(trio.server_socket, kSocketTimeout));
 
   EXPECT_TRUE(SbSocketDestroy(trio.server_socket));
   EXPECT_TRUE(SbSocketDestroy(trio.client_socket));
@@ -60,9 +69,7 @@
     return;
   }
 
-  SbThreadSleep(kSocketTimeout);
-  EXPECT_FALSE(SbSocketIsConnectedAndIdle(socket));
-
+  EXPECT_TRUE(IsNonIdleWithin(socket, kSocketTimeout));
   EXPECT_TRUE(SbSocketDestroy(socket));
 }
 
diff --git a/src/starboard/nplb/socket_waiter_wake_up_test.cc b/src/starboard/nplb/socket_waiter_wake_up_test.cc
index 3ab0f6b..4ae3a42 100644
--- a/src/starboard/nplb/socket_waiter_wake_up_test.cc
+++ b/src/starboard/nplb/socket_waiter_wake_up_test.cc
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "starboard/nplb/socket_helpers.h"
+#include "starboard/nplb/thread_helpers.h"
 #include "starboard/socket_waiter.h"
 #include "starboard/thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -24,6 +25,11 @@
 const int kMultiple = 5;
 const int kTrials = 8;
 
+struct WakeUpContext {
+  SbSocketWaiter waiter;
+  Semaphore semaphore;
+};
+
 void* WakeUpEntryPoint(void* context) {
   SbSocketWaiter waiter = reinterpret_cast<SbSocketWaiter>(context);
   SbSocketWaiterWakeUp(waiter);
@@ -31,7 +37,9 @@
 }
 
 void* WakeUpSleepEntryPoint(void* context) {
-  SbSocketWaiter waiter = reinterpret_cast<SbSocketWaiter>(context);
+  WakeUpContext* wake_up_context = reinterpret_cast<WakeUpContext*>(context);
+  SbSocketWaiter waiter = wake_up_context->waiter;
+  wake_up_context->semaphore.Take();
   SbThreadSleep(kSocketTimeout);
   SbSocketWaiterWakeUp(waiter);
   return NULL;
@@ -113,9 +121,16 @@
   for (int i = 0; i < kTrials; ++i) {
     SbSocketWaiter waiter = SbSocketWaiterCreate();
     EXPECT_TRUE(SbSocketWaiterIsValid(waiter));
+    WakeUpContext context;
+    context.waiter = waiter;
 
-    SbThread thread = Spawn(waiter, &WakeUpSleepEntryPoint);
-    WaitShouldBlockBetween(waiter, kSocketTimeout, kSocketTimeout * 2);
+    SbThread thread = Spawn(&context, &WakeUpSleepEntryPoint);
+    SbTimeMonotonic start = SbTimeGetMonotonicNow();
+    context.semaphore.Put();
+    TimedWait(waiter);
+    SbTimeMonotonic duration = SbTimeGetMonotonicNow() - start;
+    EXPECT_GT(kSocketTimeout * 2, duration);
+    EXPECT_LE(kSocketTimeout, duration);
     Join(thread);
 
     EXPECT_TRUE(SbSocketWaiterDestroy(waiter));
diff --git a/src/starboard/player.h b/src/starboard/player.h
index f340312..c897cc7 100644
--- a/src/starboard/player.h
+++ b/src/starboard/player.h
@@ -25,6 +25,7 @@
 #include "starboard/export.h"
 #include "starboard/media.h"
 #include "starboard/types.h"
+#include "starboard/window.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -159,12 +160,15 @@
 
 // --- Functions -------------------------------------------------------------
 
-// Creates a player for the specified |video_codec| and |audio_codec|, acquiring
-// all resources needed to operate it, and returning an opaque handle to it. If
-// |video_codec| is kSbMediaVideoCodecNone, the player is an audio-only
-// player. Otherwise, the player is an audio/video decoder. |audio_codec| should
-// never be kSbMediaAudioCodecNone. The expectation is that a new player will be
-// created and destroyed for every playback.
+// Creates a player that will be displayed on |window| for the specified
+// |video_codec| and |audio_codec|, acquiring all resources needed to operate
+// it, and returning an opaque handle to it. |window| can be kSbWindowInvalid
+// for platforms where video will be only displayed on a particular window
+// which the underlying implementation already has access to. If |video_codec|
+// is kSbMediaVideoCodecNone, the player is an audio-only player. Otherwise, the
+// player is an audio/video decoder. |audio_codec| should never be
+// kSbMediaAudioCodecNone. The expectation is that a new player will be created
+// and destroyed for every playback.
 //
 // |duration_pts| is the expected media duration in 90KHz ticks (PTS). It may be
 // set to SB_PLAYER_NO_DURATION for live streams.
@@ -202,7 +206,8 @@
 // simultaneously, then calls made to this function that attempt to exceed that
 // limit will return kSbPlayerInvalid.
 SB_EXPORT SbPlayer
-SbPlayerCreate(SbMediaVideoCodec video_codec,
+SbPlayerCreate(SbWindow window,
+               SbMediaVideoCodec video_codec,
                SbMediaAudioCodec audio_codec,
                SbMediaTime duration_pts,
                SbDrmSystem drm_system,
@@ -278,7 +283,9 @@
 #if SB_IS(PLAYER_PUNCHED_OUT)
 // Sets the player bounds to the given graphics plane coordinates. Will not take
 // effect until the next graphics frame buffer swap. The default bounds for a
-// player are the full screen.
+// player are the full screen. This function should be expected to be called up
+// to once per frame, so implementors should take care to avoid related
+// performance concerns with such frequent calls.
 SB_EXPORT void SbPlayerSetBounds(SbPlayer player,
                                  int x,
                                  int y,
diff --git a/src/starboard/raspi/1/gyp_configuration.gypi b/src/starboard/raspi/1/gyp_configuration.gypi
index 67a0ee9..12a59f3 100644
--- a/src/starboard/raspi/1/gyp_configuration.gypi
+++ b/src/starboard/raspi/1/gyp_configuration.gypi
@@ -23,6 +23,13 @@
     'gl_type': 'system_gles2',
     'image_cache_size_in_bytes': 32 * 1024 * 1024,
 
+    # VideoCore's tiled renderer will do a render for every tile of a render
+    # target even if only part of that target was rendered to.  Since the
+    # scratch surface cache is designed to choose large offscreen surfaces so
+    # that they can be maximally reused, it is not a very good fit for a tiled
+    # renderer.
+    'scratch_surface_cache_size_in_bytes' : 0,
+
     # This should have a default value in cobalt/base.gypi. See the comment
     # there for acceptable values for this variable.
     'javascript_engine': 'javascriptcore',
diff --git a/src/starboard/raspi/1/starboard_platform.gyp b/src/starboard/raspi/1/starboard_platform.gyp
index d1b864c..d5b6b23 100644
--- a/src/starboard/raspi/1/starboard_platform.gyp
+++ b/src/starboard/raspi/1/starboard_platform.gyp
@@ -244,6 +244,7 @@
         '<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
         '<(DEPTH)/starboard/shared/starboard/player/player_seek.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/player_set_bounds.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_set_pause.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_set_volume.cc',
         '<(DEPTH)/starboard/shared/starboard/player/player_worker.cc',
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
index be5a4ba..00e98e6 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc
@@ -194,7 +194,13 @@
 // static
 AudioDecoder* AudioDecoder::Create(SbMediaAudioCodec audio_codec,
                                    const SbMediaAudioHeader& audio_header) {
-  return new ffmpeg::AudioDecoder(audio_codec, audio_header);
+  ffmpeg::AudioDecoder* decoder =
+      new ffmpeg::AudioDecoder(audio_codec, audio_header);
+  if (decoder->is_valid()) {
+    return decoder;
+  }
+  delete decoder;
+  return NULL;
 }
 
 }  // namespace player
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h
index dc24f99..eac65a2 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h
+++ b/src/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h
@@ -40,6 +40,8 @@
   void Reset() SB_OVERRIDE;
   int GetSamplesPerSecond() SB_OVERRIDE;
 
+  bool is_valid() const { return codec_context_ != NULL; }
+
  private:
   void InitializeCodec();
   void TeardownCodec();
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
index 5174f70..6c7aec8 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.cc
@@ -293,7 +293,12 @@
 
 // static
 VideoDecoder* VideoDecoder::Create(SbMediaVideoCodec video_codec) {
-  return new ffmpeg::VideoDecoder(video_codec);
+  ffmpeg::VideoDecoder* decoder = new ffmpeg::VideoDecoder(video_codec);
+  if (decoder->is_valid()) {
+    return decoder;
+  }
+  delete decoder;
+  return NULL;
 }
 
 }  // namespace player
diff --git a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.h b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.h
index 1a78aba..6bcd6d3 100644
--- a/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.h
+++ b/src/starboard/shared/ffmpeg/ffmpeg_video_decoder.h
@@ -42,6 +42,8 @@
   void WriteEndOfStream() SB_OVERRIDE;
   void Reset() SB_OVERRIDE;
 
+  bool is_valid() const { return codec_context_ != NULL; }
+
  private:
   enum EventType {
     kInvalid,
diff --git a/src/starboard/shared/starboard/application.cc b/src/starboard/shared/starboard/application.cc
index 1482b1a..b7ca314 100644
--- a/src/starboard/shared/starboard/application.cc
+++ b/src/starboard/shared/starboard/application.cc
@@ -18,6 +18,8 @@
 #include "starboard/condition_variable.h"
 #include "starboard/event.h"
 #include "starboard/log.h"
+#include "starboard/memory.h"
+#include "starboard/string.h"
 
 namespace starboard {
 namespace shared {
@@ -39,11 +41,11 @@
 }
 
 // Dispatches a Start event to the system event handler.
-void DispatchStart(int argc, char** argv) {
+void DispatchStart(int argc, char** argv, const char* link) {
   SbEventStartData start_data;
   start_data.argument_values = argv;
   start_data.argument_count = argc;
-  start_data.link = NULL;
+  start_data.link = link;
   Dispatch(kSbEventTypeStart, &start_data, NULL);
 }
 
@@ -54,7 +56,8 @@
 
 Application* Application::g_instance = NULL;
 
-Application::Application() : error_level_(0), thread_(SbThreadGetCurrent()) {
+Application::Application()
+    : error_level_(0), thread_(SbThreadGetCurrent()), start_link_(NULL) {
   Application* old_instance =
       reinterpret_cast<Application*>(SbAtomicAcquire_CompareAndSwapPtr(
           reinterpret_cast<SbAtomicPtr*>(&g_instance),
@@ -71,11 +74,12 @@
           reinterpret_cast<SbAtomicPtr>(NULL)));
   SB_DCHECK(old_instance);
   SB_DCHECK(old_instance == this);
+  SbMemoryFree(start_link_);
 }
 
 int Application::Run(int argc, char** argv) {
   Initialize();
-  DispatchStart(argc, argv);
+  DispatchStart(argc, argv, start_link_);
 
   for (;;) {
     if (!DispatchAndDelete(GetNextEvent())) {
@@ -105,8 +109,24 @@
   CancelTimedEvent(id);
 }
 
-void Application::HandleFrame(const player::VideoFrame& frame) {
-  AcceptFrame(frame);
+#if SB_HAS(PLAYER) && SB_IS(PLAYER_PUNCHED_OUT)
+void Application::HandleFrame(SbPlayer player,
+                              const player::VideoFrame& frame,
+                              int x,
+                              int y,
+                              int width,
+                              int height) {
+  AcceptFrame(player, frame, x, y, width, height);
+}
+#endif  // SB_HAS(PLAYER) && SB_IS(PLAYER_PUNCHED_OUT)
+
+void Application::SetStartLink(const char* start_link) {
+  SbMemoryFree(start_link_);
+  if (start_link) {
+    start_link_ = SbStringDuplicate(start_link);
+  } else {
+    start_link_ = NULL;
+  }
 }
 
 bool Application::DispatchAndDelete(Application::Event* event) {
diff --git a/src/starboard/shared/starboard/application.h b/src/starboard/shared/starboard/application.h
index 730f8da..2c990a0 100644
--- a/src/starboard/shared/starboard/application.h
+++ b/src/starboard/shared/starboard/application.h
@@ -22,11 +22,13 @@
 #include "starboard/condition_variable.h"
 #include "starboard/event.h"
 #include "starboard/log.h"
+#include "starboard/player.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/player/video_frame_internal.h"
 #include "starboard/thread.h"
 #include "starboard/time.h"
 #include "starboard/types.h"
+#include "starboard/window.h"
 
 namespace starboard {
 namespace shared {
@@ -62,6 +64,13 @@
     delete static_cast<T*>(value);
   }
 
+  // Destructor function that deletes the value as an array of the
+  // parameterized type.
+  template <typename T>
+  static void DeleteArrayDestructor(void* value) {
+    delete[] static_cast<T*>(value);
+  }
+
   // A Starboard event and its destructor. Takes ownership of the event, thus
   // deleting the event and calling the destructor on its data when it is
   // deleted.
@@ -125,10 +134,17 @@
   // external thread.
   void Cancel(SbEventId id);
 
-  // Handles receiving a new video frame from the media system. Only used when
-  // the application needs to composite video frames with punch-out video
-  // manually (should be rare). Will be called from an external thread.
-  void HandleFrame(const player::VideoFrame& frame);
+#if SB_HAS(PLAYER) && SB_IS(PLAYER_PUNCHED_OUT)
+  // Handles receiving a new video frame of |player| from the media system. Only
+  // used when the application needs to composite video frames with punch-out
+  // video manually (should be rare). Will be called from an external thread.
+  void HandleFrame(SbPlayer player,
+                   const player::VideoFrame& frame,
+                   int x,
+                   int y,
+                   int width,
+                   int height);
+#endif  // SB_HAS(PLAYER) && SB_IS(PLAYER_PUNCHED_OUT)
 
  protected:
   // Initializes any systems that need initialization before application
@@ -141,9 +157,16 @@
   // must be run after the application stop event is handled.
   virtual void Teardown() {}
 
+#if SB_HAS(PLAYER) && SB_IS(PLAYER_PUNCHED_OUT)
   // Subclasses may override this method to accept video frames from the media
   // system. Will be called from an external thread.
-  virtual void AcceptFrame(const player::VideoFrame& frame) {}
+  virtual void AcceptFrame(SbPlayer player,
+                           const player::VideoFrame& frame,
+                           int x,
+                           int y,
+                           int width,
+                           int height) {}
+#endif  // SB_HAS(PLAYER) && SB_IS(PLAYER_PUNCHED_OUT)
 
   // Blocks until the next event is available. Subclasses must implement this
   // method to provide events for the platform. Gives ownership to the caller.
@@ -172,7 +195,11 @@
   // kSbTimeMax if there are no queued TimedEvents.
   virtual SbTimeMonotonic GetNextTimedEventTargetTime() = 0;
 
-  bool IsCurrentThread() {
+  // Sets the launch deep link string, if any, which is passed in the start
+  // event that initializes and starts Cobalt.
+  void SetStartLink(const char* start_link);
+
+  bool IsCurrentThread() const {
     return SbThreadIsEqual(thread_, SbThreadGetCurrent());
   }
 
@@ -191,6 +218,10 @@
   // The thread that this application was created on, which is assumed to be the
   // main thread.
   SbThread thread_;
+
+  // The deep link included in the Start event sent to Cobalt. Initially NULL,
+  // derived classes may set it during initialization using |SetStartLink|.
+  char* start_link_;
 };
 
 }  // namespace starboard
diff --git a/src/starboard/shared/starboard/player/audio_renderer_internal.cc b/src/starboard/shared/starboard/player/audio_renderer_internal.cc
index d7fae73..4648f66 100644
--- a/src/starboard/shared/starboard/player/audio_renderer_internal.cc
+++ b/src/starboard/shared/starboard/player/audio_renderer_internal.cc
@@ -63,7 +63,10 @@
   SbMediaTime input_pts = input_buffer.pts();
   std::vector<float> decoded_audio;
   decoder_->Decode(input_buffer, &decoded_audio);
-  SB_DCHECK(!decoded_audio.empty());
+  if (decoded_audio.empty()) {
+    SB_DLOG(ERROR) << "decoded_audio contains no frames.";
+    return;
+  }
 
   ScopedLock lock(mutex_);
   if (seeking_) {
diff --git a/src/starboard/shared/starboard/player/player_create.cc b/src/starboard/shared/starboard/player/player_create.cc
index aaf0539..8489cce 100644
--- a/src/starboard/shared/starboard/player/player_create.cc
+++ b/src/starboard/shared/starboard/player/player_create.cc
@@ -17,7 +17,8 @@
 #include "starboard/log.h"
 #include "starboard/shared/starboard/player/player_internal.h"
 
-SbPlayer SbPlayerCreate(SbMediaVideoCodec video_codec,
+SbPlayer SbPlayerCreate(SbWindow window,
+                        SbMediaVideoCodec video_codec,
                         SbMediaAudioCodec audio_codec,
                         SbMediaTime duration_pts,
                         SbDrmSystem drm_system,
@@ -41,7 +42,7 @@
     return kSbPlayerInvalid;
   }
 
-  return new SbPlayerPrivate(video_codec, audio_codec, duration_pts, drm_system,
-                             audio_header, sample_deallocate_func,
+  return new SbPlayerPrivate(window, video_codec, audio_codec, duration_pts,
+                             drm_system, audio_header, sample_deallocate_func,
                              decoder_status_func, player_status_func, context);
 }
diff --git a/src/starboard/shared/starboard/player/player_internal.cc b/src/starboard/shared/starboard/player/player_internal.cc
index 5090a84..e14da96 100644
--- a/src/starboard/shared/starboard/player/player_internal.cc
+++ b/src/starboard/shared/starboard/player/player_internal.cc
@@ -29,6 +29,7 @@
 }
 
 SbPlayerPrivate::SbPlayerPrivate(
+    SbWindow window,
     SbMediaVideoCodec video_codec,
     SbMediaAudioCodec audio_codec,
     SbMediaTime duration_pts,
@@ -49,6 +50,7 @@
       is_paused_(true),
       volume_(1.0),
       worker_(this,
+              window,
               video_codec,
               audio_codec,
               drm_system,
@@ -90,6 +92,14 @@
   worker_.EnqueueEvent(data);
 }
 
+#if SB_IS(PLAYER_PUNCHED_OUT)
+void SbPlayerPrivate::SetBounds(int x, int y, int width, int height) {
+  PlayerWorker::SetBoundsEventData data = {x, y, width, height};
+  worker_.EnqueueEvent(data);
+  // TODO: Wait until a frame is rendered with the updated bounds.
+}
+#endif
+
 void SbPlayerPrivate::GetInfo(SbPlayerInfo* out_player_info) {
   SB_DCHECK(out_player_info != NULL);
 
diff --git a/src/starboard/shared/starboard/player/player_internal.h b/src/starboard/shared/starboard/player/player_internal.h
index 54cd1f8..58b350d 100644
--- a/src/starboard/shared/starboard/player/player_internal.h
+++ b/src/starboard/shared/starboard/player/player_internal.h
@@ -20,12 +20,14 @@
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/player/player_worker.h"
 #include "starboard/time.h"
+#include "starboard/window.h"
 
 // TODO: Implement DRM support
 struct SbPlayerPrivate
     : starboard::shared::starboard::player::PlayerWorker::Host {
  public:
-  SbPlayerPrivate(SbMediaVideoCodec video_codec,
+  SbPlayerPrivate(SbWindow window,
+                  SbMediaVideoCodec video_codec,
                   SbMediaAudioCodec audio_codec,
                   SbMediaTime duration_pts,
                   SbDrmSystem drm_system,
@@ -43,6 +45,10 @@
                    const SbMediaVideoSampleInfo* video_sample_info,
                    const SbDrmSampleInfo* sample_drm_info);
   void WriteEndOfStream(SbMediaType stream_type);
+#if SB_IS(PLAYER_PUNCHED_OUT)
+  void SetBounds(int x, int y, int width, int height);
+#endif
+
   void GetInfo(SbPlayerInfo* out_player_info);
   void SetPause(bool pause);
   void SetVolume(double volume);
diff --git a/src/starboard/shared/starboard/player/player_set_bounds.cc b/src/starboard/shared/starboard/player/player_set_bounds.cc
new file mode 100644
index 0000000..660a9da
--- /dev/null
+++ b/src/starboard/shared/starboard/player/player_set_bounds.cc
@@ -0,0 +1,30 @@
+// 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/player.h"
+
+#include "starboard/log.h"
+#include "starboard/shared/starboard/player/player_internal.h"
+
+#if SB_IS(PLAYER_PUNCHED_OUT)
+
+void SbPlayerSetBounds(SbPlayer player, int x, int y, int width, int height) {
+  if (!SbPlayerIsValid(player)) {
+    SB_DLOG(WARNING) << "player is invalid.";
+    return;
+  }
+  player->SetBounds(x, y, width, height);
+}
+
+#endif  // SB_IS(PLAYER_PUNCHED_OUT)
diff --git a/src/starboard/shared/starboard/player/player_worker.cc b/src/starboard/shared/starboard/player/player_worker.cc
index cce730e..5bab32b 100644
--- a/src/starboard/shared/starboard/player/player_worker.cc
+++ b/src/starboard/shared/starboard/player/player_worker.cc
@@ -29,6 +29,7 @@
 namespace player {
 
 PlayerWorker::PlayerWorker(Host* host,
+                           SbWindow window,
                            SbMediaVideoCodec video_codec,
                            SbMediaAudioCodec audio_codec,
                            SbDrmSystem drm_system,
@@ -38,6 +39,7 @@
                            SbPlayer player,
                            void* context)
     : host_(host),
+      window_(window),
       video_codec_(video_codec),
       audio_codec_(audio_codec),
       drm_system_(drm_system),
@@ -85,10 +87,12 @@
   delete event;
   bool running = ProcessInitEvent();
 
+  SetBoundsEventData bounds = {0, 0, 0, 0};
+
   while (running) {
     Event* event = queue_.GetTimed(kUpdateInterval);
     if (event == NULL) {
-      running &= ProcessUpdateEvent();
+      running &= ProcessUpdateEvent(bounds);
       continue;
     }
 
@@ -108,6 +112,9 @@
       running &= ProcessWriteEndOfStreamEvent(event->data.write_end_of_stream);
     } else if (event->type == Event::kSetPause) {
       running &= ProcessSetPauseEvent(event->data.set_pause);
+    } else if (event->type == Event::kSetBounds) {
+      bounds = event->data.set_bounds;
+      ProcessUpdateEvent(bounds);
     } else if (event->type == Event::kStop) {
       ProcessStopEvent();
       running = false;
@@ -119,9 +126,19 @@
 }
 
 bool PlayerWorker::ProcessInitEvent() {
-  audio_renderer_ = new AudioRenderer(
-      AudioDecoder::Create(audio_codec_, audio_header_), audio_header_);
-  video_renderer_ = new VideoRenderer(VideoDecoder::Create(video_codec_));
+  AudioDecoder* audio_decoder =
+      AudioDecoder::Create(audio_codec_, audio_header_);
+  VideoDecoder* video_decoder = VideoDecoder::Create(video_codec_);
+
+  if (!audio_decoder || !video_decoder) {
+    delete audio_decoder;
+    delete video_decoder;
+    UpdatePlayerState(kSbPlayerStateError);
+    return false;
+  }
+
+  audio_renderer_ = new AudioRenderer(audio_decoder, audio_header_);
+  video_renderer_ = new VideoRenderer(video_decoder);
   if (audio_renderer_->is_valid() && video_renderer_->is_valid()) {
     UpdatePlayerState(kSbPlayerStateInitialized);
     return true;
@@ -306,7 +323,7 @@
   return true;
 }
 
-bool PlayerWorker::ProcessUpdateEvent() {
+bool PlayerWorker::ProcessUpdateEvent(const SetBoundsEventData& bounds) {
   SB_DCHECK(player_state_ != kSbPlayerStateDestroyed);
 
   if (player_state_ == kSbPlayerStatePrerolling ||
@@ -318,9 +335,9 @@
 
     const VideoFrame& frame =
         video_renderer_->GetCurrentFrame(audio_renderer_->GetCurrentTime());
-    // TODO: Properly paint the video frame.
 #if SB_IS(PLAYER_PUNCHED_OUT)
-    shared::starboard::Application::Get()->HandleFrame(frame);
+    shared::starboard::Application::Get()->HandleFrame(
+        player_, frame, bounds.x, bounds.y, bounds.width, bounds.height);
 #endif  // SB_IS(PLAYER_PUNCHED_OUT)
 
     if (audio_decoder_state_ == kSbPlayerDecoderStateBufferFull &&
@@ -347,7 +364,8 @@
   video_renderer_ = NULL;
 #if SB_IS(PLAYER_PUNCHED_OUT)
   // Clear the video frame as we terminate.
-  shared::starboard::Application::Get()->HandleFrame(VideoFrame());
+  shared::starboard::Application::Get()->HandleFrame(player_, VideoFrame(), 0,
+                                                     0, 0, 0);
 #endif  // SB_IS(PLAYER_PUNCHED_OUT)
   UpdatePlayerState(kSbPlayerStateDestroyed);
 }
diff --git a/src/starboard/shared/starboard/player/player_worker.h b/src/starboard/shared/starboard/player/player_worker.h
index 1dca71d..843806f 100644
--- a/src/starboard/shared/starboard/player/player_worker.h
+++ b/src/starboard/shared/starboard/player/player_worker.h
@@ -24,8 +24,8 @@
 #include "starboard/shared/starboard/player/video_renderer_internal.h"
 #include "starboard/thread.h"
 #include "starboard/time.h"
+#include "starboard/window.h"
 
-// TODO: Implement DRM support
 namespace starboard {
 namespace shared {
 namespace starboard {
@@ -59,6 +59,13 @@
     bool pause;
   };
 
+  struct SetBoundsEventData {
+    int x;
+    int y;
+    int width;
+    int height;
+  };
+
   struct Event {
    public:
     enum Type {
@@ -67,6 +74,7 @@
       kWriteSample,
       kWriteEndOfStream,
       kSetPause,
+      kSetBounds,
       kStop,
     };
 
@@ -75,6 +83,7 @@
       WriteSampleEventData write_sample;
       WriteEndOfStreamEventData write_end_of_stream;
       SetPauseEventData set_pause;
+      SetBoundsEventData set_bounds;
     };
 
     explicit Event(const SeekEventData& seek) : type(kSeek) {
@@ -95,6 +104,10 @@
       data.set_pause = set_pause;
     }
 
+    explicit Event(const SetBoundsEventData& set_bounds) : type(kSetBounds) {
+      data.set_bounds = set_bounds;
+    }
+
     explicit Event(Type type) : type(type) {
       SB_DCHECK(type == kInit || type == kStop);
     }
@@ -106,6 +119,7 @@
   static const SbTime kUpdateInterval = 5 * kSbTimeMillisecond;
 
   PlayerWorker(Host* host,
+               SbWindow window,
                SbMediaVideoCodec video_codec,
                SbMediaAudioCodec audio_codec,
                SbDrmSystem drm_system,
@@ -130,7 +144,7 @@
   bool ProcessWriteSampleEvent(const WriteSampleEventData& data, bool* retry);
   bool ProcessWriteEndOfStreamEvent(const WriteEndOfStreamEventData& data);
   bool ProcessSetPauseEvent(const SetPauseEventData& data);
-  bool ProcessUpdateEvent();
+  bool ProcessUpdateEvent(const SetBoundsEventData& bounds);
   void ProcessStopEvent();
 
   void UpdateDecoderState(SbMediaType type);
@@ -141,6 +155,7 @@
 
   Host* host_;
 
+  SbWindow window_;
   SbMediaVideoCodec video_codec_;
   SbMediaAudioCodec audio_codec_;
   SbDrmSystem drm_system_;
diff --git a/src/starboard/shared/starboard/player/video_renderer_internal.cc b/src/starboard/shared/starboard/player/video_renderer_internal.cc
index 03f7aee..da9ccf8 100644
--- a/src/starboard/shared/starboard/player/video_renderer_internal.cc
+++ b/src/starboard/shared/starboard/player/video_renderer_internal.cc
@@ -62,13 +62,14 @@
 void VideoRenderer::Seek(SbMediaTime seek_to_pts) {
   SB_DCHECK(seek_to_pts >= 0);
 
+  decoder_->Reset();
+
   ScopedLock lock(mutex_);
 
   seeking_to_pts_ = std::max<SbMediaTime>(seek_to_pts, 0);
   seeking_ = true;
   end_of_stream_written_ = false;
 
-  decoder_->Reset();
   frames_.clear();
 }
 
@@ -81,11 +82,11 @@
   }
   // Remove any frames with timestamps earlier than |media_time|, but always
   // keep at least one of the frames.
-  while (frames_.size() > 1 && frames_.begin()->pts() < media_time) {
-    frames_.erase(frames_.begin());
+  while (frames_.size() > 1 && frames_.front().pts() < media_time) {
+    frames_.pop_front();
   }
 
-  return *frames_.begin();
+  return frames_.front();
 }
 
 bool VideoRenderer::IsEndOfStreamPlayed() const {
diff --git a/src/starboard/shared/starboard/player/video_renderer_internal.h b/src/starboard/shared/starboard/player/video_renderer_internal.h
index ef56cd6..f62cfda 100644
--- a/src/starboard/shared/starboard/player/video_renderer_internal.h
+++ b/src/starboard/shared/starboard/player/video_renderer_internal.h
@@ -15,7 +15,7 @@
 #ifndef STARBOARD_SHARED_STARBOARD_PLAYER_VIDEO_RENDERER_INTERNAL_H_
 #define STARBOARD_SHARED_STARBOARD_PLAYER_VIDEO_RENDERER_INTERNAL_H_
 
-#include <vector>
+#include <list>
 
 #include "starboard/log.h"
 #include "starboard/media.h"
@@ -50,7 +50,7 @@
   bool IsSeekingInProgress() const;
 
  private:
-  typedef std::vector<VideoFrame> Frames;
+  typedef std::list<VideoFrame> Frames;
 
   // Preroll considered finished after either kPrerollFrames is cached or EOS
   // is reached.
diff --git a/src/starboard/shared/starboard/thread_checker.h b/src/starboard/shared/starboard/thread_checker.h
new file mode 100644
index 0000000..b1842ad
--- /dev/null
+++ b/src/starboard/shared/starboard/thread_checker.h
@@ -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.
+
+#ifndef STARBOARD_SHARED_STARBOARD_THREAD_CHECKER_H_
+#define STARBOARD_SHARED_STARBOARD_THREAD_CHECKER_H_
+
+#include "starboard/atomic.h"
+#include "starboard/thread.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+
+#if defined(COBALT_BUILD_TYPE_GOLD)
+
+class ThreadChecker {
+ public:
+  enum Type { kSetThreadIdOnCreation, kSetThreadIdOnFirstCheck };
+
+  explicit ThreadChecker(Type type = kSetThreadIdOnCreation) {
+    SB_UNREFERENCED_PARAMETER(type);
+  }
+
+  bool CalledOnValidThread() const { return true; }
+};
+
+#else  // defined(COBALT_BUILD_TYPE_GOLD)
+
+class ThreadChecker {
+ public:
+  enum Type { kSetThreadIdOnCreation, kSetThreadIdOnFirstCheck };
+
+  explicit ThreadChecker(Type type = kSetThreadIdOnCreation) {
+    if (type == kSetThreadIdOnCreation)
+      thread_id_ = SbThreadGetId();
+    else
+      thread_id_ = kSbThreadInvalidId;
+  }
+
+  bool CalledOnValidThread() const {
+    SbThreadId current_thread_id = SbThreadGetId();
+    SbThreadId stored_thread_id = SbAtomicNoBarrier_CompareAndSwap(
+        &thread_id_, kSbThreadInvalidId, current_thread_id);
+    return stored_thread_id == kSbThreadInvalidId ||
+           stored_thread_id == current_thread_id;
+  }
+
+ private:
+  mutable SbThreadId thread_id_;
+};
+
+#endif  // defined(COBALT_BUILD_TYPE_GOLD)
+
+}  // namespace starboard
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_STARBOARD_THREAD_CHECKER_H_
diff --git a/src/starboard/shared/stub/player_create.cc b/src/starboard/shared/stub/player_create.cc
index e6be979..c9cb1e8 100644
--- a/src/starboard/shared/stub/player_create.cc
+++ b/src/starboard/shared/stub/player_create.cc
@@ -14,7 +14,8 @@
 
 #include "starboard/player.h"
 
-SbPlayer SbPlayerCreate(SbMediaVideoCodec /*video_codec*/,
+SbPlayer SbPlayerCreate(SbWindow /*window*/,
+                        SbMediaVideoCodec /*video_codec*/,
                         SbMediaAudioCodec /*audio_codec*/,
                         SbMediaTime /*duration_pts*/,
                         SbDrmSystem /*drm_system*/,
diff --git a/src/starboard/shared/stub/player_set_bounds.cc b/src/starboard/shared/stub/player_set_bounds.cc
new file mode 100644
index 0000000..68a3c25
--- /dev/null
+++ b/src/starboard/shared/stub/player_set_bounds.cc
@@ -0,0 +1,25 @@
+// 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/player.h"
+
+#if SB_IS(PLAYER_PUNCHED_OUT)
+
+void SbPlayerSetBounds(SbPlayer /*player*/,
+                       int /*x*/,
+                       int /*y*/,
+                       int /*width*/,
+                       int /*height*/) {}
+
+#endif  // SB_IS(PLAYER_PUNCHED_OUT)
diff --git a/src/starboard/shared/x11/application_x11.cc b/src/starboard/shared/x11/application_x11.cc
index 6225362..3499bd8 100644
--- a/src/starboard/shared/x11/application_x11.cc
+++ b/src/starboard/shared/x11/application_x11.cc
@@ -681,7 +681,7 @@
         ScopedLock lock(frame_mutex_);
         if (frame_written_) {
           // Clear the old frame, now that we are done with it.
-          frames_[frame_read_index_] = VideoFrame();
+          frame_infos_[frame_read_index_].frame = VideoFrame();
 
           // Increment the index to the next frame, which has been written.
           frame_read_index_ = (frame_read_index_ + 1) % kNumFrames;
@@ -692,18 +692,26 @@
         }
         index = frame_read_index_;
       }
-      if (!frames_[index].IsEndOfStream() &&
-          frames_[index].format() != VideoFrame::kBGRA32) {
-        frames_[index] = frames_[index].ConvertTo(VideoFrame::kBGRA32);
+      FrameInfo& frame_info = frame_infos_[frame_read_index_];
+
+      if (!frame_info.frame.IsEndOfStream() &&
+          frame_info.frame.format() != VideoFrame::kBGRA32) {
+        frame_info.frame = frame_info.frame.ConvertTo(VideoFrame::kBGRA32);
       }
-      window->Composite(&frames_[index]);
+      window->Composite(frame_info.x, frame_info.y, frame_info.width,
+                        frame_info.height, &frame_info.frame);
     }
   }
   composite_event_id_ =
       SbEventSchedule(&CompositeCallback, this, kSbTimeSecond / 60);
 }
 
-void ApplicationX11::AcceptFrame(const VideoFrame& frame) {
+void ApplicationX11::AcceptFrame(SbPlayer player,
+                                 const VideoFrame& frame,
+                                 int x,
+                                 int y,
+                                 int width,
+                                 int height) {
   int write_index = -1;
   {
     ScopedLock lock(frame_mutex_);
@@ -717,7 +725,11 @@
   }
 
   // Copy the frame.
-  frames_[write_index] = frame;
+  frame_infos_[write_index].frame = frame;
+  frame_infos_[write_index].x = x;
+  frame_infos_[write_index].y = y;
+  frame_infos_[write_index].width = width;
+  frame_infos_[write_index].height = height;
 
   {
     ScopedLock lock(frame_mutex_);
diff --git a/src/starboard/shared/x11/application_x11.h b/src/starboard/shared/x11/application_x11.h
index 6d017ba..4be2cab 100644
--- a/src/starboard/shared/x11/application_x11.h
+++ b/src/starboard/shared/x11/application_x11.h
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "starboard/configuration.h"
+#include "starboard/player.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/application.h"
 #include "starboard/shared/starboard/queue_application.h"
@@ -47,8 +48,12 @@
   void Composite();
 
  protected:
-  void AcceptFrame(const shared::starboard::player::VideoFrame& frame)
-      SB_OVERRIDE;
+  void AcceptFrame(SbPlayer player,
+                   const shared::starboard::player::VideoFrame& frame,
+                   int x,
+                   int y,
+                   int width,
+                   int height) SB_OVERRIDE;
 #endif  // SB_IS(PLAYER_PUNCHED_OUT)
 
  protected:
@@ -65,6 +70,16 @@
  private:
   typedef std::vector<SbWindow> SbWindowVector;
 
+#if SB_IS(PLAYER_PUNCHED_OUT)
+  struct FrameInfo {
+    shared::starboard::player::VideoFrame frame;
+    int x;
+    int y;
+    int width;
+    int height;
+  };
+#endif  // SB_IS(PLAYER_PUNCHED_OUT)
+
   // Ensures that X is up, display is populated and connected.
   void EnsureX();
 
@@ -87,7 +102,7 @@
   int frame_read_index_;
   bool frame_written_;
   static const int kNumFrames = 2;
-  shared::starboard::player::VideoFrame frames_[kNumFrames];
+  FrameInfo frame_infos_[kNumFrames];
 #endif  // SB_IS(PLAYER_PUNCHED_OUT)
 
   Display* display_;
diff --git a/src/starboard/shared/x11/window_internal.cc b/src/starboard/shared/x11/window_internal.cc
index c330c30..3885bf6 100644
--- a/src/starboard/shared/x11/window_internal.cc
+++ b/src/starboard/shared/x11/window_internal.cc
@@ -147,7 +147,11 @@
 }
 
 #if SB_IS(PLAYER_PUNCHED_OUT)
-void SbWindowPrivate::Composite(VideoFrame* frame) {
+void SbWindowPrivate::Composite(int bounds_x,
+                                int bounds_y,
+                                int bounds_width,
+                                int bounds_height,
+                                VideoFrame* frame) {
   XSynchronize(display, True);
   XWindowAttributes window_attributes;
   XGetWindowAttributes(display, window, &window_attributes);
@@ -227,10 +231,12 @@
     // Initially assume we don't have to center or scale.
     int video_width = frame->width();
     int video_height = frame->height();
-    if (frame->width() != width || frame->height() != height) {
+    if (bounds_width != width || bounds_height != height ||
+        frame->width() != width || frame->height() != height) {
       // Scale to fit the smallest dimension of the frame into the window.
-      double scale = std::min(width / static_cast<double>(frame->width()),
-                              height / static_cast<double>(frame->height()));
+      double scale =
+          std::min(bounds_width / static_cast<double>(frame->width()),
+                   bounds_height / static_cast<double>(frame->height()));
       // Center the scaled frame within the window.
       video_width = scale * frame->width();
       video_height = scale * frame->height();
@@ -242,8 +248,8 @@
       XRenderSetPictureTransform(display, video_picture, &transform);
     }
 
-    int dest_x = (width - video_width) / 2;
-    int dest_y = (height - video_height) / 2;
+    int dest_x = bounds_x + (bounds_width - video_width) / 2;
+    int dest_y = bounds_y + (bounds_height - video_height) / 2;
     XRenderComposite(display, PictOpSrc, video_picture, NULL,
                      composition_picture, 0, 0, 0, 0, dest_x, dest_y,
                      video_width, video_height);
diff --git a/src/starboard/shared/x11/window_internal.h b/src/starboard/shared/x11/window_internal.h
index 00d3c01..7c55cb3 100644
--- a/src/starboard/shared/x11/window_internal.h
+++ b/src/starboard/shared/x11/window_internal.h
@@ -35,8 +35,13 @@
 #if SB_IS(PLAYER_PUNCHED_OUT)
   // Composites graphics and the given video frame video for this window. In
   // PLAYER_PUNCHED_OUT mode, this is the only way any graphics or video is
-  // presented in the window.
-  void Composite(::starboard::shared::starboard::player::VideoFrame* frame);
+  // presented in the window.  The video frame will be rendered according to
+  // boundaries specified by the parameters.
+  void Composite(int bounds_x,
+                 int bounds_y,
+                 int bounds_width,
+                 int bounds_height,
+                 ::starboard::shared::starboard::player::VideoFrame* frame);
 
   // The cached XRender Picture that represents the window that is the
   // destination of the composition.
diff --git a/src/starboard/stub/starboard_platform.gyp b/src/starboard/stub/starboard_platform.gyp
index e07af31..1ac0c82 100644
--- a/src/starboard/stub/starboard_platform.gyp
+++ b/src/starboard/stub/starboard_platform.gyp
@@ -107,6 +107,7 @@
         '<(DEPTH)/starboard/shared/stub/player_destroy.cc',
         '<(DEPTH)/starboard/shared/stub/player_get_info.cc',
         '<(DEPTH)/starboard/shared/stub/player_seek.cc',
+        '<(DEPTH)/starboard/shared/stub/player_set_bounds.cc',
         '<(DEPTH)/starboard/shared/stub/player_set_pause.cc',
         '<(DEPTH)/starboard/shared/stub/player_write_end_of_stream.cc',
         '<(DEPTH)/starboard/shared/stub/player_write_sample.cc',