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;
}
}