Import Cobalt 3.11764
diff --git a/src/cobalt/base/base.gyp b/src/cobalt/base/base.gyp
index a2822ab..19652ec 100644
--- a/src/cobalt/base/base.gyp
+++ b/src/cobalt/base/base.gyp
@@ -45,6 +45,7 @@
         'log_message_handler.h',
         'math.cc',
         'math.h',
+        'message_queue.h',
         'poller.h',
         'polymorphic_downcast.h',
         'polymorphic_equatable.h',
diff --git a/src/cobalt/base/message_queue.h b/src/cobalt/base/message_queue.h
new file mode 100644
index 0000000..3c7ad78
--- /dev/null
+++ b/src/cobalt/base/message_queue.h
@@ -0,0 +1,63 @@
+/*
+ * 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_MESSAGE_QUEUE_H_
+#define COBALT_BASE_MESSAGE_QUEUE_H_
+
+#include <queue>
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// A thread safe in-order message queue.  In some situations this can be
+// preferred versus PostTask()ing directly to a MessageLoop since the data
+// stored within the queued Closures can be destroyed on demand, and also the
+// queue messages can be processed at a time of the user's choosing.
+class MessageQueue {
+ public:
+  ~MessageQueue() {
+    // Leave no message behind!
+    ProcessAll();
+  }
+
+  // Add a message to the end of the queue.
+  void AddMessage(const base::Closure& message) {
+    base::AutoLock lock(mutex_);
+    DCHECK(!message.is_null());
+    queue_.push(message);
+  }
+
+  // Execute all messages in the MessageQueue until the queue is empty and then
+  // return.
+  void ProcessAll() {
+    base::AutoLock lock(mutex_);
+
+    while (!queue_.empty()) {
+      queue_.front().Run();
+      queue_.pop();
+    }
+  }
+
+ private:
+  base::Lock mutex_;
+  std::queue<base::Closure> queue_;
+};
+
+}  // namespace base
+
+#endif  // COBALT_BASE_MESSAGE_QUEUE_H_
diff --git a/src/cobalt/bindings/testing/global_interface_bindings_test.cc b/src/cobalt/bindings/testing/global_interface_bindings_test.cc
index 5f8b90c..5f50d61 100644
--- a/src/cobalt/bindings/testing/global_interface_bindings_test.cc
+++ b/src/cobalt/bindings/testing/global_interface_bindings_test.cc
@@ -38,7 +38,9 @@
 }  // namespace
 
 TEST_F(GlobalInterfaceBindingsTest, GlobalWindowIsThis) {
-  EXPECT_TRUE(EvaluateScript("window === this;", NULL));
+  std::string result;
+  EXPECT_TRUE(EvaluateScript("window === this;", &result));
+  EXPECT_STREQ("true", result.c_str());
 }
 
 TEST_F(GlobalInterfaceBindingsTest, GlobalOperation) {
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index 692ee5d..da20704 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -139,6 +139,9 @@
                       options.network_module_options),
       render_tree_combiner_(renderer_module_.pipeline(),
                             renderer_module_.render_target()->GetSize()),
+#if defined(ENABLE_SCREENSHOT)
+      screen_shot_writer_(new ScreenShotWriter(renderer_module_.pipeline())),
+#endif  // defined(ENABLE_SCREENSHOT)
       web_module_loaded_(true /* manually_reset */,
                          false /* initially_signalled */),
       web_module_recreated_callback_(options.web_module_recreated_callback),
@@ -158,9 +161,6 @@
           kScreenshotCommandShortHelp, kScreenshotCommandLongHelp)),
 #endif  // defined(ENABLE_SCREENSHOT)
 #endif  // defined(ENABLE_DEBUG_CONSOLE)
-#if defined(ENABLE_SCREENSHOT)
-      screen_shot_writer_(new ScreenShotWriter(renderer_module_.pipeline())),
-#endif  // defined(ENABLE_SCREENSHOT)
       ALLOW_THIS_IN_INITIALIZER_LIST(
           h5vcc_url_handler_(this, system_window, account_manager)),
       web_module_options_(options.web_module_options),
@@ -190,7 +190,7 @@
 
 #if defined(ENABLE_DEBUG_CONSOLE)
   debug_console_.reset(new DebugConsole(
-      base::Bind(&BrowserModule::OnDebugConsoleRenderTreeProduced,
+      base::Bind(&BrowserModule::QueueOnDebugConsoleRenderTreeProduced,
                  base::Unretained(this)),
       media_module_.get(), &network_module_,
       renderer_module_.render_target()->GetSize(),
@@ -239,18 +239,19 @@
   }
 
   // Destroy old WebModule first, so we don't get a memory high-watermark after
-  // the second WebModule's construtor runs, but before scoped_ptr::reset() is
+  // the second WebModule's constructor runs, but before scoped_ptr::reset() is
   // run.
   web_module_.reset(NULL);
 
   // Show a splash screen while we're waiting for the web page to load.
   const math::Size& viewport_size = renderer_module_.render_target()->GetSize();
   DestroySplashScreen();
-  splash_screen_.reset(new SplashScreen(
-      base::Bind(&BrowserModule::OnRenderTreeProduced, base::Unretained(this)),
-      &network_module_, viewport_size,
-      renderer_module_.pipeline()->GetResourceProvider(),
-      kLayoutMaxRefreshFrequencyInHz));
+  splash_screen_.reset(
+      new SplashScreen(base::Bind(&BrowserModule::QueueOnRenderTreeProduced,
+                                  base::Unretained(this)),
+                       &network_module_, viewport_size,
+                       renderer_module_.pipeline()->GetResourceProvider(),
+                       kLayoutMaxRefreshFrequencyInHz));
 
   // Create new WebModule.
 #if !defined(COBALT_FORCE_CSP)
@@ -269,19 +270,27 @@
 #endif  // defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
   options.image_cache_capacity_multiplier_when_playing_video =
       COBALT_IMAGE_CACHE_CAPACITY_MULTIPLIER_WHEN_PLAYING_VIDEO;
-  web_module_.reset(new WebModule(
-      url,
-      base::Bind(&BrowserModule::OnRenderTreeProduced, base::Unretained(this)),
-      base::Bind(&BrowserModule::OnError, base::Unretained(this)),
-      media_module_.get(), &network_module_, viewport_size,
-      renderer_module_.pipeline()->GetResourceProvider(),
-      kLayoutMaxRefreshFrequencyInHz, options));
+  web_module_.reset(
+      new WebModule(url, base::Bind(&BrowserModule::QueueOnRenderTreeProduced,
+                                    base::Unretained(this)),
+                    base::Bind(&BrowserModule::OnError, base::Unretained(this)),
+                    media_module_.get(), &network_module_, viewport_size,
+                    renderer_module_.pipeline()->GetResourceProvider(),
+                    kLayoutMaxRefreshFrequencyInHz, options));
   if (!web_module_recreated_callback_.is_null()) {
     web_module_recreated_callback_.Run();
   }
 }
 
 void BrowserModule::OnLoad() {
+  // Repost to our own message loop if necessary. This also prevents
+  // asynchonrous access to this object by |web_module_| during destruction.
+  if (MessageLoop::current() != self_message_loop_) {
+    self_message_loop_->PostTask(
+        FROM_HERE, base::Bind(&BrowserModule::OnLoad, weak_this_));
+    return;
+  }
+
   DestroySplashScreen();
   web_module_loaded_.Signal();
 }
@@ -303,16 +312,28 @@
 }
 #endif
 
+void BrowserModule::ProcessRenderTreeSubmissionQueue() {
+  TRACE_EVENT0("cobalt::browser",
+               "BrowserModule::ProcessRenderTreeSubmissionQueue()");
+  DCHECK_EQ(MessageLoop::current(), self_message_loop_);
+  render_tree_submission_queue_.ProcessAll();
+}
+
+void BrowserModule::QueueOnRenderTreeProduced(
+    const browser::WebModule::LayoutResults& layout_results) {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::QueueOnRenderTreeProduced()");
+  render_tree_submission_queue_.AddMessage(
+      base::Bind(&BrowserModule::OnRenderTreeProduced, base::Unretained(this),
+                 layout_results));
+  self_message_loop_->PostTask(
+      FROM_HERE,
+      base::Bind(&BrowserModule::ProcessRenderTreeSubmissionQueue, weak_this_));
+}
+
 void BrowserModule::OnRenderTreeProduced(
     const browser::WebModule::LayoutResults& layout_results) {
   TRACE_EVENT0("cobalt::browser", "BrowserModule::OnRenderTreeProduced()");
-  if (MessageLoop::current() != self_message_loop_) {
-    self_message_loop_->PostTask(
-        FROM_HERE,
-        base::Bind(&BrowserModule::OnRenderTreeProduced, weak_this_,
-                   layout_results));
-    return;
-  }
+  DCHECK_EQ(MessageLoop::current(), self_message_loop_);
 
   renderer::Submission renderer_submission(layout_results.render_tree,
                                            layout_results.layout_time);
@@ -372,17 +393,23 @@
   }
 }
 
+void BrowserModule::QueueOnDebugConsoleRenderTreeProduced(
+    const browser::WebModule::LayoutResults& layout_results) {
+  TRACE_EVENT0("cobalt::browser",
+               "BrowserModule::QueueOnDebugConsoleRenderTreeProduced()");
+  render_tree_submission_queue_.AddMessage(
+      base::Bind(&BrowserModule::OnDebugConsoleRenderTreeProduced,
+                 base::Unretained(this), layout_results));
+  self_message_loop_->PostTask(
+      FROM_HERE,
+      base::Bind(&BrowserModule::ProcessRenderTreeSubmissionQueue, weak_this_));
+}
+
 void BrowserModule::OnDebugConsoleRenderTreeProduced(
     const browser::WebModule::LayoutResults& layout_results) {
   TRACE_EVENT0("cobalt::browser",
                "BrowserModule::OnDebugConsoleRenderTreeProduced()");
-  if (MessageLoop::current() != self_message_loop_) {
-    self_message_loop_->PostTask(
-        FROM_HERE,
-        base::Bind(&BrowserModule::OnDebugConsoleRenderTreeProduced, weak_this_,
-                   layout_results));
-    return;
-  }
+  DCHECK_EQ(MessageLoop::current(), self_message_loop_);
 
   render_tree_combiner_.UpdateDebugConsoleRenderTree(renderer::Submission(
       layout_results.render_tree, layout_results.layout_time));
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index df6da73..d00a3fb 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -24,6 +24,7 @@
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "cobalt/account/account_manager.h"
+#include "cobalt/base/message_queue.h"
 #include "cobalt/browser/h5vcc_url_handler.h"
 #include "cobalt/browser/render_tree_combiner.h"
 #include "cobalt/browser/screen_shot_writer.h"
@@ -126,6 +127,8 @@
 
   // Glue function to deal with the production of the main render tree,
   // and will manage handing it off to the renderer.
+  void QueueOnRenderTreeProduced(
+      const browser::WebModule::LayoutResults& layout_results);
   void OnRenderTreeProduced(
       const browser::WebModule::LayoutResults& layout_results);
 
@@ -173,6 +176,8 @@
 
   // Glue function to deal with the production of the debug console render tree,
   // and will manage handing it off to the renderer.
+  void QueueOnDebugConsoleRenderTreeProduced(
+      const browser::WebModule::LayoutResults& layout_results);
   void OnDebugConsoleRenderTreeProduced(
       const browser::WebModule::LayoutResults& layout_results);
 #endif  // defined(ENABLE_DEBUG_CONSOLE)
@@ -192,6 +197,9 @@
   void OnRendererSubmissionRasterized();
 #endif  // OS_STARBOARD
 
+  // Process all messages queued into the |render_tree_submission_queue_|.
+  void ProcessRenderTreeSubmissionQueue();
+
   // TODO:
   //     WeakPtr usage here can be avoided if BrowserModule has a thread to
   //     own where it can ensure that its tasks are all resolved when it is
@@ -244,6 +252,18 @@
   // Manages the two render trees, combines and renders them.
   RenderTreeCombiner render_tree_combiner_;
 
+#if defined(ENABLE_SCREENSHOT)
+  // Helper object to create screen shots of the last layout tree.
+  scoped_ptr<ScreenShotWriter> screen_shot_writer_;
+#endif  // defined(ENABLE_SCREENSHOT)
+
+  // Keeps track of all messages containing render tree submissions that will
+  // ultimately reference the |render_tree_combiner_| and the
+  // |renderer_module_|.  It is important that this is destroyed before the
+  // above mentioned references are.  It must however outlive all WebModules
+  // that may be producing render trees.
+  base::MessageQueue render_tree_submission_queue_;
+
   // Sets up everything to do with web page management, from loading and
   // parsing the web page and all referenced files to laying it out.  The
   // web module will ultimately produce a render tree that can be passed
@@ -283,11 +303,6 @@
 #endif  // defined(ENABLE_SCREENSHOT)
 #endif  // defined(ENABLE_DEBUG_CONSOLE)
 
-#if defined(ENABLE_SCREENSHOT)
-  // Helper object to create screen shots of the last layout tree.
-  scoped_ptr<ScreenShotWriter> screen_shot_writer_;
-#endif  // defined(ENABLE_SCREENSHOT)
-
   // Handler object for h5vcc URLs.
   H5vccURLHandler h5vcc_url_handler_;
 
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index eb49ee4..fa37d0f 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-11337
\ No newline at end of file
+11764
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index 3e07aab..56da0af 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -122,6 +122,7 @@
     #   - scratch_surface_cache_size_in_bytes
     #   - surface_cache_size_in_bytes
     #   - image_cache_size_in_bytes
+    #   - skia_glyph_atlas_width * skia_glyph_atlas_height
     #
     # The other caches affect CPU memory usage.
 
@@ -162,6 +163,15 @@
     #     image_cache_capacity_multiplier_when_playing_video.
     'image_cache_capacity_multiplier_when_playing_video%': '1.0f',
 
+    # Determines the size in pixels of the glyph atlas where rendered glyphs are
+    # cached. The resulting memory usage is 2 bytes of GPU memory per pixel.
+    # When a value is used that is too small, thrashing may occur that will
+    # result in visible stutter. Such thrashing is more likely to occur when CJK
+    # language glyphs are rendered and when the size of the glyphs in pixels is
+    # larger, such as for higher resolution displays.
+    'skia_glyph_atlas_width%': '2048',
+    'skia_glyph_atlas_height%': '2048',
+
     # Compiler configuration.
 
     # The following variables are used to specify compiler and linker
diff --git a/src/cobalt/debug/debug_web_server.cc b/src/cobalt/debug/debug_web_server.cc
index 0bc80b7..5ec3d06 100644
--- a/src/cobalt/debug/debug_web_server.cc
+++ b/src/cobalt/debug/debug_web_server.cc
@@ -137,10 +137,10 @@
 }
 
 DebugWebServer::~DebugWebServer() {
-  net::HttpServer* server = server_.get();
-  server_->AddRef();
-  server_ = NULL;
-  http_server_thread_.message_loop()->ReleaseSoon(FROM_HERE, server);
+  // Destroy the server on its own thread then stop the thread.
+  http_server_thread_.message_loop()->PostTask(
+      FROM_HERE,
+      base::Bind(&DebugWebServer::StopServer, base::Unretained(this)));
   http_server_thread_.Stop();
 }
 
@@ -320,5 +320,10 @@
   }
 }
 
+void DebugWebServer::StopServer() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  server_ = NULL;
+}
+
 }  // namespace debug
 }  // namespace cobalt
diff --git a/src/cobalt/debug/debug_web_server.h b/src/cobalt/debug/debug_web_server.h
index ac2a593..9f55c16 100644
--- a/src/cobalt/debug/debug_web_server.h
+++ b/src/cobalt/debug/debug_web_server.h
@@ -79,11 +79,14 @@
 
   void StartServer(int port);
 
+  void StopServer();
+
   void SendErrorResponseOverWebSocket(int id, const std::string& message);
 
   base::ThreadChecker thread_checker_;
   base::Thread http_server_thread_;
   scoped_ptr<net::StreamListenSocketFactory> factory_;
+  // net::HttpServer is a ref-counted object, so we have to use scoped_refptr.
   scoped_refptr<net::HttpServer> server_;
   GetDebugServerCallback get_debug_server_callback_;
 
diff --git a/src/cobalt/dom/media_error.h b/src/cobalt/dom/media_error.h
index 339c386..124b437 100644
--- a/src/cobalt/dom/media_error.h
+++ b/src/cobalt/dom/media_error.h
@@ -44,7 +44,7 @@
 
   // Web API: MediaError
   //
-  Code code() const { return code_; }
+  uint32 code() const { return code_; }
 
   DEFINE_WRAPPABLE_TYPE(MediaError);
 
diff --git a/src/cobalt/dom_parser/libxml_html_parser_wrapper.cc b/src/cobalt/dom_parser/libxml_html_parser_wrapper.cc
index e65ef8f..75e760b 100644
--- a/src/cobalt/dom_parser/libxml_html_parser_wrapper.cc
+++ b/src/cobalt/dom_parser/libxml_html_parser_wrapper.cc
@@ -110,9 +110,7 @@
     return;
   }
 
-  if (!IsStringUTF8(std::string(data, size))) {
-    static const char* kWarningNotUTF8 = "Ignoring non-UTF8 HTML input.";
-    OnParsingIssue(kWarning, kWarningNotUTF8);
+  if (CheckInputAndUpdateSeverity(data, size) >= kError) {
     return;
   }
 
@@ -127,7 +125,7 @@
         NULL /*filename*/, XML_CHAR_ENCODING_UTF8);
 
     if (!html_parser_context_) {
-      static const char* kErrorUnableCreateParser =
+      static const char kErrorUnableCreateParser[] =
           "Unable to create the libxml2 parser.";
       OnParsingIssue(kFatal, kErrorUnableCreateParser);
     } else {
@@ -149,12 +147,8 @@
   }
 
   if (html_parser_context_) {
-    // TODO: The check on issue level is a workaround for the fact that libxml
-    // doesn't recover fully from error related to encoding.
-    if (issue_level() <= kWarning) {
-      htmlParseChunk(html_parser_context_, NULL, 0,
-                     1 /*terminate*/);  // Triggers EndDocument
-    }
+    htmlParseChunk(html_parser_context_, NULL, 0,
+                   1 /*terminate*/);  // Triggers EndDocument
     if (IsFullDocument()) {
       document()->DecreaseLoadingCounterAndMaybeDispatchLoadEvent();
     }
diff --git a/src/cobalt/dom_parser/libxml_parser_wrapper.cc b/src/cobalt/dom_parser/libxml_parser_wrapper.cc
index 3acaf88..ec05383 100644
--- a/src/cobalt/dom_parser/libxml_parser_wrapper.cc
+++ b/src/cobalt/dom_parser/libxml_parser_wrapper.cc
@@ -214,8 +214,8 @@
 
 void LibxmlParserWrapper::OnParsingIssue(IssueSeverity severity,
                                          const std::string& message) {
-  if (severity > issue_level_) {
-    issue_level_ = severity;
+  if (severity > max_severity_) {
+    max_severity_ = severity;
   }
   if (severity < LibxmlParserWrapper::kFatal) {
     LOG(WARNING) << message;
@@ -230,5 +230,31 @@
   node_stack_.top()->AppendChild(new dom::CDATASection(document_, value));
 }
 
+LibxmlParserWrapper::IssueSeverity
+LibxmlParserWrapper::CheckInputAndUpdateSeverity(const char* data,
+                                                 size_t size) {
+  if (max_severity_ >= kError) {
+    return max_severity_;
+  }
+
+  // Check the total input size.
+  total_input_size_ += size;
+  if (total_input_size_ > kMaxTotalInputSize) {
+    static const char kErrorTooLong[] = "Parser input is too long.";
+    OnParsingIssue(kError, kErrorTooLong);
+    return max_severity_;
+  }
+
+  // Check the encoding of the input.
+  if (!IsStringUTF8(std::string(data, size))) {
+    static const char kErrorNotUTF8[] =
+        "Parser input contains non-UTF8 characters.";
+    OnParsingIssue(kError, kErrorNotUTF8);
+    return max_severity_;
+  }
+
+  return max_severity_;
+}
+
 }  // namespace dom_parser
 }  // namespace cobalt
diff --git a/src/cobalt/dom_parser/libxml_parser_wrapper.h b/src/cobalt/dom_parser/libxml_parser_wrapper.h
index 61f3d04..c391fab 100644
--- a/src/cobalt/dom_parser/libxml_parser_wrapper.h
+++ b/src/cobalt/dom_parser/libxml_parser_wrapper.h
@@ -92,7 +92,8 @@
         first_chunk_location_(first_chunk_location),
         error_callback_(error_callback),
         depth_limit_exceeded_(false),
-        issue_level_(kNoIssue) {}
+        max_severity_(kNoIssue),
+        total_input_size_(0) {}
   virtual ~LibxmlParserWrapper() {}
 
   // These functions are for Libxml interface, calls are forwarded here by
@@ -120,6 +121,9 @@
   // Returns true when the input is a full document, false when it's a fragment.
   bool IsFullDocument() { return document_ == parent_node_; }
 
+  // Checks the input, updates and returns the maximum issue severity.
+  IssueSeverity CheckInputAndUpdateSeverity(const char* data, size_t size);
+
   const scoped_refptr<dom::Document>& document() { return document_; }
   const base::SourceLocation& first_chunk_location() {
     return first_chunk_location_;
@@ -128,13 +132,14 @@
     return error_callback_;
   }
 
-  IssueSeverity issue_level() const { return issue_level_; }
-
   const std::stack<scoped_refptr<dom::Node> >& node_stack() {
     return node_stack_;
   }
 
  private:
+  // Maximum total input size, 1MB.
+  static const size_t kMaxTotalInputSize = 1 << 16;
+
   const scoped_refptr<dom::Document> document_;
   const scoped_refptr<dom::Node> parent_node_;
   const scoped_refptr<dom::Node> reference_node_;
@@ -145,7 +150,8 @@
   const base::Callback<void(const std::string&)> error_callback_;
 
   bool depth_limit_exceeded_;
-  IssueSeverity issue_level_;
+  IssueSeverity max_severity_;
+  size_t total_input_size_;
 
   std::stack<scoped_refptr<dom::Node> > node_stack_;
 
diff --git a/src/cobalt/dom_parser/libxml_xml_parser_wrapper.cc b/src/cobalt/dom_parser/libxml_xml_parser_wrapper.cc
index edab9f0..c933f5e 100644
--- a/src/cobalt/dom_parser/libxml_xml_parser_wrapper.cc
+++ b/src/cobalt/dom_parser/libxml_xml_parser_wrapper.cc
@@ -79,9 +79,7 @@
     return;
   }
 
-  if (!IsStringUTF8(std::string(data, size))) {
-    static const char* kWarningNotUTF8 = "Ignoring non-UTF8 XML input.";
-    OnParsingIssue(kWarning, kWarningNotUTF8);
+  if (CheckInputAndUpdateSeverity(data, size) >= kError) {
     return;
   }
 
diff --git a/src/cobalt/loader/embedded_resources/splash_screen.css b/src/cobalt/loader/embedded_resources/splash_screen.css
index 0af40bf..7602576 100644
--- a/src/cobalt/loader/embedded_resources/splash_screen.css
+++ b/src/cobalt/loader/embedded_resources/splash_screen.css
@@ -4,11 +4,11 @@
 }
 
 #splash {
-  background-color: #e62d27;
+  background-color: #e62117;
   background-image: url("h5vcc-embedded://you_tube_logo.png");
   background-position: center center;
   background-repeat: no-repeat;
-  background-size: 60%;
+  background-size: 100%;
   height: 100%;
   left: 0;
   position: absolute;
diff --git a/src/cobalt/loader/embedded_resources/you_tube_logo.png b/src/cobalt/loader/embedded_resources/you_tube_logo.png
index 0d2082d..a964097 100644
--- a/src/cobalt/loader/embedded_resources/you_tube_logo.png
+++ b/src/cobalt/loader/embedded_resources/you_tube_logo.png
Binary files differ
diff --git a/src/cobalt/media/media_buffer_allocator.h b/src/cobalt/media/media_buffer_allocator.h
new file mode 100644
index 0000000..ef7f620
--- /dev/null
+++ b/src/cobalt/media/media_buffer_allocator.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COBALT_MEDIA_MEDIA_BUFFER_ALLOCATOR_H_
+#define COBALT_MEDIA_MEDIA_BUFFER_ALLOCATOR_H_
+
+#include "base/optional.h"
+#include "nb/memory_pool.h"
+
+namespace cobalt {
+namespace media {
+
+class MediaBufferAllocator {
+ public:
+  MediaBufferAllocator(void* pool, size_t main_pool_size,
+                       size_t small_allocation_pool_size,
+                       size_t small_allocation_threshold)
+      : pool_(reinterpret_cast<uint8*>(pool)),
+        main_pool_size_(main_pool_size),
+        small_allocation_pool_size_(small_allocation_pool_size),
+        small_allocation_threshold_(small_allocation_threshold),
+        main_pool_(pool_, main_pool_size_, true, /* thread_safe */
+                   true /* verify_full_capacity */) {
+    if (small_allocation_pool_size_ > 0u) {
+      DCHECK_GT(small_allocation_threshold_, 0u);
+      small_allocation_pool_.emplace(pool_ + main_pool_size_,
+                                     small_allocation_pool_size_,
+                                     true, /* thread_safe */
+                                     true /* verify_full_capacity */);
+    } else {
+      DCHECK_EQ(small_allocation_pool_size_, 0u);
+      DCHECK_EQ(small_allocation_threshold_, 0u);
+    }
+  }
+
+  void* Allocate(size_t size, size_t alignment) {
+    void* p = NULL;
+    if (size < small_allocation_threshold_ && small_allocation_pool_) {
+      p = small_allocation_pool_->Allocate(size, alignment);
+    }
+    if (!p) {
+      p = main_pool_.Allocate(size, alignment);
+    }
+    if (!p && small_allocation_pool_) {
+      p = small_allocation_pool_->Allocate(size, alignment);
+    }
+    return p;
+  }
+
+  void Free(void* p) {
+    if (p >= pool_ + main_pool_size_ && small_allocation_pool_) {
+      DCHECK_LT(p, pool_ + main_pool_size_ + small_allocation_pool_size_);
+      small_allocation_pool_->Free(p);
+      return;
+    }
+    DCHECK_GE(p, pool_);
+    DCHECK_LT(p, pool_ + main_pool_size_);
+    main_pool_.Free(p);
+  }
+
+ private:
+  uint8* pool_;
+  size_t main_pool_size_;
+  size_t small_allocation_pool_size_;
+  size_t small_allocation_threshold_;
+
+  nb::MemoryPool main_pool_;
+  base::optional<nb::MemoryPool> small_allocation_pool_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaBufferAllocator);
+};
+
+}  // namespace media
+}  // namespace cobalt
+
+#endif  // COBALT_MEDIA_MEDIA_BUFFER_ALLOCATOR_H_
diff --git a/src/cobalt/script/mozjs/conversion_helpers.h b/src/cobalt/script/mozjs/conversion_helpers.h
index 3d54ec6..f5eca1e 100644
--- a/src/cobalt/script/mozjs/conversion_helpers.h
+++ b/src/cobalt/script/mozjs/conversion_helpers.h
@@ -369,6 +369,10 @@
       context,
       global_environment->wrapper_factory()->GetWrapperProxy(in_object));
   DCHECK(object);
+  JS::RootedObject proxy_target(context, js::GetProxyTargetObject(object));
+  if (JS_IsGlobalObject(proxy_target)) {
+    object = proxy_target;
+  }
 
   out_value.set(OBJECT_TO_JSVAL(object));
 }
diff --git a/src/cobalt/script/mozjs/mozjs.gyp b/src/cobalt/script/mozjs/mozjs.gyp
index b29d99b..6e856f5 100644
--- a/src/cobalt/script/mozjs/mozjs.gyp
+++ b/src/cobalt/script/mozjs/mozjs.gyp
@@ -73,5 +73,30 @@
         '<(DEPTH)/third_party/mozjs/mozjs.gyp:mozjs_lib',
       ],
     },
+
+    {
+      'target_name': 'mozjs_engine_test',
+      'type': '<(gtest_target_type)',
+      'sources': [
+        '<(DEPTH)/third_party/mozjs/test/jscustomallocator_test.cc',
+      ],
+      'dependencies': [
+        '<(DEPTH)/base/base.gyp:run_all_unittests',
+        '<(DEPTH)/testing/gtest.gyp:gtest',
+        '<(DEPTH)/third_party/mozjs/mozjs.gyp:mozjs_lib',
+      ],
+    },
+
+    {
+      'target_name': 'mozjs_engine_test_deploy',
+      'type': 'none',
+      'dependencies': [
+        'mozjs_engine_test',
+      ],
+      'variables': {
+        'executable_name': 'mozjs_engine_test',
+      },
+      'includes': [ '../../../starboard/build/deploy.gypi' ],
+    },
   ],
 }
diff --git a/src/cobalt/script/mozjs/mozjs_engine.cc b/src/cobalt/script/mozjs/mozjs_engine.cc
index 1b79cf7..6c21306 100644
--- a/src/cobalt/script/mozjs/mozjs_engine.cc
+++ b/src/cobalt/script/mozjs/mozjs_engine.cc
@@ -19,7 +19,10 @@
 #include <algorithm>
 
 #include "base/logging.h"
+#include "cobalt/base/c_val.h"
+#include "cobalt/base/poller.h"
 #include "cobalt/script/mozjs/mozjs_global_environment.h"
+#include "third_party/mozjs/cobalt_config/include/jscustomallocator.h"
 #include "third_party/mozjs/js/src/jsapi.h"
 
 namespace cobalt {
@@ -38,6 +41,64 @@
   CheckAccessStub,
   MozjsGlobalEnvironment::CheckEval
 };
+
+#if defined(__LB_SHELL__FOR_RELEASE__)
+const int kPollerPeriodMs = 2000;
+#else  // #if defined(__LB_SHELL__FOR_RELEASE__)
+const int kPollerPeriodMs = 20;
+#endif  // #if defined(__LB_SHELL__FOR_RELEASE__)
+
+class EngineStats {
+ public:
+  EngineStats();
+
+  static EngineStats* GetInstance() {
+    return Singleton<EngineStats,
+                     StaticMemorySingletonTraits<EngineStats> >::get();
+  }
+
+  void EngineCreated() {
+    base::AutoLock auto_lock(lock_);
+    ++engine_count_;
+  }
+
+  void EngineDestroyed() {
+    base::AutoLock auto_lock(lock_);
+    --engine_count_;
+  }
+
+  void Update() {
+    base::AutoLock auto_lock(lock_);
+    allocated_memory_ =
+        MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+    mapped_memory_ = MemoryAllocatorReporter::Get()->GetCurrentBytesMapped();
+    memory_sum_ = allocated_memory_ + mapped_memory_;
+  }
+
+ private:
+  base::Lock lock_;
+  base::CVal<size_t, base::CValPublic> allocated_memory_;
+  base::CVal<size_t, base::CValPublic> mapped_memory_;
+  base::CVal<size_t, base::CValPublic> memory_sum_;
+  base::CVal<size_t> engine_count_;
+
+  // Repeating timer to query the used bytes.
+  scoped_ptr<base::PollerWithThread> poller_;
+};
+
+EngineStats::EngineStats()
+    : allocated_memory_("Memory.JS.AllocatedMemory", 0,
+                        "JS memory occupied by the Mozjs allocator."),
+      mapped_memory_("Memory.JS.MappedMemory", 0, "JS mapped memory."),
+      memory_sum_("Memory.JS", 0,
+                  "Total memory occupied by the Mozjs allocator and heap."),
+      engine_count_("Count.JS.Engine", 0,
+                    "Total JavaScript engine registered.") {
+  poller_.reset(new base::PollerWithThread(
+      base::Bind(&EngineStats::Update, base::Unretained(this)),
+      base::TimeDelta::FromMilliseconds(kPollerPeriodMs)));
+}
+
 }  // namespace
 
 MozjsEngine::MozjsEngine() {
@@ -68,10 +129,13 @@
 
   // Callback to be called during garbage collection during the sweep phase.
   JS_SetFinalizeCallback(runtime_, &MozjsEngine::FinalizeCallback);
+
+  EngineStats::GetInstance()->EngineCreated();
 }
 
 MozjsEngine::~MozjsEngine() {
   DCHECK(thread_checker_.CalledOnValidThread());
+  EngineStats::GetInstance()->EngineDestroyed();
   JS_DestroyRuntime(runtime_);
 }
 
diff --git a/src/third_party/mozjs/cobalt_config/include/jscustomallocator.h b/src/third_party/mozjs/cobalt_config/include/jscustomallocator.h
index b8d70d1..4dcd88e 100644
--- a/src/third_party/mozjs/cobalt_config/include/jscustomallocator.h
+++ b/src/third_party/mozjs/cobalt_config/include/jscustomallocator.h
@@ -12,7 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#ifndef gc_JSCUSTOMALLOCATOR_H
+#define gc_JSCUSTOMALLOCATOR_H
+
+#include <algorithm>
+
 #include "jstypes.h"
+#include "memory_allocator_reporter.h"
 #include "starboard/memory.h"
 #include "starboard/string.h"
 
@@ -20,25 +26,58 @@
 #define JS_OOM_POSSIBLY_FAIL_REPORT(cx) do {} while(0)
 
 static JS_INLINE void* js_malloc(size_t bytes) {
-  return SbMemoryAllocate(bytes);
-}
-
-static JS_INLINE void* js_calloc(size_t bytes) {
-  return SbMemoryCalloc(bytes, 1);
+  size_t reservation_bytes = AllocationMetadata::GetReservationBytes(bytes);
+  MemoryAllocatorReporter::Get()->UpdateAllocatedBytes(reservation_bytes);
+  void* metadata = SbMemoryAllocate(reservation_bytes);
+  AllocationMetadata::SetSizeToBaseAddress(metadata, reservation_bytes);
+  return AllocationMetadata::GetUserAddressFromBaseAddress(metadata);
 }
 
 static JS_INLINE void* js_calloc(size_t nmemb, size_t size) {
-  return SbMemoryCalloc(nmemb, size);
+  size_t total_size = nmemb * size;
+  void* memory = js_malloc(total_size);
+  if (memory) {
+    SbMemorySet(memory, 0, total_size);
+  }
+  return memory;
 }
 
-static JS_INLINE void* js_realloc(void* p, size_t bytes) {
-  return SbMemoryReallocate(p, bytes);
+static JS_INLINE void* js_calloc(size_t bytes) {
+  return js_calloc(bytes, 1);
 }
 
 static JS_INLINE void js_free(void* p) {
-  SbMemoryFree(p);
+  if (p == NULL) {
+    return;
+  }
+
+  AllocationMetadata* metadata =
+      AllocationMetadata::GetMetadataFromUserAddress(p);
+  MemoryAllocatorReporter::Get()->UpdateAllocatedBytes(-static_cast<ssize_t>(
+      AllocationMetadata::GetSizeOfAllocationFromMetadata(metadata)));
+  SbMemoryFree(metadata);
+}
+
+static JS_INLINE void* js_realloc(void* p, size_t bytes) {
+  AllocationMetadata* metadata =
+      AllocationMetadata::GetMetadataFromUserAddress(p);
+  size_t current_size =
+      AllocationMetadata::GetSizeOfAllocationFromMetadata(metadata);
+  size_t adjusted_size = AllocationMetadata::GetReservationBytes(bytes);
+
+  MemoryAllocatorReporter::Get()->UpdateAllocatedBytes(
+      static_cast<ssize_t>(adjusted_size - current_size));
+  void* new_ptr = SbMemoryReallocate(metadata, adjusted_size);
+  AllocationMetadata::SetSizeToBaseAddress(new_ptr, adjusted_size);
+  return AllocationMetadata::GetUserAddressFromBaseAddress(new_ptr);
 }
 
 static JS_INLINE char* js_strdup(char* s) {
-  return SbStringDuplicate(s);
+  size_t length = SbStringGetLength(s) + 1;
+
+  char* new_ptr = reinterpret_cast<char*>(js_malloc(length));
+  SbStringCopy(new_ptr, s, length);
+  return new_ptr;
 }
+
+#endif /* gc_JSCUSTOMALLOCATOR_H */
diff --git a/src/third_party/mozjs/js/src/gc/Memory.cpp b/src/third_party/mozjs/js/src/gc/Memory.cpp
index b9e5199..9c55ba1 100644
--- a/src/third_party/mozjs/js/src/gc/Memory.cpp
+++ b/src/third_party/mozjs/js/src/gc/Memory.cpp
@@ -7,6 +7,7 @@
 #include "gc/Memory.h"
 
 #include "jscntxt.h"
+#include "memory_allocator_reporter.h"
 
 #include "js/HeapAPI.h"
 
@@ -324,13 +325,23 @@
     JS_ASSERT(flags == 0);
     JS_ASSERT(fd == -1);
     JS_ASSERT(offset == 0);
-    return SbMemoryMap(length, prot, "mozjs::gc::MapMemory");
+
+    void* result = SbMemoryMap(length, prot, "mozjs::gc::MapMemory");
+    if (result != SB_MEMORY_MAP_FAILED) {
+      MemoryAllocatorReporter::Get()->UpdateMappedBytes(length);
+    }
+    return result;
 }
 
 static inline bool
 UnmapMemory(void* region, size_t length)
 {
-    return SbMemoryUnmap(region, length);
+    bool success = SbMemoryUnmap(region, length);
+    if (success) {
+      MemoryAllocatorReporter::Get()->UpdateMappedBytes(
+          -static_cast<ssize_t>(length));
+    }
+    return success;
 }
 #else
 
diff --git a/src/third_party/mozjs/js/src/jsstarboard-time.cpp b/src/third_party/mozjs/js/src/jsstarboard-time.cpp
index d5049e2..92d309b 100644
--- a/src/third_party/mozjs/js/src/jsstarboard-time.cpp
+++ b/src/third_party/mozjs/js/src/jsstarboard-time.cpp
@@ -15,8 +15,11 @@
 #include "jsstarboard-time.h"
 
 #include "mozilla/Assertions.h"
+#include "starboard/configuration.h"
 #include "unicode/timezone.h"
 
+// If the Starboard platform has this quirk, do not use these functions.
+#if !SB_HAS_QUIRK(NO_TIMEZONE_NAME_SUPPORT)
 SbTime getDSTOffset(int64_t utc_time_us) {
   // UDate is in milliseconds from the epoch.
   UDate udate = utc_time_us / kSbTimeMillisecond;
@@ -41,4 +44,4 @@
   delete current_zone;
   return raw_offset_ms * kSbTimeMillisecond;
 }
-
+#endif
diff --git a/src/third_party/mozjs/js/src/memory_allocator_reporter.cpp b/src/third_party/mozjs/js/src/memory_allocator_reporter.cpp
new file mode 100644
index 0000000..93d42df
--- /dev/null
+++ b/src/third_party/mozjs/js/src/memory_allocator_reporter.cpp
@@ -0,0 +1,83 @@
+// 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 "memory_allocator_reporter.h"
+
+#include "starboard/once.h"
+
+namespace {
+// Control to initialize s_instance.
+SbOnceControl s_instance_control = SB_ONCE_INITIALIZER;
+MemoryAllocatorReporter* s_instance = NULL;
+
+void Initialize() {
+  s_instance = new MemoryAllocatorReporter();
+}
+
+void* OffsetPointer(void* base, ssize_t offset) {
+  uintptr_t base_as_int = reinterpret_cast<uintptr_t>(base);
+  return reinterpret_cast<void*>(base_as_int + offset);
+}
+}  // namespace
+
+AllocationMetadata* AllocationMetadata::GetMetadataFromUserAddress(void* ptr) {
+  if (ptr == NULL) {
+    return NULL;
+  }
+
+  // The metadata lives just in front of the data.
+  void* meta_addr =
+      OffsetPointer(ptr, -static_cast<ssize_t>(sizeof(AllocationMetadata)));
+  return reinterpret_cast<AllocationMetadata*>(meta_addr);
+}
+
+void* AllocationMetadata::GetUserAddressFromBaseAddress(void* base_ptr) {
+  void* adjusted_base =
+      OffsetPointer(base_ptr, static_cast<ssize_t>(sizeof(AllocationMetadata)));
+  return adjusted_base;
+}
+
+void AllocationMetadata::SetSizeToBaseAddress(void* base_ptr, size_t size) {
+  if (base_ptr) {
+    AllocationMetadata* metadata =
+        reinterpret_cast<AllocationMetadata*>(base_ptr);
+    metadata->set_size_requested(size);
+  }
+}
+
+void MemoryAllocatorReporter::UpdateAllocatedBytes(ssize_t bytes) {
+  starboard::ScopedLock lock(mutex_);
+  current_bytes_allocated_ += bytes;
+}
+
+ssize_t MemoryAllocatorReporter::GetCurrentBytesAllocated() {
+  starboard::ScopedLock lock(mutex_);
+  return current_bytes_allocated_;
+}
+
+void MemoryAllocatorReporter::UpdateMappedBytes(ssize_t bytes) {
+  starboard::ScopedLock lock(mutex_);
+  current_bytes_mapped_ += bytes;
+}
+
+ssize_t MemoryAllocatorReporter::GetCurrentBytesMapped() {
+  starboard::ScopedLock lock(mutex_);
+  return current_bytes_mapped_;
+}
+
+// static
+MemoryAllocatorReporter* MemoryAllocatorReporter::Get() {
+  SbOnce(&s_instance_control, &Initialize);
+  return s_instance;
+}
diff --git a/src/third_party/mozjs/js/src/memory_allocator_reporter.h b/src/third_party/mozjs/js/src/memory_allocator_reporter.h
new file mode 100644
index 0000000..e0d679f
--- /dev/null
+++ b/src/third_party/mozjs/js/src/memory_allocator_reporter.h
@@ -0,0 +1,62 @@
+// 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 MemoryAllocatorReporter_h
+#define MemoryAllocatorReporter_h
+
+#include <sys/types.h>
+
+#include "starboard/mutex.h"
+
+class AllocationMetadata {
+ public:
+  static AllocationMetadata* GetMetadataFromUserAddress(void* ptr);
+  static void* GetUserAddressFromBaseAddress(void* base_ptr);
+  static size_t GetReservationBytes(size_t bytes_requested) {
+    return sizeof(AllocationMetadata) + bytes_requested;
+  }
+  static size_t GetSizeOfAllocationFromMetadata(AllocationMetadata* metadata) {
+    return metadata ? metadata->size_requested() : 0;
+  }
+  static void SetSizeToBaseAddress(void* base_ptr, size_t size);
+
+  size_t size_requested() { return size_requested_; }
+  void set_size_requested(size_t size) { size_requested_ = size; }
+
+ private:
+  // Bytes requested by the underlying allocator.
+  size_t size_requested_;
+};
+
+// Reporter that is used to report memory allocation.
+class MemoryAllocatorReporter {
+ public:
+  static MemoryAllocatorReporter* Get();
+
+  MemoryAllocatorReporter()
+      : current_bytes_allocated_(0), current_bytes_mapped_(0) {}
+
+  void UpdateAllocatedBytes(ssize_t bytes);
+  ssize_t GetCurrentBytesAllocated();
+
+  void UpdateMappedBytes(ssize_t bytes);
+  ssize_t GetCurrentBytesMapped();
+
+ private:
+  starboard::Mutex mutex_;
+  ssize_t current_bytes_allocated_;
+  ssize_t current_bytes_mapped_;
+};
+
+#endif /* MemoryAllocatorReporter_h */
diff --git a/src/third_party/mozjs/js/src/vm/DateTime.cpp b/src/third_party/mozjs/js/src/vm/DateTime.cpp
index cfca247..a78a121 100644
--- a/src/third_party/mozjs/js/src/vm/DateTime.cpp
+++ b/src/third_party/mozjs/js/src/vm/DateTime.cpp
@@ -8,8 +8,16 @@
 
 #if defined(STARBOARD)
 #include "jsstarboard-time.h"
+#include "starboard/configuration.h"
 #include "starboard/time_zone.h"
-#else
+// For Starboard platforms that don't have support for getting the timezone
+// name, fall back to using localtime for conversion between UTC<->localtime.
+#if !SB_HAS_QUIRK(NO_TIMEZONE_NAME_SUPPORT)
+#define USE_STARBOARD_TIME
+#endif  // !SB_HAS_QUIRK(NO_TIMEZONE_NAME_SUPPORT)
+#endif  // defined(STARBOARD)
+
+#if !defined(USE_STARBOARD_TIME)
 #include <time.h>
 #endif
 
@@ -17,7 +25,7 @@
 
 using mozilla::UnspecifiedNaN;
 
-#if !defined(STARBOARD)
+#if !defined(USE_STARBOARD_TIME)
 static bool
 ComputeLocalTime(time_t local, struct tm *ptm)
 {
@@ -131,7 +139,7 @@
     // local seconds' frame of reference and then subtract.
     return local_secs - (utc_secs + SecondsPerDay);
 }
-#endif  // defined(STARBOARD)
+#endif  // defined(USE_STARBOARD_TIME)
 
 void
 js::DateTimeInfo::updateTimeZoneAdjustment()
@@ -140,7 +148,7 @@
      * The difference between local standard time and UTC will never change for
      * a given time zone.
      */
-#if defined(STARBOARD)
+#if defined(USE_STARBOARD_TIME)
     utcToLocalStandardOffsetSeconds = getTZOffset() / kSbTimeSecond;
 #else
     utcToLocalStandardOffsetSeconds = UTCToLocalStandardOffsetSeconds();
@@ -179,7 +187,7 @@
     updateTimeZoneAdjustment();
 }
 
-#if defined(STARBOARD)
+#if defined(USE_STARBOARD_TIME)
 int64_t
 js::DateTimeInfo::computeDSTOffsetMilliseconds(int64_t utcSeconds)
 {
@@ -219,7 +227,7 @@
 
     return diff * msPerSecond;
 }
-#endif  // defined(STARBOARD)
+#endif  // defined(USE_STARBOARD_TIME)
 
 int64_t
 js::DateTimeInfo::getDSTOffsetMilliseconds(int64_t utcMilliseconds)
diff --git a/src/third_party/mozjs/mozjs.gypi b/src/third_party/mozjs/mozjs.gypi
index 9fb9822..6b85ee0 100644
--- a/src/third_party/mozjs/mozjs.gypi
+++ b/src/third_party/mozjs/mozjs.gypi
@@ -82,6 +82,7 @@
       'js/src/jsweakmap.cpp',
       'js/src/jsworkers.cpp',
       'js/src/jswrapper.cpp',
+      'js/src/memory_allocator_reporter.cpp',
       'js/src/perf/jsperf.cpp',
       'js/src/perf/pm_stub.cpp',
       'js/src/prmjtime.cpp',
diff --git a/src/third_party/mozjs/test/jscustomallocator_test.cc b/src/third_party/mozjs/test/jscustomallocator_test.cc
new file mode 100644
index 0000000..e6702e1
--- /dev/null
+++ b/src/third_party/mozjs/test/jscustomallocator_test.cc
@@ -0,0 +1,178 @@
+/*
+ * 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 "jscustomallocator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const size_t kSize = 1024 * 128;
+
+TEST(JSCustomallocator, JSMalloc) {
+  void* memory = js_malloc(kSize);
+  EXPECT_NE(static_cast<void*>(NULL), memory);
+  ssize_t current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated,
+            AllocationMetadata::GetReservationBytes(kSize));
+  js_free(memory);
+  current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated, 0);
+}
+
+TEST(JSCustomallocator, JSCallocWithNumber) {
+  void* memory = js_calloc(5, kSize);
+  EXPECT_NE(static_cast<void*>(NULL), memory);
+  ssize_t current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated,
+            AllocationMetadata::GetReservationBytes(5 * kSize));
+  js_free(memory);
+  current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated, 0);
+}
+
+TEST(JSCustomallocator, JSCalloc) {
+  void* memory = js_calloc(kSize);
+  EXPECT_NE(static_cast<void*>(NULL), memory);
+  ssize_t current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated,
+            AllocationMetadata::GetReservationBytes(kSize));
+  js_free(memory);
+  current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated, 0);
+}
+
+TEST(JSCustomallocator, JSReallocSmaller) {
+  void* memory = js_malloc(kSize);
+  ASSERT_NE(static_cast<void*>(NULL), memory);
+  char* data = static_cast<char*>(memory);
+  for (int i = 0; i < kSize; ++i) {
+    data[i] = i;
+  }
+
+  for (int i = 0; i < kSize; ++i) {
+    EXPECT_EQ(data[i], static_cast<char>(i));
+  }
+
+  ssize_t current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated,
+            AllocationMetadata::GetReservationBytes(kSize));
+
+  memory = js_realloc(memory, kSize / 2);
+  data = static_cast<char*>(memory);
+  ASSERT_NE(static_cast<void*>(NULL), memory);
+  for (int i = 0; i < kSize / 2; ++i) {
+    EXPECT_EQ(data[i], static_cast<char>(i));
+  }
+
+  current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated,
+            AllocationMetadata::GetReservationBytes(kSize / 2));
+
+  js_free(memory);
+
+  current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated, 0);
+}
+
+TEST(JSCustomallocator, JSReallocBigger) {
+  void* memory = js_malloc(kSize);
+  ASSERT_NE(static_cast<void*>(NULL), memory);
+  char* data = static_cast<char*>(memory);
+  for (int i = 0; i < kSize; ++i) {
+    data[i] = i;
+  }
+
+  for (int i = 0; i < kSize; ++i) {
+    EXPECT_EQ(data[i], static_cast<char>(i));
+  }
+
+  ssize_t current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated,
+            AllocationMetadata::GetReservationBytes(kSize));
+
+  memory = js_realloc(memory, kSize * 2);
+  ASSERT_NE(static_cast<void*>(NULL), memory);
+  data = static_cast<char*>(memory);
+  for (int i = 0; i < kSize; ++i) {
+    EXPECT_EQ(data[i], static_cast<char>(i));
+  }
+
+  for (int i = kSize; i < kSize * 2; ++i) {
+    data[i] = i;
+  }
+
+  for (int i = kSize; i < kSize * 2; ++i) {
+    EXPECT_EQ(data[i], static_cast<char>(i));
+  }
+
+  current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated,
+            AllocationMetadata::GetReservationBytes(kSize * 2));
+
+  js_free(memory);
+
+  current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated, 0);
+}
+
+TEST(JSCustomallocator, JSReallocNULL) {
+  void* memory = js_realloc(NULL, kSize);
+  EXPECT_NE(static_cast<void*>(NULL), memory);
+  ssize_t current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated,
+            AllocationMetadata::GetReservationBytes(kSize));
+
+  js_free(memory);
+
+  current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated, 0);
+}
+
+TEST(JSCustomallocator, JSStrdup) {
+  const char* input = "abcedfg123456";
+  char* dupe = js_strdup(const_cast<char*>(input));
+  const char* kNull = NULL;
+  EXPECT_NE(kNull, dupe);
+  EXPECT_EQ(0, SbStringCompareNoCase(input, dupe));
+  EXPECT_EQ(SbStringGetLength(input), SbStringGetLength(dupe));
+
+  ssize_t current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated, AllocationMetadata::GetReservationBytes(
+                                         SbStringGetLength(dupe) + 1));
+
+  js_free(dupe);
+
+  current_bytes_allocated =
+      MemoryAllocatorReporter::Get()->GetCurrentBytesAllocated();
+  EXPECT_EQ(current_bytes_allocated, 0);
+}
+
+}  // namespace
diff --git a/src/third_party/skia/gyp/gpu.gypi b/src/third_party/skia/gyp/gpu.gypi
index ebc07b2..eaaf5d0 100644
--- a/src/third_party/skia/gyp/gpu.gypi
+++ b/src/third_party/skia/gyp/gpu.gypi
@@ -6,6 +6,10 @@
 # The skia build defines these in common_variables.gypi
 #
 {
+  'defines': [
+    'COBALT_SKIA_GLYPH_ATLAS_WIDTH=<(skia_glyph_atlas_width)',
+    'COBALT_SKIA_GLYPH_ATLAS_HEIGHT=<(skia_glyph_atlas_height)',
+  ],
   'variables': {
     'skgpu_sources': [
       '<(skia_include_path)/gpu/GrBackendProcessorFactory.h',
diff --git a/src/third_party/skia/src/gpu/GrTextStrike.cpp b/src/third_party/skia/src/gpu/GrTextStrike.cpp
index 66aeee0..ef1bf64 100644
--- a/src/third_party/skia/src/gpu/GrTextStrike.cpp
+++ b/src/third_party/skia/src/gpu/GrTextStrike.cpp
@@ -19,8 +19,8 @@
 
 // On Cobalt we would like to avoid re-rasterizing glyphs as much as possible,
 // so increase the default atlas size.
-#define GR_ATLAS_TEXTURE_WIDTH 2048
-#define GR_ATLAS_TEXTURE_HEIGHT 2048
+#define GR_ATLAS_TEXTURE_WIDTH COBALT_SKIA_GLYPH_ATLAS_WIDTH
+#define GR_ATLAS_TEXTURE_HEIGHT COBALT_SKIA_GLYPH_ATLAS_HEIGHT
 
 // On Cobalt, not being able to fit glyphs into the atlas is a big penalty,
 // since its software rendering is not optimized.  Increase the plot size