Import Cobalt 4.13110
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 5ee42a0..29a4b1d 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -615,9 +615,6 @@
   // Stop the generation of render trees.
   layout_manager_->Suspend();
 
-  // Clear out all image resources from the image cache.
-  image_cache_->Purge();
-
 #if defined(ENABLE_DEBUG_CONSOLE)
   // The debug overlay may be holding onto a render tree, clear that out.
   debug_overlay_->ClearInput();
@@ -627,6 +624,17 @@
   // in-progress loads.
   loader_factory_->Suspend();
 
+  // Ensure the document is not holding onto any more image cached resources so
+  // that they are eligible to be purged.
+  window_->document()->PurgeCachedResourceReferencesRecursively();
+
+  // Clear out all image resources from the image cache. We need to do this
+  // after we abort all in-progress loads, and after we clear all document
+  // references, or they will still be referenced and won't be cleared from the
+  // cache.
+  image_cache_->Purge();
+  remote_typeface_cache_->Purge();
+
   // Finally mark that we have no resource provider.
   resource_provider_ = NULL;
 }
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index ec9b96f..d5688f5 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-13031
\ No newline at end of file
+13110
\ No newline at end of file
diff --git a/src/cobalt/dom/html_element.h b/src/cobalt/dom/html_element.h
index 33ffb9a..4aad8a2 100644
--- a/src/cobalt/dom/html_element.h
+++ b/src/cobalt/dom/html_element.h
@@ -261,6 +261,10 @@
 
   void CopyDirectionality(const HTMLElement& other);
 
+  // Releases image resources and invalidates computed style if there are images
+  // associated with this html element in the image cache.
+  void ReleaseImagesAndInvalidateComputedStyleIfNecessary() OVERRIDE;
+
  private:
   // From Node.
   void OnMutation() OVERRIDE;
@@ -289,10 +293,6 @@
   // https://www.w3.org/TR/html5/semantics.html#the-root-element.
   bool IsRootElement();
 
-  // Releases image resources and invalidates computed style if there are images
-  // associated with this html element in the image cache.
-  void ReleaseImagesAndInvalidateComputedStyleIfNecessary();
-
   // The directionality of the html element is determined by the 'dir'
   // attribute.
   // https://dev.w3.org/html5/spec-preview/global-attributes.html#the-directionality
diff --git a/src/cobalt/dom/node.cc b/src/cobalt/dom/node.cc
index 6ce2955..cac03aa 100644
--- a/src/cobalt/dom/node.cc
+++ b/src/cobalt/dom/node.cc
@@ -467,6 +467,16 @@
   }
 }
 
+void Node::PurgeCachedResourceReferencesRecursively() {
+  ReleaseImagesAndInvalidateComputedStyleIfNecessary();
+
+  Node* child = first_child_;
+  while (child) {
+    child->PurgeCachedResourceReferencesRecursively();
+    child = child->next_sibling_;
+  }
+}
+
 void Node::InvalidateLayoutBoxesFromNodeAndAncestors() {
   if (parent_) {
     parent_->InvalidateLayoutBoxesFromNodeAndAncestors();
diff --git a/src/cobalt/dom/node.h b/src/cobalt/dom/node.h
index 0c2a4f6..7e349d6 100644
--- a/src/cobalt/dom/node.h
+++ b/src/cobalt/dom/node.h
@@ -218,6 +218,10 @@
 
   virtual scoped_refptr<Node> Duplicate() const = 0;
 
+  // Purges all cached resource reference from the current node and all
+  // descendents.
+  void PurgeCachedResourceReferencesRecursively();
+
   DEFINE_WRAPPABLE_TYPE(Node);
 
  protected:
@@ -244,6 +248,10 @@
   // Invalidate the render tree nodes within the layout boxes of this node.
   virtual void InvalidateRenderTreeNodesFromNode() {}
 
+  // Releases image resources and invalidates computed style if there are images
+  // associated with this html element in the image cache.
+  virtual void ReleaseImagesAndInvalidateComputedStyleIfNecessary() {}
+
   // Triggers a generation update in this node and all its ancestor nodes.
   void UpdateGenerationForNodeAndAncestors();
 
diff --git a/src/cobalt/dom_parser/html_decoder.h b/src/cobalt/dom_parser/html_decoder.h
index db142e7..cf57cf9 100644
--- a/src/cobalt/dom_parser/html_decoder.h
+++ b/src/cobalt/dom_parser/html_decoder.h
@@ -20,6 +20,7 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/threading/thread_checker.h"
@@ -60,6 +61,11 @@
       const scoped_refptr<net::HttpResponseHeaders>& headers) OVERRIDE;
   void DecodeChunk(const char* data, size_t size) OVERRIDE;
   void Finish() OVERRIDE;
+  bool Suspend() OVERRIDE { return false; }
+
+  void Resume(render_tree::ResourceProvider* /*resource_provider*/) OVERRIDE {
+    NOTIMPLEMENTED();
+  };
 
  private:
   // This subclass is responsible for providing the handlers for the interface
diff --git a/src/cobalt/dom_parser/xml_decoder.h b/src/cobalt/dom_parser/xml_decoder.h
index 1be11a7..2ee38e4 100644
--- a/src/cobalt/dom_parser/xml_decoder.h
+++ b/src/cobalt/dom_parser/xml_decoder.h
@@ -52,6 +52,11 @@
   // From Decoder.
   void DecodeChunk(const char* data, size_t size) OVERRIDE;
   void Finish() OVERRIDE;
+  bool Suspend() OVERRIDE { return false; }
+
+  void Resume(render_tree::ResourceProvider* /*resource_provider*/) OVERRIDE {
+    NOTIMPLEMENTED();
+  };
 
  private:
   // This subclass is responsible for providing the handlers for the interface
diff --git a/src/cobalt/loader/decoder.h b/src/cobalt/loader/decoder.h
index f307097..bdd4040 100644
--- a/src/cobalt/loader/decoder.h
+++ b/src/cobalt/loader/decoder.h
@@ -18,6 +18,7 @@
 #define COBALT_LOADER_DECODER_H_
 
 #include "cobalt/loader/loader_types.h"
+#include "cobalt/render_tree/resource_provider.h"
 #include "net/http/http_response_headers.h"
 
 namespace cobalt {
@@ -45,7 +46,13 @@
   // This is called when all data are sent in and decoding should be finalized.
   virtual void Finish() = 0;
 
-  virtual void Abort() { NOTREACHED() << "Abort not supported."; }
+  // Suspends the decode of this resource, resetting internal state. Returns
+  // whether the decoder was reset correctly. If not, the load will have to be
+  // aborted.
+  virtual bool Suspend() = 0;
+
+  // Resumes the decode of this resource, starting over from the zero state.
+  virtual void Resume(render_tree::ResourceProvider* resource_provider) = 0;
 };
 
 }  // namespace loader
diff --git a/src/cobalt/loader/fetcher_factory.cc b/src/cobalt/loader/fetcher_factory.cc
index 81b7d2f..e16c970 100644
--- a/src/cobalt/loader/fetcher_factory.cc
+++ b/src/cobalt/loader/fetcher_factory.cc
@@ -44,6 +44,16 @@
   *file_path = FilePath(path);
   return !file_path->empty();
 }
+
+std::string ClipUrl(const GURL& url, size_t length) {
+  const std::string& spec = url.possibly_invalid_spec();
+  if (spec.size() < length) {
+    return spec;
+  }
+
+  return spec.substr(0, length - 5) + "[...]";
+}
+
 }  // namespace
 
 FetcherFactory::FetcherFactory(network::NetworkModule* network_module)
@@ -72,6 +82,7 @@
     return scoped_ptr<Fetcher>(NULL);
   }
 
+  DLOG(INFO) << "Fetching: " << ClipUrl(url, 60);
   scoped_ptr<Fetcher> fetcher;
   if (url.SchemeIs(kEmbeddedScheme)) {
     EmbeddedFetcher::Options options;
diff --git a/src/cobalt/loader/font/typeface_decoder.cc b/src/cobalt/loader/font/typeface_decoder.cc
index 2f7556d..9d2e6db 100644
--- a/src/cobalt/loader/font/typeface_decoder.cc
+++ b/src/cobalt/loader/font/typeface_decoder.cc
@@ -29,7 +29,7 @@
       success_callback_(success_callback),
       error_callback_(error_callback),
       is_raw_data_too_large_(false),
-      aborted_(false) {
+      suspended_(false) {
   UNREFERENCED_PARAMETER(failure_callback);
 
   DCHECK(resource_provider_);
@@ -38,6 +38,11 @@
 }
 
 void TypefaceDecoder::DecodeChunk(const char* data, size_t size) {
+  if (suspended_) {
+    DLOG(WARNING) << __FUNCTION__ << "[" << this << "] while suspended.";
+    return;
+  }
+
   // If the data was already too large, then there's no need to process this
   // chunk. Just early out.
   if (is_raw_data_too_large_) {
@@ -65,16 +70,16 @@
 }
 
 void TypefaceDecoder::Finish() {
+  if (suspended_) {
+    DLOG(WARNING) << __FUNCTION__ << "[" << this << "] while suspended.";
+    return;
+  }
+
   if (is_raw_data_too_large_) {
     error_callback_.Run("Raw typeface data size too large");
     return;
   }
 
-  if (aborted_) {
-    error_callback_.Run(
-        "TypefaceDecoder's ResourceProvider has been externally aborted.");
-    return;
-  }
   if (!resource_provider_) {
     error_callback_.Run(
         "No resource provider was passed to the TypefaceDecoder.");
@@ -95,7 +100,24 @@
 
 void TypefaceDecoder::ReleaseRawData() { raw_data_.reset(); }
 
-void TypefaceDecoder::Abort() { aborted_ = true; }
+bool TypefaceDecoder::Suspend() {
+  DCHECK(!suspended_);
+  suspended_ = true;
+  is_raw_data_too_large_ = false;
+  resource_provider_ = NULL;
+  ReleaseRawData();
+  return true;
+}
+
+void TypefaceDecoder::Resume(render_tree::ResourceProvider* resource_provider) {
+  if (!suspended_) {
+    DCHECK_EQ(resource_provider_, resource_provider);
+    return;
+  }
+
+  suspended_ = false;
+  resource_provider_ = resource_provider;
+}
 
 }  // namespace font
 }  // namespace loader
diff --git a/src/cobalt/loader/font/typeface_decoder.h b/src/cobalt/loader/font/typeface_decoder.h
index 4af8965..83ed308 100644
--- a/src/cobalt/loader/font/typeface_decoder.h
+++ b/src/cobalt/loader/font/typeface_decoder.h
@@ -47,20 +47,20 @@
   // From Decoder.
   void DecodeChunk(const char* data, size_t size) OVERRIDE;
   void Finish() OVERRIDE;
-
-  void Abort() OVERRIDE;
+  bool Suspend() OVERRIDE;
+  void Resume(render_tree::ResourceProvider* resource_provider) OVERRIDE;
 
  private:
   void ReleaseRawData();
 
-  render_tree::ResourceProvider* const resource_provider_;
+  render_tree::ResourceProvider* resource_provider_;
   const SuccessCallback success_callback_;
   const ErrorCallback error_callback_;
 
   scoped_ptr<render_tree::ResourceProvider::RawTypefaceDataVector> raw_data_;
   bool is_raw_data_too_large_;
 
-  bool aborted_;
+  bool suspended_;
 };
 
 }  // namespace font
diff --git a/src/cobalt/loader/font/typeface_decoder_test.cc b/src/cobalt/loader/font/typeface_decoder_test.cc
index 9b767d6..4d12892 100644
--- a/src/cobalt/loader/font/typeface_decoder_test.cc
+++ b/src/cobalt/loader/font/typeface_decoder_test.cc
@@ -54,6 +54,8 @@
   void DecodeChunk(const char* data, size_t size) OVERRIDE;
 
   void Finish() OVERRIDE;
+  bool Suspend() OVERRIDE;
+  void Resume(render_tree::ResourceProvider* resource_provider) OVERRIDE;
 
   scoped_refptr<render_tree::Typeface> Typeface();
 
@@ -83,6 +85,13 @@
 
 void MockTypefaceDecoder::Finish() { typeface_decoder_->Finish(); }
 
+bool MockTypefaceDecoder::Suspend() { return typeface_decoder_->Suspend(); }
+
+void MockTypefaceDecoder::Resume(
+    render_tree::ResourceProvider* resource_provider) {
+  typeface_decoder_->Resume(resource_provider);
+}
+
 scoped_refptr<render_tree::Typeface> MockTypefaceDecoder::Typeface() {
   return typeface_decoder_callback_.typeface;
 }
diff --git a/src/cobalt/loader/image/image_decoder.cc b/src/cobalt/loader/image/image_decoder.cc
index 24a8f9b..5161dd3 100644
--- a/src/cobalt/loader/image/image_decoder.cc
+++ b/src/cobalt/loader/image/image_decoder.cc
@@ -71,6 +71,11 @@
     Fetcher* fetcher, const scoped_refptr<net::HttpResponseHeaders>& headers) {
   UNREFERENCED_PARAMETER(fetcher);
 
+  if (state_ == kSuspended) {
+    DLOG(WARNING) << __FUNCTION__ << "[" << this << "] while suspended.";
+    return kLoadResponseContinue;
+  }
+
   if (headers->response_code() == net::HTTP_OK &&
       headers->GetContentLength() == 0) {
     // The server successfully processed the request and expected some contents,
@@ -137,8 +142,8 @@
     case kNoResourceProvider:
       failure_callback_.Run("No resource provider was passed to the decoder.");
       break;
-    case kAborted:
-      error_callback_.Run("ImageDecoder received an external signal to abort.");
+    case kSuspended:
+      DLOG(WARNING) << __FUNCTION__ << "[" << this << "] while suspended.";
       break;
     case kNotApplicable:
       // no image is available.
@@ -147,13 +152,28 @@
   }
 }
 
-void ImageDecoder::Abort() {
+bool ImageDecoder::Suspend() {
   if (state_ == kDecoding) {
     DCHECK(decoder_);
     decoder_.reset();
-    state_ = kAborted;
-  } else if (state_ == kWaitingForHeader) {
-    state_ = kAborted;
+  }
+  state_ = kSuspended;
+  signature_cache_.position = 0;
+  resource_provider_ = NULL;
+  return true;
+}
+
+void ImageDecoder::Resume(render_tree::ResourceProvider* resource_provider) {
+  if (state_ != kSuspended) {
+    DCHECK_EQ(resource_provider_, resource_provider);
+    return;
+  }
+
+  state_ = kWaitingForHeader;
+  resource_provider_ = resource_provider;
+
+  if (!resource_provider_) {
+    state_ = kNoResourceProvider;
   }
 }
 
@@ -182,7 +202,7 @@
     } break;
     case kNotApplicable:
     case kUnsupportedImageFormat:
-    case kAborted:
+    case kSuspended:
     case kNoResourceProvider:
     default: {
       // Do not attempt to continue processing data.
diff --git a/src/cobalt/loader/image/image_decoder.h b/src/cobalt/loader/image/image_decoder.h
index be6e056..610d27b 100644
--- a/src/cobalt/loader/image/image_decoder.h
+++ b/src/cobalt/loader/image/image_decoder.h
@@ -52,8 +52,8 @@
       const scoped_refptr<net::HttpResponseHeaders>& headers) OVERRIDE;
   void DecodeChunk(const char* data, size_t size) OVERRIDE;
   void Finish() OVERRIDE;
-
-  void Abort() OVERRIDE;
+  bool Suspend() OVERRIDE;
+  void Resume(render_tree::ResourceProvider* resource_provider) OVERRIDE;
 
   // Call this function to use the StubImageDecoder which produces a small image
   // without decoding.
@@ -66,7 +66,7 @@
     kNotApplicable,
     kUnsupportedImageFormat,
     kNoResourceProvider,
-    kAborted,
+    kSuspended,
   };
 
   // The current longest signature is WEBP signature.
@@ -81,7 +81,7 @@
   bool InitializeInternalDecoder(const uint8* input_bytes, size_t size,
                                  size_t* consumed_size);
 
-  render_tree::ResourceProvider* const resource_provider_;
+  render_tree::ResourceProvider* resource_provider_;
   const SuccessCallback success_callback_;
   const FailureCallback failure_callback_;
   const ErrorCallback error_callback_;
diff --git a/src/cobalt/loader/image/image_decoder_test.cc b/src/cobalt/loader/image/image_decoder_test.cc
index 59c1d38..dafc54b 100644
--- a/src/cobalt/loader/image/image_decoder_test.cc
+++ b/src/cobalt/loader/image/image_decoder_test.cc
@@ -58,6 +58,8 @@
   void DecodeChunk(const char* data, size_t size) OVERRIDE;
 
   void Finish() OVERRIDE;
+  bool Suspend() OVERRIDE;
+  void Resume(render_tree::ResourceProvider* resource_provider) OVERRIDE;
 
   scoped_refptr<render_tree::Image> Image();
 
@@ -92,6 +94,13 @@
 
 void MockImageDecoder::Finish() { image_decoder_->Finish(); }
 
+bool MockImageDecoder::Suspend() { return image_decoder_->Suspend(); }
+
+void MockImageDecoder::Resume(
+    render_tree::ResourceProvider* resource_provider) {
+  image_decoder_->Resume(resource_provider);
+}
+
 scoped_refptr<render_tree::Image> MockImageDecoder::Image() {
   return image_decoder_callback_.image;
 }
diff --git a/src/cobalt/loader/loader.cc b/src/cobalt/loader/loader.cc
index 90e6bfe..a5d86e7 100644
--- a/src/cobalt/loader/loader.cc
+++ b/src/cobalt/loader/loader.cc
@@ -70,23 +70,23 @@
 //////////////////////////////////////////////////////////////////
 
 Loader::Loader(const FetcherCreator& fetcher_creator,
-               scoped_ptr<Decoder> decoder,
-               const base::Callback<void(const std::string&)>& error_callback,
+               scoped_ptr<Decoder> decoder, const OnErrorFunction& on_error,
                const OnDestructionFunction& on_destruction)
-    : decoder_(decoder.Pass()),
-      fetcher_to_decoder_adaptor_(
-          new FetcherToDecoderAdapter(decoder_.get(), error_callback)),
-      fetcher_(fetcher_creator.Run(fetcher_to_decoder_adaptor_.get())),
-      on_destruction_(on_destruction) {
+    : fetcher_creator_(fetcher_creator),
+      decoder_(decoder.Pass()),
+      on_error_(on_error),
+      on_destruction_(on_destruction),
+      suspended_(false) {
   DCHECK(decoder_);
-  DCHECK(!error_callback.is_null());
-  DCHECK(!fetcher_creator.is_null());
+  DCHECK(!on_error.is_null());
+
+  Start();
 
   // Post the error callback on the current message loop in case loader is
   // destroyed in the callback.
   if (!fetcher_) {
     fetcher_creator_error_closure_.Reset(
-        base::Bind(error_callback, "Fetcher was not created."));
+        base::Bind(on_error, "Fetcher was not created."));
     MessageLoop::current()->PostTask(FROM_HERE,
                                      fetcher_creator_error_closure_.callback());
   }
@@ -101,7 +101,44 @@
   fetcher_creator_error_closure_.Cancel();
 }
 
-void Loader::Abort() { decoder_->Abort(); }
+void Loader::Suspend() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (suspended_) {
+    return;
+  }
+
+  bool suspendable = decoder_->Suspend();
+  if (fetcher_) {
+    fetcher_.reset();
+  }
+
+  fetcher_to_decoder_adaptor_.reset();
+  fetcher_creator_error_closure_.Cancel();
+  suspended_ = true;
+
+  if (!suspendable) {
+    on_error_.Run("Aborted.");
+  }
+}
+
+void Loader::Resume(render_tree::ResourceProvider* resource_provider) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (!suspended_) {
+    return;
+  }
+  suspended_ = false;
+  decoder_->Resume(resource_provider);
+  Start();
+}
+
+void Loader::Start() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(decoder_);
+  DCHECK(!fetcher_creator_.is_null());
+  fetcher_to_decoder_adaptor_.reset(
+      new FetcherToDecoderAdapter(decoder_.get(), on_error_));
+  fetcher_ = fetcher_creator_.Run(fetcher_to_decoder_adaptor_.get());
+}
 
 }  // namespace loader
 }  // namespace cobalt
diff --git a/src/cobalt/loader/loader.h b/src/cobalt/loader/loader.h
index 43da425..1a1bd1e 100644
--- a/src/cobalt/loader/loader.h
+++ b/src/cobalt/loader/loader.h
@@ -26,6 +26,7 @@
 #include "base/threading/thread_checker.h"
 #include "cobalt/loader/decoder.h"
 #include "cobalt/loader/fetcher.h"
+#include "cobalt/render_tree/resource_provider.h"
 
 namespace cobalt {
 namespace loader {
@@ -38,6 +39,7 @@
  public:
   typedef base::Callback<scoped_ptr<Fetcher>(Fetcher::Handler*)> FetcherCreator;
   typedef base::Callback<void(Loader*)> OnDestructionFunction;
+  typedef base::Callback<void(const std::string&)> OnErrorFunction;
 
   // The construction of Loader initiates the loading. It takes the ownership
   // of a Decoder and creates and manages a Fetcher using the given creation
@@ -45,16 +47,26 @@
   // The fetcher creator, decoder and error callback shouldn't be NULL.
   // It is allowed to destroy the loader in the error callback.
   Loader(const FetcherCreator& fetcher_creator, scoped_ptr<Decoder> decoder,
-         const base::Callback<void(const std::string&)>& error_callback,
+         const OnErrorFunction& on_error,
          const OnDestructionFunction& on_destruction = OnDestructionFunction());
 
   ~Loader();
 
-  void Abort();
+  // Suspends the load of this resource, expecting it to be resumed or destroyed
+  // later.
+  void Suspend();
+
+  // Resumes the load of this resource. Suspend must have been previously
+  // called.
+  void Resume(render_tree::ResourceProvider* resource_provider);
 
  private:
   class FetcherToDecoderAdapter;
 
+  // Starts the fetch-and-decode.
+  void Start();
+
+  FetcherCreator fetcher_creator_;
   scoped_ptr<Decoder> decoder_;
   scoped_ptr<FetcherToDecoderAdapter> fetcher_to_decoder_adaptor_;
   scoped_ptr<Fetcher> fetcher_;
@@ -62,8 +74,11 @@
   base::CancelableClosure fetcher_creator_error_closure_;
   base::ThreadChecker thread_checker_;
 
+  OnErrorFunction on_error_;
   OnDestructionFunction on_destruction_;
 
+  bool suspended_;
+
   DISALLOW_COPY_AND_ASSIGN(Loader);
 };
 
diff --git a/src/cobalt/loader/loader_factory.cc b/src/cobalt/loader/loader_factory.cc
index 9356c00..e39a512 100644
--- a/src/cobalt/loader/loader_factory.cc
+++ b/src/cobalt/loader/loader_factory.cc
@@ -76,7 +76,7 @@
   resource_provider_ = NULL;
   for (LoaderSet::const_iterator iter = active_loaders_.begin();
        iter != active_loaders_.end(); ++iter) {
-    (*iter)->Abort();
+    (*iter)->Suspend();
   }
 }
 
@@ -86,6 +86,10 @@
   DCHECK(!resource_provider_);
 
   resource_provider_ = resource_provider;
+  for (LoaderSet::const_iterator iter = active_loaders_.begin();
+       iter != active_loaders_.end(); ++iter) {
+    (*iter)->Resume(resource_provider);
+  }
 }
 
 void LoaderFactory::OnLoaderCreated(Loader* loader) {
diff --git a/src/cobalt/loader/loader_test.cc b/src/cobalt/loader/loader_test.cc
index f3be464..c7e637c 100644
--- a/src/cobalt/loader/loader_test.cc
+++ b/src/cobalt/loader/loader_test.cc
@@ -73,33 +73,47 @@
 // Mocks & Stubs
 //////////////////////////////////////////////////////////////////////////
 
-class StubFetcherError : public Fetcher {
- public:
-  explicit StubFetcherError(Handler* handler) : Fetcher(handler) {
-    handler->OnError(this, "Fake error for test");
-  }
-
-  static scoped_ptr<Fetcher> Create(Handler* handler) {
-    return scoped_ptr<Fetcher>(new StubFetcherError(handler));
-  }
-};
-
-class StubFetcherReceivedDone : public Fetcher {
- public:
-  explicit StubFetcherReceivedDone(Handler* handler) : Fetcher(handler) {
-    handler->OnReceived(this, NULL, 0);
-    handler->OnDone(this);
-  }
-
-  static scoped_ptr<Fetcher> Create(Handler* handler) {
-    return scoped_ptr<Fetcher>(new StubFetcherReceivedDone(handler));
-  }
-};
-
 class MockDecoder : public Decoder {
  public:
   MOCK_METHOD2(DecodeChunk, void(const char*, size_t));
   MOCK_METHOD0(Finish, void());
+  MOCK_METHOD0(Suspend, bool());
+  MOCK_METHOD1(Resume, void(render_tree::ResourceProvider*));
+};
+
+class MockFetcher : public Fetcher {
+ public:
+  explicit MockFetcher(Handler* handler) : Fetcher(handler) {}
+
+  void FireError(const char* message) { handler()->OnError(this, message); }
+
+  void FireReceived(const char* data, size_t size) {
+    handler()->OnReceived(this, data, size);
+  }
+
+  void FireDone() { handler()->OnDone(this); }
+
+  static scoped_ptr<Fetcher> Create(Handler* handler) {
+    return scoped_ptr<Fetcher>(new MockFetcher(handler));
+  }
+};
+
+struct MockFetcherFactory {
+ public:
+  MockFetcherFactory(): count(0) {}
+  // Way to access the last fetcher created by the fetcher factory.
+  MockFetcher* fetcher;
+  int count;
+
+  scoped_ptr<Fetcher> Create(Fetcher::Handler* handler) {
+    fetcher = new MockFetcher(handler);
+    ++count;
+    return scoped_ptr<Fetcher>(fetcher);
+  }
+
+  Loader::FetcherCreator GetFetcherCreator() {
+    return base::Bind(&MockFetcherFactory::Create, base::Unretained(this));
+  }
 };
 
 class MockLoaderCallback : public LoaderCallback {
@@ -138,30 +152,77 @@
 
 TEST_F(LoaderTest, FetcherError) {
   MockLoaderCallback mock_loader_callback;
+  MockFetcherFactory mock_fetcher_factory;
   MockDecoder* mock_decoder = new MockDecoder();  // To be owned by loader.
   EXPECT_CALL(*mock_decoder, DecodeChunk(_, _)).Times(0);
   EXPECT_CALL(*mock_decoder, Finish()).Times(0);
   EXPECT_CALL(mock_loader_callback, OnError(_));
 
-  Loader loader(base::Bind(&StubFetcherError::Create),
+  Loader loader(mock_fetcher_factory.GetFetcherCreator(),
                 scoped_ptr<Decoder>(mock_decoder),
                 base::Bind(&MockLoaderCallback::OnError,
                            base::Unretained(&mock_loader_callback)));
+  mock_fetcher_factory.fetcher->FireError("Fail");
+}
+
+TEST_F(LoaderTest, FetcherSuspendAbort) {
+  MockLoaderCallback mock_loader_callback;
+  MockFetcherFactory mock_fetcher_factory;
+  MockDecoder* mock_decoder = new MockDecoder();  // To be owned by loader.
+  EXPECT_CALL(*mock_decoder, DecodeChunk(_, _)).Times(0);
+  EXPECT_CALL(*mock_decoder, Finish()).Times(0);
+  EXPECT_CALL(*mock_decoder, Suspend());
+  EXPECT_CALL(*mock_decoder, Resume(_)).Times(0);
+  EXPECT_CALL(mock_loader_callback, OnError(_));
+
+  Loader loader(mock_fetcher_factory.GetFetcherCreator(),
+                scoped_ptr<Decoder>(mock_decoder),
+                base::Bind(&MockLoaderCallback::OnError,
+                           base::Unretained(&mock_loader_callback)));
+  loader.Suspend();
+}
+
+TEST_F(LoaderTest, FetcherSuspendResumeDone) {
+  MockLoaderCallback mock_loader_callback;
+  MockFetcherFactory mock_fetcher_factory;
+  MockDecoder* mock_decoder = new MockDecoder();  // To be owned by loader.
+  ON_CALL(*mock_decoder, Suspend()).WillByDefault(testing::Return(true));
+
+  EXPECT_CALL(*mock_decoder, Suspend());
+  EXPECT_CALL(*mock_decoder, Resume(_));
+
+  EXPECT_CALL(*mock_decoder, DecodeChunk(_, _)).Times(0);
+  EXPECT_CALL(mock_loader_callback, OnError(_)).Times(0);
+  EXPECT_CALL(*mock_decoder, Finish());
+
+  Loader loader(mock_fetcher_factory.GetFetcherCreator(),
+                scoped_ptr<Decoder>(mock_decoder),
+                base::Bind(&MockLoaderCallback::OnError,
+                           base::Unretained(&mock_loader_callback)));
+  loader.Suspend();
+  loader.Resume(NULL);
+
+  // The fetcher should have been torn down and recreated.
+  EXPECT_EQ(2, mock_fetcher_factory.count);
+  mock_fetcher_factory.fetcher->FireDone();
 }
 
 TEST_F(LoaderTest, FetcherReceiveDone) {
   InSequence dummy;
 
   MockLoaderCallback mock_loader_callback;
+  MockFetcherFactory mock_fetcher_factory;
   MockDecoder* mock_decoder = new MockDecoder();  // To be owned by loader.
   EXPECT_CALL(mock_loader_callback, OnError(_)).Times(0);
   EXPECT_CALL(*mock_decoder, DecodeChunk(_, _));
   EXPECT_CALL(*mock_decoder, Finish());
 
-  Loader loader(base::Bind(&StubFetcherReceivedDone::Create),
+  Loader loader(mock_fetcher_factory.GetFetcherCreator(),
                 scoped_ptr<Decoder>(mock_decoder),
                 base::Bind(&MockLoaderCallback::OnError,
                            base::Unretained(&mock_loader_callback)));
+  mock_fetcher_factory.fetcher->FireReceived(NULL, 0);
+  mock_fetcher_factory.fetcher->FireDone();
 }
 
 // Typical usage of Loader.
diff --git a/src/cobalt/loader/text_decoder.h b/src/cobalt/loader/text_decoder.h
index 3c7cf13..5de3c4c 100644
--- a/src/cobalt/loader/text_decoder.h
+++ b/src/cobalt/loader/text_decoder.h
@@ -33,7 +33,7 @@
 class TextDecoder : public Decoder {
  public:
   explicit TextDecoder(base::Callback<void(const std::string&)> done_callback)
-      : done_callback_(done_callback) {}
+      : done_callback_(done_callback), suspended_(false) {}
   ~TextDecoder() OVERRIDE {}
 
   // This function is used for binding callback for creating TextDecoder.
@@ -45,17 +45,32 @@
   // From Decoder.
   void DecodeChunk(const char* data, size_t size) OVERRIDE {
     DCHECK(thread_checker_.CalledOnValidThread());
+    if (suspended_) {
+      return;
+    }
     text_.append(data, size);
   }
   void Finish() OVERRIDE {
     DCHECK(thread_checker_.CalledOnValidThread());
+    if (suspended_) {
+      return;
+    }
     done_callback_.Run(text_);
   }
+  bool Suspend() OVERRIDE {
+    suspended_ = true;
+    text_.clear();
+    return true;
+  }
+  void Resume(render_tree::ResourceProvider* /*resource_provider*/) OVERRIDE {
+    suspended_ = false;
+  }
 
  private:
   base::ThreadChecker thread_checker_;
   std::string text_;
   base::Callback<void(const std::string&)> done_callback_;
+  bool suspended_;
 };
 
 }  // namespace loader
diff --git a/src/cobalt/script/mozjs/mozjs_engine.cc b/src/cobalt/script/mozjs/mozjs_engine.cc
index d5076b8..a2870e8 100644
--- a/src/cobalt/script/mozjs/mozjs_engine.cc
+++ b/src/cobalt/script/mozjs/mozjs_engine.cc
@@ -87,6 +87,17 @@
                     "Total JavaScript engine registered.") {
 }
 
+// Pretend we always preserve wrappers since we never call
+// SetPreserveWrapperCallback anywhere else. This is necessary for
+// TryPreserveReflector called by WeakMap to not crash. Disabling
+// bindings to WeakMap does not appear to be an easy option because
+// of its use in selfhosted.js. See bugzilla discussion linked where
+// they decided to include a similar dummy in the mozjs shell.
+// https://bugzilla.mozilla.org/show_bug.cgi?id=829798
+bool DummyPreserveWrapperCallback(JSContext *cx, JSObject *obj) {
+  return true;
+}
+
 }  // namespace
 
 MozjsEngine::MozjsEngine() {
@@ -124,6 +135,8 @@
   // Callback to be called during garbage collection during the sweep phase.
   JS_SetFinalizeCallback(runtime_, &MozjsEngine::FinalizeCallback);
 
+  js::SetPreserveWrapperCallback(runtime_, DummyPreserveWrapperCallback);
+
   EngineStats::GetInstance()->EngineCreated();
 }
 
diff --git a/src/cobalt/speech/audio_encoder_flac.cc b/src/cobalt/speech/audio_encoder_flac.cc
index d4403e1..16c5640 100644
--- a/src/cobalt/speech/audio_encoder_flac.cc
+++ b/src/cobalt/speech/audio_encoder_flac.cc
@@ -57,16 +57,21 @@
   FLAC__stream_encoder_delete(encoder_);
 }
 
-void AudioEncoderFlac::Encode(const AudioBus* audio_bus) {
+void AudioEncoderFlac::Encode(const ShellAudioBus* audio_bus) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   DCHECK_EQ(audio_bus->channels(), 1);
-  const float* audio_data = audio_bus->channel(0);
   uint32 frames = static_cast<uint32>(audio_bus->frames());
   scoped_array<FLAC__int32> flac_samples(new FLAC__int32[frames]);
   for (uint32 i = 0; i < frames; ++i) {
-    flac_samples[i] =
-        static_cast<FLAC__int32>(audio_data[i] * kMaxInt16AsFloat32);
+    if (audio_bus->sample_type() == ShellAudioBus::kFloat32) {
+      flac_samples[i] = static_cast<FLAC__int32>(
+          audio_bus->GetFloat32Sample(0, i) * kMaxInt16AsFloat32);
+    } else {
+      DCHECK_EQ(audio_bus->sample_type(), ShellAudioBus::kInt16);
+      flac_samples[i] =
+          static_cast<FLAC__int32>(audio_bus->GetInt16Sample(0, i));
+    }
   }
 
   FLAC__int32* flac_samples_ptr = flac_samples.get();
diff --git a/src/cobalt/speech/audio_encoder_flac.h b/src/cobalt/speech/audio_encoder_flac.h
index be993ca..62fcfb1 100644
--- a/src/cobalt/speech/audio_encoder_flac.h
+++ b/src/cobalt/speech/audio_encoder_flac.h
@@ -22,7 +22,7 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/threading/thread_checker.h"
-#include "media/base/audio_bus.h"
+#include "media/base/shell_audio_bus.h"
 #include "third_party/flac/include/FLAC/stream_encoder.h"
 
 namespace cobalt {
@@ -31,13 +31,13 @@
 // Encode raw audio to using FLAC codec.
 class AudioEncoderFlac {
  public:
-  typedef ::media::AudioBus AudioBus;
+  typedef ::media::ShellAudioBus ShellAudioBus;
 
   explicit AudioEncoderFlac(int sample_rate);
   ~AudioEncoderFlac();
 
   // Encode raw audio data.
-  void Encode(const AudioBus* audio_bus);
+  void Encode(const ShellAudioBus* audio_bus);
   // Finish encoding.
   void Finish();
 
diff --git a/src/cobalt/speech/mic.h b/src/cobalt/speech/mic.h
index b83b875..506632a 100644
--- a/src/cobalt/speech/mic.h
+++ b/src/cobalt/speech/mic.h
@@ -20,7 +20,7 @@
 #include <string>
 
 #include "base/callback.h"
-#include "media/base/audio_bus.h"
+#include "media/base/shell_audio_bus.h"
 
 namespace cobalt {
 namespace speech {
@@ -28,8 +28,8 @@
 // An abstract class is used for interacting platform specific microphone.
 class Mic {
  public:
-  typedef ::media::AudioBus AudioBus;
-  typedef base::Callback<void(scoped_ptr<AudioBus>)> DataReceivedCallback;
+  typedef ::media::ShellAudioBus ShellAudioBus;
+  typedef base::Callback<void(scoped_ptr<ShellAudioBus>)> DataReceivedCallback;
   typedef base::Callback<void(void)> CompletionCallback;
   typedef base::Callback<void(void)> ErrorCallback;
 
diff --git a/src/cobalt/speech/speech_recognition_manager.cc b/src/cobalt/speech/speech_recognition_manager.cc
index 2c69fc2..e531a77 100644
--- a/src/cobalt/speech/speech_recognition_manager.cc
+++ b/src/cobalt/speech/speech_recognition_manager.cc
@@ -93,7 +93,8 @@
   state_ = kAborted;
 }
 
-void SpeechRecognitionManager::OnDataReceived(scoped_ptr<AudioBus> audio_bus) {
+void SpeechRecognitionManager::OnDataReceived(
+    scoped_ptr<ShellAudioBus> audio_bus) {
   if (!main_message_loop_->BelongsToCurrentThread()) {
     // Called from mic thread.
     main_message_loop_->PostTask(
@@ -123,9 +124,9 @@
     // silence at the end in case encoder had no data already.
     size_t dummy_frames =
         static_cast<size_t>(kSampleRate * kAudioPacketDurationInSeconds);
-    scoped_ptr<AudioBus> dummy_audio_bus =
-        AudioBus::Create(1, static_cast<int>(dummy_frames));
-    memset(dummy_audio_bus->channel(0), 0, dummy_frames);
+    scoped_ptr<ShellAudioBus> dummy_audio_bus(new ShellAudioBus(
+        1, dummy_frames, ShellAudioBus::kInt16, ShellAudioBus::kPlanar));
+    dummy_audio_bus->ZeroAllFrames();
     recognizer_.RecognizeAudio(dummy_audio_bus.Pass(), true);
   }
 }
diff --git a/src/cobalt/speech/speech_recognition_manager.h b/src/cobalt/speech/speech_recognition_manager.h
index dcc9457..852ede2 100644
--- a/src/cobalt/speech/speech_recognition_manager.h
+++ b/src/cobalt/speech/speech_recognition_manager.h
@@ -26,6 +26,7 @@
 #include "cobalt/speech/speech_recognition_error.h"
 #include "cobalt/speech/speech_recognition_event.h"
 #include "cobalt/speech/speech_recognizer.h"
+#include "media/base/shell_audio_bus.h"
 
 namespace cobalt {
 namespace speech {
@@ -37,7 +38,7 @@
 // class would encode the audio data, then send it to recogniton service.
 class SpeechRecognitionManager {
  public:
-  typedef ::media::AudioBus AudioBus;
+  typedef ::media::ShellAudioBus ShellAudioBus;
   typedef base::Callback<bool(const scoped_refptr<dom::Event>&)> EventCallback;
 
   SpeechRecognitionManager(network::NetworkModule* network_module,
@@ -59,7 +60,7 @@
   };
 
   // Callbacks from mic.
-  void OnDataReceived(scoped_ptr<AudioBus> audio_bus);
+  void OnDataReceived(scoped_ptr<ShellAudioBus> audio_bus);
   void OnDataCompletion();
   void OnMicError();
 
diff --git a/src/cobalt/speech/speech_recognizer.cc b/src/cobalt/speech/speech_recognizer.cc
index bdd0688..d5c1ce1 100644
--- a/src/cobalt/speech/speech_recognizer.cc
+++ b/src/cobalt/speech/speech_recognizer.cc
@@ -169,7 +169,7 @@
       base::Bind(&SpeechRecognizer::StopInternal, base::Unretained(this)));
 }
 
-void SpeechRecognizer::RecognizeAudio(scoped_ptr<AudioBus> audio_bus,
+void SpeechRecognizer::RecognizeAudio(scoped_ptr<ShellAudioBus> audio_bus,
                                       bool is_last_chunk) {
   // Called by the speech recognition manager thread.
   thread_.message_loop()->PostTask(
@@ -293,8 +293,8 @@
   chunked_byte_buffer_.Clear();
 }
 
-void SpeechRecognizer::UploadAudioDataInternal(scoped_ptr<AudioBus> audio_bus,
-                                               bool is_last_chunk) {
+void SpeechRecognizer::UploadAudioDataInternal(
+    scoped_ptr<ShellAudioBus> audio_bus, bool is_last_chunk) {
   DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
   DCHECK(audio_bus);
 
diff --git a/src/cobalt/speech/speech_recognizer.h b/src/cobalt/speech/speech_recognizer.h
index cb76a05..90e5dcd 100644
--- a/src/cobalt/speech/speech_recognizer.h
+++ b/src/cobalt/speech/speech_recognizer.h
@@ -42,7 +42,7 @@
 // manager.
 class SpeechRecognizer : public net::URLFetcherDelegate {
  public:
-  typedef ::media::AudioBus AudioBus;
+  typedef ::media::ShellAudioBus ShellAudioBus;
   typedef base::Callback<void(const scoped_refptr<dom::Event>&)> EventCallback;
   typedef SpeechRecognitionResultList::SpeechRecognitionResults
       SpeechRecognitionResults;
@@ -58,7 +58,7 @@
   // Stop speech recognizer.
   void Stop();
   // An encoded audio data is available and ready to be recognized.
-  void RecognizeAudio(scoped_ptr<AudioBus> audio_bus, bool is_last_chunk);
+  void RecognizeAudio(scoped_ptr<ShellAudioBus> audio_bus, bool is_last_chunk);
 
   // net::URLFetcherDelegate interface
   void OnURLFetchDownloadData(const net::URLFetcher* source,
@@ -71,7 +71,7 @@
  private:
   void StartInternal(const SpeechRecognitionConfig& config, int sample_rate);
   void StopInternal();
-  void UploadAudioDataInternal(scoped_ptr<AudioBus> audio_bus,
+  void UploadAudioDataInternal(scoped_ptr<ShellAudioBus> audio_bus,
                                bool is_last_chunk);
   void ProcessAndFireSuccessEvent(const SpeechRecognitionResults& new_results);
 
diff --git a/src/cobalt/webdriver_benchmarks/partial_layout_benchmark.py b/src/cobalt/webdriver_benchmarks/partial_layout_benchmark.py
index 41503c6..479ad5c 100755
--- a/src/cobalt/webdriver_benchmarks/partial_layout_benchmark.py
+++ b/src/cobalt/webdriver_benchmarks/partial_layout_benchmark.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python2
 """Webdriver-based benchmarks for partial layout.
 
 Benchmarks for partial layout changes in Cobalt.
@@ -108,11 +108,12 @@
     sys.path.append(script_path + "/../../tools/lbshell/")
     app_launcher = importlib.import_module("app_launcher")
     self.launcher = app_launcher.CreateLauncher(
-        platform, executable, devkit_name=devkit_name)
+        platform, executable, devkit_name=devkit_name, close_output_file=False)
 
     self.launcher.SetArgs(["--enable_webdriver"])
     self.launcher.SetOutputCallback(self._HandleLine)
     self.log_file_path = log_file_path
+    self.log_file = None
 
   def __enter__(self):
     self.thread = threading.Thread(target=self.Run)
@@ -166,13 +167,15 @@
     to_close = None
     try:
       if self.log_file_path:
-        log_file = open(self.log_file_path, "w")
-        to_close = log_file
+        self.log_file = open(self.log_file_path, "w")
+        to_close = self.log_file
       else:
-        log_file = sys.stdout
+        self.log_file = sys.stdout
 
-      self.launcher.SetOutputFile(log_file)
+      self.launcher.SetOutputFile(self.log_file)
       self.launcher.Run()
+      # This is watched for in webdriver_benchmark_test.py
+      sys.stdout.write("partial_layout_benchmark TEST COMPLETE\n")
     finally:
       if to_close:
         to_close.close()
@@ -195,6 +198,8 @@
 
 def main():
   args = arg_parser.parse_args()
+  # Keep unittest module from seeing these args
+  sys.argv = sys.argv[:1]
 
   platform = args.platform
   if platform is None:
diff --git a/src/cobalt/webdriver_benchmarks/tests/all.py b/src/cobalt/webdriver_benchmarks/tests/all.py
new file mode 100755
index 0000000..78924c0
--- /dev/null
+++ b/src/cobalt/webdriver_benchmarks/tests/all.py
@@ -0,0 +1,38 @@
+#!/usr/bin/python2
+"""Target for running all tests cases."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import importlib
+import os
+import sys
+import unittest
+
+# The parent directory is a module
+sys.path.insert(0, os.path.dirname(os.path.dirname(
+    os.path.realpath(__file__))))
+
+# pylint: disable=C6204,C6203
+import tv_testcase
+
+
+# pylint: disable=unused-argument
+def load_tests(loader, tests, pattern):
+  """This is a Python unittest "load_tests protocol method."""
+  s = unittest.TestSuite()
+
+  for f in os.listdir(os.path.dirname(__file__)):
+    if not f.endswith(".py"):
+      continue
+    if f.startswith("_"):
+      continue
+    if f == "all.py":
+      continue
+    s.addTest(unittest.TestLoader().loadTestsFromModule(
+        importlib.import_module("tests." + f[:-3])))
+  return s
+
+if __name__ == "__main__":
+  tv_testcase.main()
diff --git a/src/cobalt/webdriver_benchmarks/tests/guide.py b/src/cobalt/webdriver_benchmarks/tests/guide.py
new file mode 100755
index 0000000..442eef1
--- /dev/null
+++ b/src/cobalt/webdriver_benchmarks/tests/guide.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python2
+"""Simple guide navigation test."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import os
+import sys
+
+# The parent directory is a module
+sys.path.insert(0, os.path.dirname(os.path.dirname(
+    os.path.realpath(__file__))))
+
+# pylint: disable=C6204,C6203
+import tv
+import tv_testcase
+import partial_layout_benchmark
+
+# selenium imports
+keys = partial_layout_benchmark.ImportSeleniumModule("webdriver.common.keys")
+
+REPEAT_COUNT = 10
+
+
+class GuideTest(tv_testcase.TvTestCase):
+
+  def test_simple(self):
+    self.load_tv()
+    self.assert_displayed(tv.FOCUSED_SHELF)
+
+    print(str(self.get_webdriver().execute_script(
+        "h5vcc.system.recordStats = true")))
+
+    for _ in xrange(REPEAT_COUNT):
+      self.send_keys(tv.FOCUSED_SHELF, keys.Keys.ARROW_LEFT)
+      self.assert_displayed(tv.FOCUSED_GUIDE)
+      self.wait_for_layout_complete()
+      self.send_keys(tv.FOCUSED_GUIDE, keys.Keys.ARROW_RIGHT)
+      self.poll_until_found(tv.FOCUSED_SHELF)
+      self.assert_displayed(tv.FOCUSED_SHELF_TITLE)
+      self.wait_for_layout_complete()
+
+    self.record_results("GuideTest.test_simple")
+
+
+if __name__ == "__main__":
+  tv_testcase.main()
diff --git a/src/cobalt/webdriver_benchmarks/tests/shelf.py b/src/cobalt/webdriver_benchmarks/tests/shelf.py
index b81478b..b47e379 100755
--- a/src/cobalt/webdriver_benchmarks/tests/shelf.py
+++ b/src/cobalt/webdriver_benchmarks/tests/shelf.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python2
 """Simple shelf navigation test."""
 
 from __future__ import absolute_import
@@ -7,7 +7,6 @@
 
 import os
 import sys
-import time
 
 # The parent directory is a module
 sys.path.insert(0, os.path.dirname(os.path.dirname(
@@ -27,11 +26,6 @@
 
 class ShelfTest(tv_testcase.TvTestCase):
 
-  def _wait_for_layout(self):
-    while int(self.get_webdriver().execute_script(
-        "return h5vcc.cVal.getValue('Event.MainWebModule.IsProcessing')")):
-      time.sleep(0.1)
-
   def test_simple(self):
     self.load_tv()
     self.assert_displayed(tv.FOCUSED_SHELF)
@@ -43,18 +37,16 @@
       self.send_keys(tv.FOCUSED_SHELF, keys.Keys.ARROW_DOWN)
       self.poll_until_found(tv.FOCUSED_SHELF)
       self.assert_displayed(tv.FOCUSED_SHELF_TITLE)
-      self._wait_for_layout()
+      self.wait_for_layout_complete()
 
     for _ in xrange(SHELF_ITEMS_COUNT):
       self.send_keys(tv.FOCUSED_TILE, keys.Keys.ARROW_RIGHT)
       self.poll_until_found(tv.FOCUSED_TILE)
       self.assert_displayed(tv.FOCUSED_SHELF_TITLE)
-      self._wait_for_layout()
+      self.wait_for_layout_complete()
 
-    print("ShelfTest event durations"
-          + str(self.get_webdriver().execute_script(
-              "return h5vcc.cVal.getValue("
-              "'Event.Durations.MainWebModule.KeyUp')")))
+    self.record_results("ShelfTest.test_simple")
+
 
 if __name__ == "__main__":
   tv_testcase.main()
diff --git a/src/cobalt/webdriver_benchmarks/tv_testcase.py b/src/cobalt/webdriver_benchmarks/tv_testcase.py
index 39bfe41..23649ec 100644
--- a/src/cobalt/webdriver_benchmarks/tv_testcase.py
+++ b/src/cobalt/webdriver_benchmarks/tv_testcase.py
@@ -27,6 +27,7 @@
 
 BASE_URL = "https://www.youtube.com/tv"
 PAGE_LOAD_WAIT_SECONDS = 30
+LAYOUT_TIMEOUT_SECONDS = 5
 
 
 class TvTestCase(unittest.TestCase):
@@ -36,6 +37,9 @@
   with an internal class with the same name.
   """
 
+  class LayoutTimeoutException(BaseException):
+    """Exception thrown when layout did not complete in time."""
+
   def get_webdriver(self):
     return partial_layout_benchmark.GetWebDriver()
 
@@ -127,6 +131,10 @@
     could not be immediately found. If the retries do not succeed,
     the underlying exception is passed through.
 
+    Args:
+      css_selector: A CSS selector
+      keys: key events
+
     Raises:
       Underlying WebDriver exceptions
     """
@@ -144,6 +152,30 @@
           raise
         time.sleep(1)
 
+  def wait_for_layout_complete(self):
+    """Waits for Cobalt to complete pending layouts."""
+    start_time = time.time()
+    while int(self.get_webdriver().execute_script(
+        "return h5vcc.cVal.getValue('Event.MainWebModule.IsProcessing')")):
+
+      if time.time() - start_time > LAYOUT_TIMEOUT_SECONDS:
+        raise TvTestCase.LayoutTimeoutException()
+
+      time.sleep(0.1)
+
+  def record_results(self, name):
+    """Records results of benchmark.
+
+    The duration of KeyUp events will be recorded.
+
+    Args:
+      name: name of test case
+    """
+    print("tv_testcase RESULT: " + name + " "
+          + str(self.get_webdriver().execute_script(
+              "return h5vcc.cVal.getValue("
+              "'Event.Durations.MainWebModule.KeyUp')")))
+
 
 def main():
   partial_layout_benchmark.main()
diff --git a/src/media/base/shell_audio_bus.h b/src/media/base/shell_audio_bus.h
index 6c43f8c..16c7012 100644
--- a/src/media/base/shell_audio_bus.h
+++ b/src/media/base/shell_audio_bus.h
@@ -59,6 +59,7 @@
 
   size_t channels() const { return channels_; }
   size_t frames() const { return frames_; }
+  SampleType sample_type() const { return sample_type_; }
   size_t GetSampleSizeInBytes() const;
   const uint8* interleaved_data() const;
   const uint8* planar_data(size_t channel) const;
diff --git a/src/starboard/shared/posix/log_raw.cc b/src/starboard/shared/posix/log_raw.cc
index 10cfff0..f790d78 100644
--- a/src/starboard/shared/posix/log_raw.cc
+++ b/src/starboard/shared/posix/log_raw.cc
@@ -23,14 +23,13 @@
   // Cribbed from base/logging.cc's RawLog() function.
   size_t bytes_written = 0;
   const size_t message_len = strlen(message);
-  int rv;
   while (bytes_written < message_len) {
-    rv = HANDLE_EINTR(write(STDERR_FILENO, message + bytes_written,
-                            message_len - bytes_written));
-    if (rv < 0) {
+    int retval = HANDLE_EINTR(write(STDERR_FILENO, message + bytes_written,
+                                    message_len - bytes_written));
+    if (retval < 0) {
       // Give up, nothing we can do now.
       break;
     }
-    bytes_written += rv;
+    bytes_written += retval;
   }
 }