Import Cobalt 2.11130 2016-09-17
diff --git a/src/base/test/run_all_unittests.cc b/src/base/test/run_all_unittests.cc
index 1aba309..7c69f3b 100644
--- a/src/base/test/run_all_unittests.cc
+++ b/src/base/test/run_all_unittests.cc
@@ -5,22 +5,11 @@
#include "base/test/main_hook.h"
#include "base/test/test_suite.h"
#include "build/build_config.h"
+#include "starboard/client_porting/wrap_main/wrap_main.h"
-#if !defined(OS_STARBOARD)
-int main(int argc, char** argv) {
- MainHook hook(main, argc, argv);
+int TestSuiteRun(int argc, char** argv) {
+ MainHook hook(NULL, argc, argv);
return base::TestSuite(argc, argv).Run();
}
-#else
-#include "starboard/event.h"
-#include "starboard/system.h"
-void SbEventHandle(const SbEvent* event) {
- if (event->type == kSbEventTypeStart) {
- SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
- MainHook hook(NULL, data->argument_count, data->argument_values);
- SbSystemRequestStop(
- base::TestSuite(data->argument_count, data->argument_values).Run());
- }
-}
-#endif
+STARBOARD_WRAP_SIMPLE_MAIN(TestSuiteRun);
diff --git a/src/cobalt/audio/audio_device.cc b/src/cobalt/audio/audio_device.cc
index 74d4c2d..8ab8b57 100644
--- a/src/cobalt/audio/audio_device.cc
+++ b/src/cobalt/audio/audio_device.cc
@@ -16,6 +16,7 @@
#include "cobalt/audio/audio_device.h"
+#include "base/debug/trace_event.h"
#include "base/memory/scoped_ptr.h"
#if defined(OS_STARBOARD)
#include "starboard/audio_sink.h"
@@ -192,6 +193,7 @@
int* offset_in_frames,
bool* is_playing,
bool* is_eos_reached) {
+ TRACE_EVENT0("cobalt::audio", "AudioDevice::Impl::UpdateSourceStatus()");
*is_playing = true;
*is_eos_reached = false;
@@ -248,6 +250,7 @@
}
void AudioDevice::Impl::FillOutputAudioBus() {
+ TRACE_EVENT0("cobalt::audio", "AudioDevice::Impl::FillOutputAudioBus()");
if (output_sample_type_ == kSbMediaAudioSampleTypeFloat32) {
FillOutputAudioBusForType<float>();
} else if (output_sample_type_ == kSbMediaAudioSampleTypeInt16) {
@@ -305,6 +308,8 @@
static_cast<size_t>(kRenderBufferSizeFrames),
ShellAudioBus::kFloat32, ShellAudioBus::kPlanar),
render_callback_(callback) {
+ TRACE_EVENT0("cobalt::audio", "AudioDevice::Impl::Impl()");
+
DCHECK_GT(number_of_channels, 0);
DCHECK(media::ShellAudioStreamer::Instance()->GetConfig().interleaved())
<< "Planar audio is not supported.";
@@ -341,6 +346,8 @@
bool AudioDevice::Impl::PullFrames(uint32* offset_in_frame,
uint32* total_frames) {
+ TRACE_EVENT0("cobalt::audio", "AudioDevice::Impl::PullFrames()");
+
// In case offset_in_frame or total_frames is NULL.
uint32 dummy_offset_in_frame;
uint32 dummy_total_frames;
@@ -401,6 +408,7 @@
}
void AudioDevice::Impl::FillOutputAudioBus() {
+ TRACE_EVENT0("cobalt::audio", "AudioDevice::Impl::FillOutputAudioBus()");
// Determine the offset into the audio bus that represents the tail of
// buffered data.
uint64 channel_offset = buffered_frame_cursor_ % kFramesPerChannel;
diff --git a/src/cobalt/base/c_val.h b/src/cobalt/base/c_val.h
index 787f51a..c4bcc0c 100644
--- a/src/cobalt/base/c_val.h
+++ b/src/cobalt/base/c_val.h
@@ -18,6 +18,7 @@
#include <stdint.h>
+#include <iomanip>
#include <set>
#include <sstream>
#include <string>
@@ -29,6 +30,7 @@
#include "base/memory/singleton.h"
#include "base/optional.h"
#include "base/synchronization/lock.h"
+#include "base/time.h"
// The CVal system allows you to mark certain variables to be part of the
// CVal system and therefore analyzable and trackable by other systems. All
@@ -93,6 +95,7 @@
// An enumeration to allow CVals to track the type that they hold in a run-time
// variable.
enum CValType {
+ kSize,
kU32,
kU64,
kS32,
@@ -100,8 +103,41 @@
kFloat,
kDouble,
kString,
+ kTimeDelta,
};
+// CVals are commonly used for values that are in units of bytes. By making
+// a CVal of type SizeInBytes, this can be made explicit, and allows the CVal
+// system to use KB/MB suffixes instead of K/M.
+namespace cval {
+class SizeInBytes {
+ public:
+ SizeInBytes(uint64 size_in_bytes) // NOLINT(runtime/explicit)
+ : size_in_bytes_(size_in_bytes) {}
+ SizeInBytes& operator=(uint64 rhs) {
+ size_in_bytes_ = rhs;
+ return *this;
+ }
+ SizeInBytes& operator+=(const SizeInBytes& rhs) {
+ size_in_bytes_ += rhs.size_in_bytes_;
+ return *this;
+ }
+ SizeInBytes& operator-=(const SizeInBytes& rhs) {
+ size_in_bytes_ -= rhs.size_in_bytes_;
+ return *this;
+ }
+ operator uint64() const { return value(); }
+
+ uint64 value() const { return size_in_bytes_; }
+
+ private:
+ uint64 size_in_bytes_;
+};
+inline std::ostream& operator<<(std::ostream& out, const SizeInBytes& size) {
+ return out << static_cast<uint64>(size);
+}
+} // namespace cval
+
namespace CValDetail {
// Introduce a Traits class so that we can convert from C++ type to
@@ -113,6 +149,11 @@
int UnsupportedCValType[0];
};
template <>
+struct Traits<cval::SizeInBytes> {
+ static const CValType kTypeVal = kSize;
+ static const bool kIsNumerical = true;
+};
+template <>
struct Traits<uint32_t> {
static const CValType kTypeVal = kU32;
static const bool kIsNumerical = true;
@@ -147,6 +188,11 @@
static const CValType kTypeVal = kString;
static const bool kIsNumerical = false;
};
+template <>
+struct Traits<base::TimeDelta> {
+ static const CValType kTypeVal = kTimeDelta;
+ static const bool kIsNumerical = true;
+};
// Provide methods to convert from an arbitrary type to a string, useful for
// systems that want to read the value of a CVal without caring about its type.
@@ -162,22 +208,60 @@
return value;
}
+template <>
+inline std::string ValToString<base::TimeDelta>(const base::TimeDelta& value) {
+ return ValToString(value.InMicroseconds());
+}
+
// Helper function to implement the numerical branch of ValToPrettyString
template <typename T>
-std::string NumericalValToPrettyString(const T& value) {
- struct {
- T threshold;
- T divide_by;
- const char* postfix;
- } thresholds[] = {
- {static_cast<T>(10 * 1024 * 1024), static_cast<T>(1024 * 1024), "MB"},
- {static_cast<T>(10 * 1024), static_cast<T>(1024), "KB"},
+struct ThresholdListElement {
+ T threshold;
+ T divide_by;
+ const char* postfix;
+};
+template <>
+struct ThresholdListElement<cval::SizeInBytes> {
+ uint64 threshold;
+ uint64 divide_by;
+ const char* postfix;
+};
+template <typename T>
+struct ThresholdList {
+ ThresholdList(ThresholdListElement<T>* array, size_t size)
+ : array(array), size(size) {}
+ ThresholdListElement<T>* array;
+ size_t size;
+};
+
+template <typename T>
+ThresholdList<T> GetThresholdList() {
+ static ThresholdListElement<T> thresholds[] = {
+ {static_cast<T>(10 * 1000 * 1000), static_cast<T>(1000 * 1000), "M"},
+ {static_cast<T>(10 * 1000), static_cast<T>(1000), "K"},
};
+ return ThresholdList<T>(thresholds, arraysize(thresholds));
+}
+
+template <>
+inline ThresholdList<cval::SizeInBytes> GetThresholdList<cval::SizeInBytes>() {
+ static ThresholdListElement<cval::SizeInBytes> thresholds[] = {
+ {10LL * 1024LL * 1024LL * 1024LL, 1024LL * 1024LL * 1024LL, "GB"},
+ {10LL * 1024LL * 1024LL, 1024LL * 1024LL, "MB"},
+ {10LL * 1024LL, 1024LL, "KB"},
+ };
+ return ThresholdList<cval::SizeInBytes>(thresholds, arraysize(thresholds));
+}
+
+template <typename T>
+std::string NumericalValToPrettyString(const T& value) {
+ ThresholdList<T> threshold_list = GetThresholdList<T>();
+ ThresholdListElement<T>* thresholds = threshold_list.array;
T divided_value = value;
const char* postfix = "";
- for (size_t i = 0; i < sizeof(thresholds) / sizeof(thresholds[0]); ++i) {
+ for (size_t i = 0; i < threshold_list.size; ++i) {
if (value >= thresholds[i].threshold) {
divided_value = value / thresholds[i].divide_by;
postfix = thresholds[i].postfix;
@@ -190,6 +274,43 @@
return oss.str();
}
+template <>
+inline std::string NumericalValToPrettyString<base::TimeDelta>(
+ const base::TimeDelta& value) {
+ const int64 kMicrosecond = 1LL;
+ const int64 kMillisecond = 1000LL * kMicrosecond;
+ const int64 kSecond = 1000LL * kMillisecond;
+ const int64 kMinute = 60LL * kSecond;
+ const int64 kHour = 60LL * kMinute;
+
+ int64 value_in_us = value.InMicroseconds();
+ bool negative = value_in_us < 0;
+ value_in_us *= negative ? -1 : 1;
+
+ std::ostringstream oss;
+ if (negative) {
+ oss << "-";
+ }
+ if (value_in_us > kHour) {
+ oss << value_in_us / kHour << ":" << std::setfill('0') << std::setw(2)
+ << (value_in_us % kHour) / kMinute << ":" << std::setfill('0')
+ << std::setw(2) << (value_in_us % kMinute) / kSecond << "h";
+ } else if (value_in_us > kMinute) {
+ oss << value_in_us / kMinute << ":" << std::setfill('0') << std::setw(2)
+ << (value_in_us % kMinute) / kSecond << "m";
+ } else if (value_in_us > kSecond * 10) {
+ oss << value_in_us / kSecond << "s";
+ } else if (value_in_us > kMillisecond * 2) {
+ oss << value_in_us / kMillisecond << "ms";
+ } else if (value_in_us > 0) {
+ oss << value_in_us << "us";
+ } else {
+ oss << value_in_us;
+ }
+
+ return oss.str();
+}
+
// Helper function for the subsequent ValToPrettyString function.
template <typename T, bool IsNumerical>
class ValToPrettyStringHelper {};
@@ -413,10 +534,7 @@
}
}
- operator T() const {
- base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
- return value_;
- }
+ operator T() const { return value(); }
const CValImpl<T>& operator=(const T& rhs) {
bool value_changed;
@@ -479,6 +597,10 @@
return *this;
}
+ bool operator<(const T& rhs) const { return value() < rhs; }
+ bool operator>(const T& rhs) const { return value() > rhs; }
+ bool operator==(const T& rhs) const { return value() == rhs; }
+
std::string GetValueAsString() const {
// Can be called to get the value of a CVal without knowing the type first.
base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
@@ -492,6 +614,11 @@
return ValToPrettyString<T>(value_);
}
+ T value() const {
+ base::AutoLock auto_lock(CValManager::GetInstance()->values_lock_);
+ return value_;
+ }
+
private:
void CommonConstructor() {
registered_ = false;
@@ -560,6 +687,12 @@
return *this;
}
+ bool operator<(const T& rhs) const { return value_ < rhs; }
+ bool operator>(const T& rhs) const { return value_ > rhs; }
+ bool operator==(const T& rhs) const { return value_ == rhs; }
+
+ T value() const { return value_; }
+
private:
T value_;
};
diff --git a/src/cobalt/base/c_val_time_interval_entry_stats.h b/src/cobalt/base/c_val_time_interval_entry_stats.h
index 11d1f94..4ea30ad 100644
--- a/src/cobalt/base/c_val_time_interval_entry_stats.h
+++ b/src/cobalt/base/c_val_time_interval_entry_stats.h
@@ -28,6 +28,44 @@
namespace base {
+namespace detail {
+template <typename T>
+double ToDouble(T value) {
+ return static_cast<double>(value);
+}
+template <>
+inline double ToDouble<base::TimeDelta>(base::TimeDelta value) {
+ return static_cast<double>(value.InMicroseconds());
+}
+
+template <typename T>
+T FromDouble(double value) {
+ return static_cast<T>(value);
+}
+template <>
+inline base::TimeDelta FromDouble<base::TimeDelta>(double value) {
+ return base::TimeDelta::FromMicroseconds(static_cast<int64>(value));
+}
+
+template <typename T>
+T Max() {
+ return std::numeric_limits<T>::max();
+}
+template <>
+inline base::TimeDelta Max<base::TimeDelta>() {
+ return base::TimeDelta::Max();
+}
+
+template <typename T>
+T Min() {
+ return std::numeric_limits<T>::min();
+}
+template <>
+inline base::TimeDelta Min<base::TimeDelta>() {
+ return -base::TimeDelta::Max();
+}
+} // namespace detail
+
// This class tracks entries over a specified time period. When the time period
// has elapsed, the average, minimum, maximum, and standard deviation of that
// time period are recorded with CVals, and the tracking resets for the next
@@ -48,10 +86,10 @@
const int64 time_interval_in_ms_;
// CVals of the stats for the previously completed time interval.
- base::CVal<double, Visibility> average_;
+ base::CVal<EntryType, Visibility> average_;
base::CVal<EntryType, Visibility> minimum_;
base::CVal<EntryType, Visibility> maximum_;
- base::CVal<double, Visibility> standard_deviation_;
+ base::CVal<EntryType, Visibility> standard_deviation_;
// Active time interval-related
base::TimeTicks active_start_time_;
@@ -79,10 +117,13 @@
CValTimeIntervalEntryStats<EntryType, Visibility>::CValTimeIntervalEntryStats(
const std::string& name, int64 time_interval_in_ms)
: time_interval_in_ms_(time_interval_in_ms),
- average_(StringPrintf("%s.Avg", name.c_str()), 0, "Average time."),
- minimum_(StringPrintf("%s.Min", name.c_str()), 0, "Minimum time."),
- maximum_(StringPrintf("%s.Max", name.c_str()), 0, "Maximum time."),
- standard_deviation_(StringPrintf("%s.Std", name.c_str()), 0,
+ average_(StringPrintf("%s.Avg", name.c_str()), EntryType(),
+ "Average time."),
+ minimum_(StringPrintf("%s.Min", name.c_str()), EntryType(),
+ "Minimum time."),
+ maximum_(StringPrintf("%s.Max", name.c_str()), EntryType(),
+ "Maximum time."),
+ standard_deviation_(StringPrintf("%s.Std", name.c_str()), EntryType(),
"Standard deviation of times."),
active_estimated_mean_(0) {
ResetActiveEntryStats();
@@ -103,7 +144,7 @@
// the estimated mean is set to the passed in value.
if (active_start_time_.is_null()) {
active_start_time_ = now;
- active_estimated_mean_ = static_cast<double>(value);
+ active_estimated_mean_ = detail::ToDouble(value);
// Otherwise, check for the time interval having ended. If it has, then the
// CVals are updated using the active stats, the active stats are reset, and
// the timer restarted.
@@ -114,7 +155,8 @@
DCHECK_GT(active_count_, 0);
double active_shifted_mean = active_shifted_sum_ / active_count_;
- average_ = active_estimated_mean_ + active_shifted_mean;
+ average_ = detail::FromDouble<EntryType>(active_estimated_mean_ +
+ active_shifted_mean);
// The equation comes from the following:
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Computing_shifted_data
double variance =
@@ -122,7 +164,7 @@
((active_shifted_sum_ * active_shifted_sum_) / active_count_)) /
active_count_;
variance = std::max(variance, 0.0);
- standard_deviation_ = std::sqrt(variance);
+ standard_deviation_ = detail::FromDouble<EntryType>(std::sqrt(variance));
minimum_ = active_minimum_;
maximum_ = active_maximum_;
@@ -143,7 +185,7 @@
++active_count_;
double shifted_value_as_double =
- static_cast<double>(value - active_estimated_mean_);
+ detail::ToDouble(value) - active_estimated_mean_;
active_shifted_sum_ += shifted_value_as_double;
active_shifted_sum_squares_ +=
shifted_value_as_double * shifted_value_as_double;
@@ -164,8 +206,8 @@
active_shifted_sum_ = 0;
active_shifted_sum_squares_ = 0;
- active_minimum_ = std::numeric_limits<EntryType>::max();
- active_maximum_ = std::numeric_limits<EntryType>::min();
+ active_minimum_ = detail::Max<EntryType>();
+ active_maximum_ = detail::Min<EntryType>();
}
} // namespace base
diff --git a/src/cobalt/base/c_val_time_interval_timer.h b/src/cobalt/base/c_val_time_interval_timer.h
index 77d386d..8d24dd6 100644
--- a/src/cobalt/base/c_val_time_interval_timer.h
+++ b/src/cobalt/base/c_val_time_interval_timer.h
@@ -54,12 +54,12 @@
return;
}
- entry_stats_.AddEntry((now - start_time_).InMicroseconds(), now);
+ entry_stats_.AddEntry(now - start_time_, now);
start_time_ = base::TimeTicks();
}
private:
- base::CValTimeIntervalEntryStats<int64, Visibility> entry_stats_;
+ base::CValTimeIntervalEntryStats<base::TimeDelta, Visibility> entry_stats_;
base::TimeTicks start_time_;
};
diff --git a/src/cobalt/base/stop_watch.cc b/src/cobalt/base/stop_watch.cc
index ae464e4..d7814fe 100644
--- a/src/cobalt/base/stop_watch.cc
+++ b/src/cobalt/base/stop_watch.cc
@@ -35,8 +35,7 @@
void StopWatch::Stop() {
if (IsCounting()) {
- int64 time_elapsed =
- (base::TimeTicks::Now() - start_time_).InMicroseconds();
+ base::TimeDelta time_elapsed = base::TimeTicks::Now() - start_time_;
start_time_ = base::TimeTicks();
owner_->OnStopWatchStopped(id_, time_elapsed);
}
diff --git a/src/cobalt/base/stop_watch.h b/src/cobalt/base/stop_watch.h
index 7ea32a7..97fefd3 100644
--- a/src/cobalt/base/stop_watch.h
+++ b/src/cobalt/base/stop_watch.h
@@ -51,7 +51,7 @@
private:
virtual bool IsStopWatchEnabled(int id) const = 0;
- virtual void OnStopWatchStopped(int id, int64 time_elapsed) = 0;
+ virtual void OnStopWatchStopped(int id, base::TimeDelta time_elapsed) = 0;
friend class StopWatch;
};
diff --git a/src/cobalt/base/wrap_main_starboard.h b/src/cobalt/base/wrap_main_starboard.h
index c42dc73..1a72bd7 100644
--- a/src/cobalt/base/wrap_main_starboard.h
+++ b/src/cobalt/base/wrap_main_starboard.h
@@ -23,31 +23,13 @@
#include "base/message_loop.h"
#include "cobalt/base/init_cobalt.h"
#include "cobalt/base/wrap_main.h"
+#include "starboard/client_porting/wrap_main/wrap_main.h"
#include "starboard/event.h"
#include "starboard/system.h"
namespace cobalt {
namespace wrap_main {
-// Starboard implementation of the "Simple Main" use case.
-template <MainFunction main_function>
-void SimpleEventHandler(const SbEvent* event) {
- static base::AtExitManager* g_at_exit = NULL;
- switch (event->type) {
- case kSbEventTypeStart: {
- SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
- DCHECK(!g_at_exit);
- g_at_exit = new base::AtExitManager();
- InitCobalt(data->argument_count, data->argument_values);
- SbSystemRequestStop(
- main_function(data->argument_count, data->argument_values));
- break;
- }
- default:
- break;
- }
-}
-
// Starboard implementation of the "Base Main" use case.
template <StartFunction start_function, EventFunction event_function,
StopFunction stop_function>
@@ -93,15 +75,21 @@
}
}
+template <MainFunction main_function>
+int CobaltMainAddOns(int argc, char** argv) {
+ base::AtExitManager at_exit;
+ cobalt::InitCobalt(argc, argv);
+ return main_function(argc, argv);
+}
+
} // namespace wrap_main
} // namespace cobalt
// Calls |main_function| at startup, creates an AtExitManager and calls
// InitCobalt, and terminates once it is completed.
-#define COBALT_WRAP_SIMPLE_MAIN(main_function) \
- void SbEventHandle(const SbEvent* event) { \
- ::cobalt::wrap_main::SimpleEventHandler<main_function>(event); \
- }
+#define COBALT_WRAP_SIMPLE_MAIN(main_function) \
+ STARBOARD_WRAP_SIMPLE_MAIN( \
+ ::cobalt::wrap_main::CobaltMainAddOns<main_function>);
// Like COBALT_WRAP_BASE_MAIN, but supports an event_function to forward
// non-application events to.
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc
index 16e4b25..d2cfb40 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGarbageCollectionTestInterface.cc
@@ -430,9 +430,11 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::GetOpaqueRootFunction get_root =
- base::Bind(&GetOpaqueRootFromWrappable);
- WrapperPrivate::AddPrivateData(context, proxy, wrappable, get_root);
+ WrapperPrivate::GetOpaqueRootFunction get_root;
+ WrapperPrivate::GetReachableWrappablesFunction get_reachable_wrappables;
+ get_root = base::Bind(&GetOpaqueRootFromWrappable);
+ WrapperPrivate::AddPrivateData(
+ context, proxy, wrappable, get_root, get_reachable_wrappables);
return proxy;
}
diff --git a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
index fbb57b3..6d71151 100644
--- a/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
+++ b/src/cobalt/bindings/generated/mozjs/testing/MozjsGetOpaqueRootInterface.cc
@@ -91,6 +91,17 @@
return impl->get_opaque_root_function_name();
}
+void GetReachableWrappables(const scoped_refptr<Wrappable>& wrappable,
+ WrapperPrivate::WrappableVector* reachable) {
+ DCHECK(reachable);
+ GetOpaqueRootInterface* impl =
+ base::polymorphic_downcast<GetOpaqueRootInterface*>(wrappable.get());
+ Wrappable* reachable_0 = impl->add_opaque_root_function_name();
+ if (reachable_0) {
+ reachable->push_back(reachable_0);
+ }
+}
+
class MozjsGetOpaqueRootInterfaceHandler : public ProxyHandler {
public:
MozjsGetOpaqueRootInterfaceHandler()
@@ -326,9 +337,12 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
- WrapperPrivate::GetOpaqueRootFunction get_root =
- base::Bind(&GetOpaqueRootFromWrappable);
- WrapperPrivate::AddPrivateData(context, proxy, wrappable, get_root);
+ WrapperPrivate::GetOpaqueRootFunction get_root;
+ WrapperPrivate::GetReachableWrappablesFunction get_reachable_wrappables;
+ get_root = base::Bind(&GetOpaqueRootFromWrappable);
+ get_reachable_wrappables = base::Bind(&GetReachableWrappables);
+ WrapperPrivate::AddPrivateData(
+ context, proxy, wrappable, get_root, get_reachable_wrappables);
return proxy;
}
diff --git a/src/cobalt/bindings/mozjs/templates/interface.cc.template b/src/cobalt/bindings/mozjs/templates/interface.cc.template
index 19eddeb..eb4e553 100644
--- a/src/cobalt/bindings/mozjs/templates/interface.cc.template
+++ b/src/cobalt/bindings/mozjs/templates/interface.cc.template
@@ -107,6 +107,21 @@
}
{% endif %}
+{% if add_opaque_roots %}
+void GetReachableWrappables(const scoped_refptr<Wrappable>& wrappable,
+ WrapperPrivate::WrappableVector* reachable) {
+ DCHECK(reachable);
+ {{impl_class}}* impl =
+ base::polymorphic_downcast<{{impl_class}}*>(wrappable.get());
+{% for reachable_object in add_opaque_roots %}
+ Wrappable* reachable_{{loop.index0}} = impl->{{reachable_object}}();
+ if (reachable_{{loop.index0}}) {
+ reachable->push_back(reachable_{{loop.index0}});
+ }
+{% endfor %}
+}
+
+{% endif %}
{% if named_property_getter %}
bool IsSupportedNamedProperty(JSContext* context, JS::HandleObject object,
const std::string& property_name) {
@@ -833,12 +848,20 @@
JS::RootedObject proxy(context,
ProxyHandler::NewProxy(context, new_object, prototype, NULL,
proxy_handler.Pointer()));
+{% if add_opaque_roots or get_opaque_root %}
+ WrapperPrivate::GetOpaqueRootFunction get_root;
+ WrapperPrivate::GetReachableWrappablesFunction get_reachable_wrappables;
{% if get_opaque_root %}
- WrapperPrivate::GetOpaqueRootFunction get_root =
- base::Bind(&GetOpaqueRootFromWrappable);
+ get_root = base::Bind(&GetOpaqueRootFromWrappable);
{% endif %}
- WrapperPrivate::AddPrivateData(context, proxy, wrappable{{
- ", get_root" if get_opaque_root }});
+{% if add_opaque_roots %}
+ get_reachable_wrappables = base::Bind(&GetReachableWrappables);
+{% endif %}
+ WrapperPrivate::AddPrivateData(
+ context, proxy, wrappable, get_root, get_reachable_wrappables);
+{% else %}
+ WrapperPrivate::AddPrivateData(context, proxy, wrappable);
+{% endif %}
return proxy;
}
diff --git a/src/cobalt/bindings/testing/global_constructors_idls_idl_files_list.tmp b/src/cobalt/bindings/testing/global_constructors_idls_idl_files_list.tmp
deleted file mode 100644
index 1f9a3fc..0000000
--- a/src/cobalt/bindings/testing/global_constructors_idls_idl_files_list.tmp
+++ /dev/null
@@ -1,45 +0,0 @@
-AnonymousIndexedGetterInterface.idl
-AnonymousNamedGetterInterface.idl
-AnonymousNamedIndexedGetterInterface.idl
-ArbitraryInterface.idl
-BaseInterface.idl
-BooleanTypeTestInterface.idl
-CallbackFunctionInterface.idl
-CallbackInterfaceInterface.idl
-ConditionalInterface.idl
-ConstantsInterface.idl
-ConstructorInterface.idl
-ConstructorWithArgumentsInterface.idl
-DerivedGetterSetterInterface.idl
-DerivedInterface.idl
-DisabledInterface.idl
-DOMStringTestInterface.idl
-EnumerationInterface.idl
-ExceptionObjectInterface.idl
-ExceptionsInterface.idl
-ExtendedIDLAttributesInterface.idl
-GarbageCollectionTestInterface.idl
-GetOpaqueRootInterface.idl
-GlobalInterfaceParent.idl
-IndexedGetterInterface.idl
-InterfaceWithUnsupportedProperties.idl
-NamedConstructorInterface.idl
-NamedGetterInterface.idl
-NamedIndexedGetterInterface.idl
-NestedPutForwardsInterface.idl
-NoConstructorInterface.idl
-NoInterfaceObjectInterface.idl
-NullableTypesTestInterface.idl
-NumericTypesTestInterface.idl
-ObjectTypeBindingsInterface.idl
-OperationsTestInterface.idl
-PutForwardsInterface.idl
-SingleOperationInterface.idl
-StringifierAnonymousOperationInterface.idl
-StringifierAttributeInterface.idl
-StringifierOperationInterface.idl
-StaticPropertiesInterface.idl
-TargetInterface.idl
-UnionTypesInterface.idl
-Window.idl
-UnsupportedInterface.idl
diff --git a/src/cobalt/bindings/testing/global_objects_idl_files_list.tmp b/src/cobalt/bindings/testing/global_objects_idl_files_list.tmp
deleted file mode 100644
index c1c7594..0000000
--- a/src/cobalt/bindings/testing/global_objects_idl_files_list.tmp
+++ /dev/null
@@ -1,44 +0,0 @@
-AnonymousIndexedGetterInterface.idl
-AnonymousNamedGetterInterface.idl
-AnonymousNamedIndexedGetterInterface.idl
-ArbitraryInterface.idl
-BaseInterface.idl
-BooleanTypeTestInterface.idl
-CallbackFunctionInterface.idl
-CallbackInterfaceInterface.idl
-ConditionalInterface.idl
-ConstantsInterface.idl
-ConstructorInterface.idl
-ConstructorWithArgumentsInterface.idl
-DerivedGetterSetterInterface.idl
-DerivedInterface.idl
-DisabledInterface.idl
-DOMStringTestInterface.idl
-EnumerationInterface.idl
-ExceptionObjectInterface.idl
-ExceptionsInterface.idl
-ExtendedIDLAttributesInterface.idl
-GarbageCollectionTestInterface.idl
-GetOpaqueRootInterface.idl
-GlobalInterfaceParent.idl
-IndexedGetterInterface.idl
-InterfaceWithUnsupportedProperties.idl
-NamedConstructorInterface.idl
-NamedGetterInterface.idl
-NamedIndexedGetterInterface.idl
-NestedPutForwardsInterface.idl
-NoConstructorInterface.idl
-NoInterfaceObjectInterface.idl
-NullableTypesTestInterface.idl
-NumericTypesTestInterface.idl
-ObjectTypeBindingsInterface.idl
-OperationsTestInterface.idl
-PutForwardsInterface.idl
-SingleOperationInterface.idl
-StringifierAnonymousOperationInterface.idl
-StringifierAttributeInterface.idl
-StringifierOperationInterface.idl
-StaticPropertiesInterface.idl
-TargetInterface.idl
-UnionTypesInterface.idl
-Window.idl
diff --git a/src/cobalt/bindings/testing/interfaces_info_individual_static_idl_files_list.tmp b/src/cobalt/bindings/testing/interfaces_info_individual_static_idl_files_list.tmp
deleted file mode 100644
index ff5e547..0000000
--- a/src/cobalt/bindings/testing/interfaces_info_individual_static_idl_files_list.tmp
+++ /dev/null
@@ -1,48 +0,0 @@
-AnonymousIndexedGetterInterface.idl
-AnonymousNamedGetterInterface.idl
-AnonymousNamedIndexedGetterInterface.idl
-ArbitraryInterface.idl
-BaseInterface.idl
-BooleanTypeTestInterface.idl
-CallbackFunctionInterface.idl
-CallbackInterfaceInterface.idl
-ConditionalInterface.idl
-ConstantsInterface.idl
-ConstructorInterface.idl
-ConstructorWithArgumentsInterface.idl
-DerivedGetterSetterInterface.idl
-DerivedInterface.idl
-DisabledInterface.idl
-DOMStringTestInterface.idl
-EnumerationInterface.idl
-ExceptionObjectInterface.idl
-ExceptionsInterface.idl
-ExtendedIDLAttributesInterface.idl
-GarbageCollectionTestInterface.idl
-GetOpaqueRootInterface.idl
-GlobalInterfaceParent.idl
-IndexedGetterInterface.idl
-InterfaceWithUnsupportedProperties.idl
-NamedConstructorInterface.idl
-NamedGetterInterface.idl
-NamedIndexedGetterInterface.idl
-NestedPutForwardsInterface.idl
-NoConstructorInterface.idl
-NoInterfaceObjectInterface.idl
-NullableTypesTestInterface.idl
-NumericTypesTestInterface.idl
-ObjectTypeBindingsInterface.idl
-OperationsTestInterface.idl
-PutForwardsInterface.idl
-SingleOperationInterface.idl
-StringifierAnonymousOperationInterface.idl
-StringifierAttributeInterface.idl
-StringifierOperationInterface.idl
-StaticPropertiesInterface.idl
-TargetInterface.idl
-UnionTypesInterface.idl
-Window.idl
-ImplementedInterface.idl
-PartialInterface.idl
-InterfaceWithUnsupportedProperties_partial.idl
-UnsupportedInterface.idl
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index 0006b33..ac19432 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -557,16 +557,24 @@
}
Application::CValStats::CValStats()
- : free_memory("Memory.CPU.Free", 0,
- "Total free application memory remaining."),
- used_memory("Memory.CPU.Used", 0,
- "Total memory allocated via the app's allocators."),
+ : free_cpu_memory("Memory.CPU.Free", 0,
+ "Total free application CPU memory remaining."),
+ used_cpu_memory("Memory.CPU.Used", 0,
+ "Total CPU memory allocated via the app's allocators."),
#if !defined(__LB_SHELL__FOR_RELEASE__)
exe_memory("Memory.CPU.Exe", 0,
"Total memory occupied by the size of the executable."),
#endif
- app_lifetime_in_ms("Cobalt.Lifetime", 0,
- "Application lifetime in milliseconds.") {
+ app_lifetime("Cobalt.Lifetime", base::TimeDelta(),
+ "Application lifetime.") {
+#if defined(OS_STARBOARD)
+ if (SbSystemHasCapability(kSbSystemCapabilityCanQueryGPUMemoryStats)) {
+ free_gpu_memory.emplace("Memory.GPU.Free", 0,
+ "Total free application GPU memory remaining.");
+ used_gpu_memory.emplace("Memory.GPU.Used", 0,
+ "Total GPU memory allocated by the application.");
+ }
+#endif // defined(OS_STARBOARD)
}
void Application::RegisterUserLogs() {
@@ -624,8 +632,9 @@
lb_memory_get_info(&memory_info);
available_memory_ = memory_info.free_memory;
- c_val_stats_.free_memory = static_cast<size_t>(memory_info.free_memory);
- c_val_stats_.used_memory =
+ c_val_stats_.free_cpu_memory =
+ static_cast<size_t>(memory_info.free_memory);
+ c_val_stats_.used_cpu_memory =
static_cast<size_t>(memory_info.application_memory);
c_val_stats_.exe_memory = static_cast<size_t>(memory_info.executable_size);
}
@@ -634,19 +643,25 @@
// unallocated memory as the available memory.
if (!memory_stats_updated) {
available_memory_ = lb_get_unallocated_memory();
- c_val_stats_.free_memory = static_cast<size_t>(available_memory_);
- c_val_stats_.used_memory =
+ c_val_stats_.free_cpu_memory = static_cast<size_t>(available_memory_);
+ c_val_stats_.used_cpu_memory =
lb_get_total_system_memory() - lb_get_unallocated_memory();
}
#elif defined(OS_STARBOARD)
- int64_t used_memory = SbSystemGetUsedCPUMemory();
- available_memory_ = SbSystemGetTotalCPUMemory() - used_memory;
- c_val_stats_.free_memory = available_memory_;
- c_val_stats_.used_memory = used_memory;
+ int64_t used_cpu_memory = SbSystemGetUsedCPUMemory();
+ available_memory_ = SbSystemGetTotalCPUMemory() - used_cpu_memory;
+ c_val_stats_.free_cpu_memory = available_memory_;
+ c_val_stats_.used_cpu_memory = used_cpu_memory;
+
+ if (SbSystemHasCapability(kSbSystemCapabilityCanQueryGPUMemoryStats)) {
+ int64_t used_gpu_memory = SbSystemGetUsedGPUMemory();
+ *c_val_stats_.free_gpu_memory =
+ SbSystemGetTotalGPUMemory() - used_gpu_memory;
+ *c_val_stats_.used_gpu_memory = used_gpu_memory;
+ }
#endif
- lifetime_in_ms_ = (base::TimeTicks::Now() - start_time_).InMilliseconds();
- c_val_stats_.app_lifetime_in_ms = lifetime_in_ms_;
+ c_val_stats_.app_lifetime = base::TimeTicks::Now() - start_time_;
}
} // namespace browser
diff --git a/src/cobalt/browser/application.h b/src/cobalt/browser/application.h
index 870e87f..3b5189a 100644
--- a/src/cobalt/browser/application.h
+++ b/src/cobalt/browser/application.h
@@ -127,13 +127,22 @@
struct CValStats {
CValStats();
- base::CVal<size_t, base::CValPublic> free_memory;
- base::CVal<size_t, base::CValPublic> used_memory;
+ base::CVal<base::cval::SizeInBytes, base::CValPublic> free_cpu_memory;
+ base::CVal<base::cval::SizeInBytes, base::CValPublic> used_cpu_memory;
+
+ // GPU memory stats are not always available, so we put them behind
+ // base::optional so that we can enable them at runtime depending on system
+ // capabilities.
+ base::optional<base::CVal<base::cval::SizeInBytes, base::CValPublic> >
+ free_gpu_memory;
+ base::optional<base::CVal<base::cval::SizeInBytes, base::CValPublic> >
+ used_gpu_memory;
+
#if !defined(__LB_SHELL__FOR_RELEASE__)
- base::CVal<size_t, base::CValPublic> exe_memory;
+ base::CVal<base::cval::SizeInBytes, base::CValPublic> exe_memory;
#endif
- base::CVal<int64_t, base::CValPublic> app_lifetime_in_ms;
+ base::CVal<base::TimeDelta, base::CValPublic> app_lifetime;
};
void RegisterUserLogs();
diff --git a/src/cobalt/browser/browser.gyp b/src/cobalt/browser/browser.gyp
index 36effe7..88b34e9 100644
--- a/src/cobalt/browser/browser.gyp
+++ b/src/cobalt/browser/browser.gyp
@@ -49,6 +49,7 @@
'defines': [
'COBALT_IMAGE_CACHE_SIZE_IN_BYTES=<(image_cache_size_in_bytes)',
'COBALT_REMOTE_TYPEFACE_CACHE_SIZE_IN_BYTES=<(remote_typeface_cache_size_in_bytes)',
+ 'COBALT_IMAGE_CACHE_CAPACITY_MULTIPLIER_WHEN_PLAYING_VIDEO=<(image_cache_capacity_multiplier_when_playing_video)',
],
'dependencies': [
'<(DEPTH)/cobalt/account/account.gyp:account',
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index 55e33b9..cd3c605 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -249,6 +249,8 @@
array_buffer_allocator_.get();
options.dom_settings_options.array_buffer_cache = array_buffer_cache_.get();
#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)),
diff --git a/src/cobalt/browser/global_constructors_idls_idl_files_list.tmp b/src/cobalt/browser/global_constructors_idls_idl_files_list.tmp
deleted file mode 100644
index f212dcf..0000000
--- a/src/cobalt/browser/global_constructors_idls_idl_files_list.tmp
+++ /dev/null
@@ -1,143 +0,0 @@
-../audio/AudioBuffer.idl
-../audio/AudioBufferSourceNode.idl
-../audio/AudioContext.idl
-../audio/AudioDestinationNode.idl
-../audio/AudioNode.idl
-../cssom/CSSConditionRule.idl
-../cssom/CSSGroupingRule.idl
-../cssom/CSSFontFaceRule.idl
-../cssom/CSSMediaRule.idl
-../cssom/CSSKeyframeRule.idl
-../cssom/CSSKeyframesRule.idl
-../cssom/CSSRule.idl
-../cssom/CSSRuleList.idl
-../cssom/CSSStyleDeclaration.idl
-../cssom/CSSStyleRule.idl
-../cssom/CSSStyleSheet.idl
-../cssom/MediaList.idl
-../cssom/StyleSheet.idl
-../cssom/StyleSheetList.idl
-../debug/DebugHub.idl
-../debug/Debugger.idl
-../debug/DebuggerEventTarget.idl
-../debug/DebugScriptRunner.idl
-../dom/AnimationEvent.idl
-../dom/ArrayBuffer.idl
-../dom/ArrayBufferView.idl
-../dom/Attr.idl
-../dom/Blob.idl
-../dom/CDATASection.idl
-../dom/CharacterData.idl
-../dom/Comment.idl
-../dom/Console.idl
-../dom/Crypto.idl
-../dom/DataView.idl
-../dom/Document.idl
-../dom/DocumentTimeline.idl
-../dom/DocumentType.idl
-../dom/DOMException.idl
-../dom/DOMImplementation.idl
-../dom/DOMParser.idl
-../dom/DOMRect.idl
-../dom/DOMRectList.idl
-../dom/DOMRectReadOnly.idl
-../dom/DOMStringMap.idl
-../dom/DOMTokenList.idl
-../dom/Element.idl
-../dom/Event.idl
-../dom/EventListener.idl
-../dom/EventTarget.idl
-../dom/Float32Array.idl
-../dom/Float64Array.idl
-../dom/FocusEvent.idl
-../dom/History.idl
-../dom/HTMLAnchorElement.idl
-../dom/HTMLBodyElement.idl
-../dom/HTMLBRElement.idl
-../dom/HTMLCollection.idl
-../dom/HTMLDivElement.idl
-../dom/HTMLElement.idl
-../dom/HTMLHeadElement.idl
-../dom/HTMLHeadingElement.idl
-../dom/HTMLHtmlElement.idl
-../dom/HTMLImageElement.idl
-../dom/HTMLLinkElement.idl
-../dom/HTMLMediaElement.idl
-../dom/HTMLMetaElement.idl
-../dom/HTMLParagraphElement.idl
-../dom/HTMLScriptElement.idl
-../dom/HTMLSpanElement.idl
-../dom/HTMLStyleElement.idl
-../dom/HTMLTitleElement.idl
-../dom/HTMLUnknownElement.idl
-../dom/HTMLVideoElement.idl
-../dom/KeyboardEvent.idl
-../dom/Location.idl
-../dom/MediaError.idl
-../dom/MediaKeyCompleteEvent.idl
-../dom/MediaKeyError.idl
-../dom/MediaKeyErrorEvent.idl
-../dom/MediaKeyMessageEvent.idl
-../dom/MediaKeyNeededEvent.idl
-../dom/MediaQueryList.idl
-../dom/MediaSource.idl
-../dom/MimeTypeArray.idl
-../dom/NamedNodeMap.idl
-../dom/Navigator.idl
-../dom/Node.idl
-../dom/NodeList.idl
-../dom/Performance.idl
-../dom/PerformanceTiming.idl
-../dom/PluginArray.idl
-../dom/ProgressEvent.idl
-../dom/Screen.idl
-../dom/SecurityPolicyViolationEvent.idl
-../dom/SourceBuffer.idl
-../dom/SourceBufferList.idl
-../dom/Storage.idl
-../dom/StorageEvent.idl
-../dom/TestRunner.idl
-../dom/Text.idl
-../dom/TimeRanges.idl
-../dom/TransitionEvent.idl
-../dom/UIEvent.idl
-../dom/Uint16Array.idl
-../dom/Uint32Array.idl
-../dom/Uint8Array.idl
-../dom/URL.idl
-../dom/VideoPlaybackQuality.idl
-../dom/Window.idl
-../dom/XMLDocument.idl
-../dom/XMLSerializer.idl
-../h5vcc/dial/DialHttpRequest.idl
-../h5vcc/dial/DialHttpResponse.idl
-../h5vcc/dial/DialServer.idl
-../h5vcc/H5vcc.idl
-../h5vcc/H5vccAccountInfo.idl
-../h5vcc/H5vccAccountManager.idl
-../h5vcc/H5vccAudioConfig.idl
-../h5vcc/H5vccAudioConfigArray.idl
-../h5vcc/H5vccCVal.idl
-../h5vcc/H5vccCValKeyList.idl
-../h5vcc/H5vccRuntime.idl
-../h5vcc/H5vccRuntimeEventTarget.idl
-../h5vcc/H5vccSettings.idl
-../h5vcc/H5vccStorage.idl
-../h5vcc/H5vccSystem.idl
-../speech/SpeechRecognition.idl
-../speech/SpeechRecognitionAlternative.idl
-../speech/SpeechRecognitionError.idl
-../speech/SpeechRecognitionEvent.idl
-../speech/SpeechRecognitionResult.idl
-../speech/SpeechRecognitionResultList.idl
-../web_animations/Animatable.idl
-../web_animations/Animation.idl
-../web_animations/AnimationEffectReadOnly.idl
-../web_animations/AnimationEffectTimingReadOnly.idl
-../web_animations/AnimationTimeline.idl
-../web_animations/Keyframe.idl
-../web_animations/KeyframeEffectReadOnly.idl
-../webdriver/ScriptExecutor.idl
-../xhr/XMLHttpRequest.idl
-../xhr/XMLHttpRequestEventTarget.idl
-../xhr/XMLHttpRequestUpload.idl
diff --git a/src/cobalt/browser/global_objects_idl_files_list.tmp b/src/cobalt/browser/global_objects_idl_files_list.tmp
deleted file mode 100644
index f212dcf..0000000
--- a/src/cobalt/browser/global_objects_idl_files_list.tmp
+++ /dev/null
@@ -1,143 +0,0 @@
-../audio/AudioBuffer.idl
-../audio/AudioBufferSourceNode.idl
-../audio/AudioContext.idl
-../audio/AudioDestinationNode.idl
-../audio/AudioNode.idl
-../cssom/CSSConditionRule.idl
-../cssom/CSSGroupingRule.idl
-../cssom/CSSFontFaceRule.idl
-../cssom/CSSMediaRule.idl
-../cssom/CSSKeyframeRule.idl
-../cssom/CSSKeyframesRule.idl
-../cssom/CSSRule.idl
-../cssom/CSSRuleList.idl
-../cssom/CSSStyleDeclaration.idl
-../cssom/CSSStyleRule.idl
-../cssom/CSSStyleSheet.idl
-../cssom/MediaList.idl
-../cssom/StyleSheet.idl
-../cssom/StyleSheetList.idl
-../debug/DebugHub.idl
-../debug/Debugger.idl
-../debug/DebuggerEventTarget.idl
-../debug/DebugScriptRunner.idl
-../dom/AnimationEvent.idl
-../dom/ArrayBuffer.idl
-../dom/ArrayBufferView.idl
-../dom/Attr.idl
-../dom/Blob.idl
-../dom/CDATASection.idl
-../dom/CharacterData.idl
-../dom/Comment.idl
-../dom/Console.idl
-../dom/Crypto.idl
-../dom/DataView.idl
-../dom/Document.idl
-../dom/DocumentTimeline.idl
-../dom/DocumentType.idl
-../dom/DOMException.idl
-../dom/DOMImplementation.idl
-../dom/DOMParser.idl
-../dom/DOMRect.idl
-../dom/DOMRectList.idl
-../dom/DOMRectReadOnly.idl
-../dom/DOMStringMap.idl
-../dom/DOMTokenList.idl
-../dom/Element.idl
-../dom/Event.idl
-../dom/EventListener.idl
-../dom/EventTarget.idl
-../dom/Float32Array.idl
-../dom/Float64Array.idl
-../dom/FocusEvent.idl
-../dom/History.idl
-../dom/HTMLAnchorElement.idl
-../dom/HTMLBodyElement.idl
-../dom/HTMLBRElement.idl
-../dom/HTMLCollection.idl
-../dom/HTMLDivElement.idl
-../dom/HTMLElement.idl
-../dom/HTMLHeadElement.idl
-../dom/HTMLHeadingElement.idl
-../dom/HTMLHtmlElement.idl
-../dom/HTMLImageElement.idl
-../dom/HTMLLinkElement.idl
-../dom/HTMLMediaElement.idl
-../dom/HTMLMetaElement.idl
-../dom/HTMLParagraphElement.idl
-../dom/HTMLScriptElement.idl
-../dom/HTMLSpanElement.idl
-../dom/HTMLStyleElement.idl
-../dom/HTMLTitleElement.idl
-../dom/HTMLUnknownElement.idl
-../dom/HTMLVideoElement.idl
-../dom/KeyboardEvent.idl
-../dom/Location.idl
-../dom/MediaError.idl
-../dom/MediaKeyCompleteEvent.idl
-../dom/MediaKeyError.idl
-../dom/MediaKeyErrorEvent.idl
-../dom/MediaKeyMessageEvent.idl
-../dom/MediaKeyNeededEvent.idl
-../dom/MediaQueryList.idl
-../dom/MediaSource.idl
-../dom/MimeTypeArray.idl
-../dom/NamedNodeMap.idl
-../dom/Navigator.idl
-../dom/Node.idl
-../dom/NodeList.idl
-../dom/Performance.idl
-../dom/PerformanceTiming.idl
-../dom/PluginArray.idl
-../dom/ProgressEvent.idl
-../dom/Screen.idl
-../dom/SecurityPolicyViolationEvent.idl
-../dom/SourceBuffer.idl
-../dom/SourceBufferList.idl
-../dom/Storage.idl
-../dom/StorageEvent.idl
-../dom/TestRunner.idl
-../dom/Text.idl
-../dom/TimeRanges.idl
-../dom/TransitionEvent.idl
-../dom/UIEvent.idl
-../dom/Uint16Array.idl
-../dom/Uint32Array.idl
-../dom/Uint8Array.idl
-../dom/URL.idl
-../dom/VideoPlaybackQuality.idl
-../dom/Window.idl
-../dom/XMLDocument.idl
-../dom/XMLSerializer.idl
-../h5vcc/dial/DialHttpRequest.idl
-../h5vcc/dial/DialHttpResponse.idl
-../h5vcc/dial/DialServer.idl
-../h5vcc/H5vcc.idl
-../h5vcc/H5vccAccountInfo.idl
-../h5vcc/H5vccAccountManager.idl
-../h5vcc/H5vccAudioConfig.idl
-../h5vcc/H5vccAudioConfigArray.idl
-../h5vcc/H5vccCVal.idl
-../h5vcc/H5vccCValKeyList.idl
-../h5vcc/H5vccRuntime.idl
-../h5vcc/H5vccRuntimeEventTarget.idl
-../h5vcc/H5vccSettings.idl
-../h5vcc/H5vccStorage.idl
-../h5vcc/H5vccSystem.idl
-../speech/SpeechRecognition.idl
-../speech/SpeechRecognitionAlternative.idl
-../speech/SpeechRecognitionError.idl
-../speech/SpeechRecognitionEvent.idl
-../speech/SpeechRecognitionResult.idl
-../speech/SpeechRecognitionResultList.idl
-../web_animations/Animatable.idl
-../web_animations/Animation.idl
-../web_animations/AnimationEffectReadOnly.idl
-../web_animations/AnimationEffectTimingReadOnly.idl
-../web_animations/AnimationTimeline.idl
-../web_animations/Keyframe.idl
-../web_animations/KeyframeEffectReadOnly.idl
-../webdriver/ScriptExecutor.idl
-../xhr/XMLHttpRequest.idl
-../xhr/XMLHttpRequestEventTarget.idl
-../xhr/XMLHttpRequestUpload.idl
diff --git a/src/cobalt/browser/interfaces_info_individual_static_idl_files_list.tmp b/src/cobalt/browser/interfaces_info_individual_static_idl_files_list.tmp
deleted file mode 100644
index e4de45c..0000000
--- a/src/cobalt/browser/interfaces_info_individual_static_idl_files_list.tmp
+++ /dev/null
@@ -1,170 +0,0 @@
-../audio/AudioBuffer.idl
-../audio/AudioBufferSourceNode.idl
-../audio/AudioContext.idl
-../audio/AudioDestinationNode.idl
-../audio/AudioNode.idl
-../cssom/CSSConditionRule.idl
-../cssom/CSSGroupingRule.idl
-../cssom/CSSFontFaceRule.idl
-../cssom/CSSMediaRule.idl
-../cssom/CSSKeyframeRule.idl
-../cssom/CSSKeyframesRule.idl
-../cssom/CSSRule.idl
-../cssom/CSSRuleList.idl
-../cssom/CSSStyleDeclaration.idl
-../cssom/CSSStyleRule.idl
-../cssom/CSSStyleSheet.idl
-../cssom/MediaList.idl
-../cssom/StyleSheet.idl
-../cssom/StyleSheetList.idl
-../debug/DebugHub.idl
-../debug/Debugger.idl
-../debug/DebuggerEventTarget.idl
-../debug/DebugScriptRunner.idl
-../dom/AnimationEvent.idl
-../dom/ArrayBuffer.idl
-../dom/ArrayBufferView.idl
-../dom/Attr.idl
-../dom/Blob.idl
-../dom/CDATASection.idl
-../dom/CharacterData.idl
-../dom/Comment.idl
-../dom/Console.idl
-../dom/Crypto.idl
-../dom/DataView.idl
-../dom/Document.idl
-../dom/DocumentTimeline.idl
-../dom/DocumentType.idl
-../dom/DOMException.idl
-../dom/DOMImplementation.idl
-../dom/DOMParser.idl
-../dom/DOMRect.idl
-../dom/DOMRectList.idl
-../dom/DOMRectReadOnly.idl
-../dom/DOMStringMap.idl
-../dom/DOMTokenList.idl
-../dom/Element.idl
-../dom/Event.idl
-../dom/EventListener.idl
-../dom/EventTarget.idl
-../dom/Float32Array.idl
-../dom/Float64Array.idl
-../dom/FocusEvent.idl
-../dom/History.idl
-../dom/HTMLAnchorElement.idl
-../dom/HTMLBodyElement.idl
-../dom/HTMLBRElement.idl
-../dom/HTMLCollection.idl
-../dom/HTMLDivElement.idl
-../dom/HTMLElement.idl
-../dom/HTMLHeadElement.idl
-../dom/HTMLHeadingElement.idl
-../dom/HTMLHtmlElement.idl
-../dom/HTMLImageElement.idl
-../dom/HTMLLinkElement.idl
-../dom/HTMLMediaElement.idl
-../dom/HTMLMetaElement.idl
-../dom/HTMLParagraphElement.idl
-../dom/HTMLScriptElement.idl
-../dom/HTMLSpanElement.idl
-../dom/HTMLStyleElement.idl
-../dom/HTMLTitleElement.idl
-../dom/HTMLUnknownElement.idl
-../dom/HTMLVideoElement.idl
-../dom/KeyboardEvent.idl
-../dom/Location.idl
-../dom/MediaError.idl
-../dom/MediaKeyCompleteEvent.idl
-../dom/MediaKeyError.idl
-../dom/MediaKeyErrorEvent.idl
-../dom/MediaKeyMessageEvent.idl
-../dom/MediaKeyNeededEvent.idl
-../dom/MediaQueryList.idl
-../dom/MediaSource.idl
-../dom/MimeTypeArray.idl
-../dom/NamedNodeMap.idl
-../dom/Navigator.idl
-../dom/Node.idl
-../dom/NodeList.idl
-../dom/Performance.idl
-../dom/PerformanceTiming.idl
-../dom/PluginArray.idl
-../dom/ProgressEvent.idl
-../dom/Screen.idl
-../dom/SecurityPolicyViolationEvent.idl
-../dom/SourceBuffer.idl
-../dom/SourceBufferList.idl
-../dom/Storage.idl
-../dom/StorageEvent.idl
-../dom/TestRunner.idl
-../dom/Text.idl
-../dom/TimeRanges.idl
-../dom/TransitionEvent.idl
-../dom/UIEvent.idl
-../dom/Uint16Array.idl
-../dom/Uint32Array.idl
-../dom/Uint8Array.idl
-../dom/URL.idl
-../dom/VideoPlaybackQuality.idl
-../dom/Window.idl
-../dom/XMLDocument.idl
-../dom/XMLSerializer.idl
-../h5vcc/dial/DialHttpRequest.idl
-../h5vcc/dial/DialHttpResponse.idl
-../h5vcc/dial/DialServer.idl
-../h5vcc/H5vcc.idl
-../h5vcc/H5vccAccountInfo.idl
-../h5vcc/H5vccAccountManager.idl
-../h5vcc/H5vccAudioConfig.idl
-../h5vcc/H5vccAudioConfigArray.idl
-../h5vcc/H5vccCVal.idl
-../h5vcc/H5vccCValKeyList.idl
-../h5vcc/H5vccRuntime.idl
-../h5vcc/H5vccRuntimeEventTarget.idl
-../h5vcc/H5vccSettings.idl
-../h5vcc/H5vccStorage.idl
-../h5vcc/H5vccSystem.idl
-../speech/SpeechRecognition.idl
-../speech/SpeechRecognitionAlternative.idl
-../speech/SpeechRecognitionError.idl
-../speech/SpeechRecognitionEvent.idl
-../speech/SpeechRecognitionResult.idl
-../speech/SpeechRecognitionResultList.idl
-../web_animations/Animatable.idl
-../web_animations/Animation.idl
-../web_animations/AnimationEffectReadOnly.idl
-../web_animations/AnimationEffectTimingReadOnly.idl
-../web_animations/AnimationTimeline.idl
-../web_animations/Keyframe.idl
-../web_animations/KeyframeEffectReadOnly.idl
-../webdriver/ScriptExecutor.idl
-../xhr/XMLHttpRequest.idl
-../xhr/XMLHttpRequestEventTarget.idl
-../xhr/XMLHttpRequestUpload.idl
-../cssom/LinkStyle.idl
-../dom/Document_CSSOM.idl
-../dom/Document_HTML5.idl
-../dom/Document_WebAnimationsAPI.idl
-../dom/Element_CSSOMView.idl
-../dom/Element_DOMParsingAndSerialization.idl
-../dom/ElementCSSInlineStyle.idl
-../dom/GlobalCrypto.idl
-../dom/GlobalEventHandlers.idl
-../dom/HTMLElement_CSSOMView.idl
-../dom/NavigatorID.idl
-../dom/NavigatorLanguage.idl
-../dom/NavigatorPlugins.idl
-../dom/NavigatorStorageUtils.idl
-../dom/NonDocumentTypeChildNode.idl
-../dom/NonElementParentNode.idl
-../dom/ParentNode.idl
-../dom/Performance_HighResolutionTime.idl
-../dom/URLUtils.idl
-../dom/Window_AnimationTiming.idl
-../dom/Window_CSSOM.idl
-../dom/Window_CSSOMView.idl
-../dom/Window_Performance.idl
-../dom/WindowEventHandlers.idl
-../dom/WindowLocalStorage.idl
-../dom/WindowSessionStorage.idl
-../dom/WindowTimers.idl
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 372db0d..b80a9bd 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -154,6 +154,12 @@
// ImageCache that is used to manage image cache logic.
scoped_ptr<loader::image::ImageCache> image_cache_;
+ // The reduced cache capacity manager can be used to force a reduced image
+ // cache over periods of time where memory is known to be restricted, such
+ // as when a video is playing.
+ scoped_ptr<loader::image::ReducedCacheCapacityManager>
+ reduced_image_cache_capacity_manager_;
+
// RemoteTypefaceCache that is used to manage loading and caching typefaces
// from URLs.
scoped_ptr<loader::font::RemoteTypefaceCache> remote_typeface_cache_;
@@ -263,6 +269,11 @@
data.resource_provider, fetcher_factory_.get());
DCHECK(image_cache_);
+ reduced_image_cache_capacity_manager_.reset(
+ new loader::image::ReducedCacheCapacityManager(
+ image_cache_.get(),
+ data.options.image_cache_capacity_multiplier_when_playing_video));
+
DCHECK_LE(0, data.options.remote_typeface_cache_capacity);
remote_typeface_cache_ = loader::font::CreateRemoteTypefaceCache(
base::StringPrintf("Memory.%s.RemoteTypefaceCache", name_.c_str()),
@@ -297,7 +308,8 @@
window_ = new dom::Window(
data.window_dimensions.width(), data.window_dimensions.height(),
css_parser_.get(), dom_parser_.get(), fetcher_factory_.get(),
- data.resource_provider, image_cache_.get(), remote_typeface_cache_.get(),
+ data.resource_provider, image_cache_.get(),
+ reduced_image_cache_capacity_manager_.get(), remote_typeface_cache_.get(),
local_storage_database_.get(), data.media_module, data.media_module,
execution_state_.get(), script_runner_.get(),
media_source_registry_.get(),
@@ -538,7 +550,8 @@
COBALT_REMOTE_TYPEFACE_CACHE_SIZE_IN_BYTES),
csp_enforcement_mode(dom::kCspEnforcementEnable),
csp_insecure_allowed_token(0),
- track_event_stats(false) {}
+ track_event_stats(false),
+ image_cache_capacity_multiplier_when_playing_video(1.0f) {}
WebModule::WebModule(
const GURL& initial_url,
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index 854579a..a4742cb 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -134,6 +134,12 @@
// Whether or not the web module's stat tracker should track event stats.
bool track_event_stats;
+
+ // If set to something other than 1.0f, when a video starts to play, the
+ // image cache will be flushed and temporarily multiplied by this value (
+ // must be less than or equal to 1.0f) until the video ends. This can
+ // help for platforms that are low on image memory while playing a video.
+ float image_cache_capacity_multiplier_when_playing_video;
};
typedef layout::LayoutManager::LayoutResults LayoutResults;
diff --git a/src/cobalt/browser/web_module_stat_tracker.cc b/src/cobalt/browser/web_module_stat_tracker.cc
index 313711a..10bdf94 100644
--- a/src/cobalt/browser/web_module_stat_tracker.cc
+++ b/src/cobalt/browser/web_module_stat_tracker.cc
@@ -43,7 +43,7 @@
stop_watches_.push_back(
base::StopWatch(i, base::StopWatch::kAutoStartOff, this));
}
- stop_watch_durations_.resize(kNumStopWatchTypes, 0);
+ stop_watch_durations_.resize(kNumStopWatchTypes, base::TimeDelta());
}
WebModuleStatTracker::~WebModuleStatTracker() { EndCurrentEvent(false); }
@@ -104,38 +104,46 @@
count_layout_boxes_destroyed(
StringPrintf("Event.Count.%s.Layout.Box.Destroyed", name.c_str()), 0,
"Number of boxes destroyed."),
- duration_total(StringPrintf("Event.Duration.%s", name.c_str()), 0,
+ duration_total(StringPrintf("Event.Duration.%s", name.c_str()),
+ base::TimeDelta(),
"Total duration of the event (in microseconds). This is "
"the time elapsed from the event injection until the "
"render tree is produced."),
duration_dom_inject_event(
- StringPrintf("Event.Duration.%s.DOM.InjectEvent", name.c_str()), 0,
+ StringPrintf("Event.Duration.%s.DOM.InjectEvent", name.c_str()),
+ base::TimeDelta(),
"Injection duration, which includes JS, for event (in "
"microseconds). This does not include subsequent DOM and Layout "
"processing."),
duration_dom_update_computed_style(
StringPrintf("Event.Duration.%s.DOM.UpdateComputedStyle",
name.c_str()),
- 0, "UpdateComputedStyle duration for event (in microseconds)."),
+ base::TimeDelta(),
+ "UpdateComputedStyle duration for event (in microseconds)."),
duration_layout_box_tree(
- StringPrintf("Event.Duration.%s.Layout.BoxTree", name.c_str()), 0,
+ StringPrintf("Event.Duration.%s.Layout.BoxTree", name.c_str()),
+ base::TimeDelta(),
"Layout box tree duration for event (in microseconds)."),
duration_layout_box_generation(
StringPrintf("Event.Duration.%s.Layout.BoxTree.BoxGeneration",
name.c_str()),
- 0, "BoxGeneration duration for event (in microseconds)."),
+ base::TimeDelta(),
+ "BoxGeneration duration for event (in microseconds)."),
duration_layout_update_used_sizes(
StringPrintf("Event.Duration.%s.Layout.BoxTree.UpdateUsedSizes",
name.c_str()),
- 0, "UpdateUsedSizes duration for event (in microseconds)."),
+ base::TimeDelta(),
+ "UpdateUsedSizes duration for event (in microseconds)."),
duration_layout_render_and_animate(
StringPrintf("Event.Duration.%s.Layout.RenderAndAnimate",
name.c_str()),
- 0, "RenderAndAnimate duration for event (in microseconds).") {}
+ base::TimeDelta(),
+ "RenderAndAnimate duration for event (in microseconds).") {}
bool WebModuleStatTracker::IsStopWatchEnabled(int /*id*/) const { return true; }
-void WebModuleStatTracker::OnStopWatchStopped(int id, int64 time_elapsed) {
+void WebModuleStatTracker::OnStopWatchStopped(int id,
+ base::TimeDelta time_elapsed) {
stop_watch_durations_[static_cast<size_t>(id)] += time_elapsed;
}
@@ -144,7 +152,7 @@
return;
}
- stop_watch_durations_[kStopWatchTypeEvent] = 0;
+ stop_watch_durations_[kStopWatchTypeEvent] = base::TimeDelta();
stop_watches_[kStopWatchTypeEvent].Stop();
dom_stat_tracker_->DisableStopWatches();
layout_stat_tracker_->DisableStopWatches();
@@ -166,8 +174,9 @@
layout_stat_tracker_->boxes_destroyed_count();
// Update event durations
- int64 event_injection_duration = dom_stat_tracker_->GetStopWatchTypeDuration(
- dom::DomStatTracker::kStopWatchTypeInjectEvent);
+ base::TimeDelta event_injection_duration =
+ dom_stat_tracker_->GetStopWatchTypeDuration(
+ dom::DomStatTracker::kStopWatchTypeInjectEvent);
// If a render tree was produced, then the total duration is the duration from
// when the event started until now. Otherwise, the injection duration is
// used. This is because some events do not trigger a new layout. In these
diff --git a/src/cobalt/browser/web_module_stat_tracker.h b/src/cobalt/browser/web_module_stat_tracker.h
index b10554c..8e9dbd3 100644
--- a/src/cobalt/browser/web_module_stat_tracker.h
+++ b/src/cobalt/browser/web_module_stat_tracker.h
@@ -79,18 +79,22 @@
base::CVal<int, base::CValPublic> count_layout_boxes_destroyed;
// Duration-related
- base::CVal<int64, base::CValPublic> duration_total;
- base::CVal<int64, base::CValPublic> duration_dom_inject_event;
- base::CVal<int64, base::CValPublic> duration_dom_update_computed_style;
- base::CVal<int64, base::CValPublic> duration_layout_box_tree;
- base::CVal<int64, base::CValPublic> duration_layout_box_generation;
- base::CVal<int64, base::CValPublic> duration_layout_update_used_sizes;
- base::CVal<int64, base::CValPublic> duration_layout_render_and_animate;
+ base::CVal<base::TimeDelta, base::CValPublic> duration_total;
+ base::CVal<base::TimeDelta, base::CValPublic> duration_dom_inject_event;
+ base::CVal<base::TimeDelta, base::CValPublic>
+ duration_dom_update_computed_style;
+ base::CVal<base::TimeDelta, base::CValPublic> duration_layout_box_tree;
+ base::CVal<base::TimeDelta, base::CValPublic>
+ duration_layout_box_generation;
+ base::CVal<base::TimeDelta, base::CValPublic>
+ duration_layout_update_used_sizes;
+ base::CVal<base::TimeDelta, base::CValPublic>
+ duration_layout_render_and_animate;
};
// From base::StopWatchOwner
bool IsStopWatchEnabled(int id) const OVERRIDE;
- void OnStopWatchStopped(int id, int64 time_elapsed) OVERRIDE;
+ void OnStopWatchStopped(int id, base::TimeDelta time_elapsed) OVERRIDE;
// End the current event if one is active. This triggers an update of all
// |EventStats| for the event.
@@ -110,7 +114,7 @@
// Stop watch-related
std::vector<base::StopWatch> stop_watches_;
- std::vector<int64> stop_watch_durations_;
+ std::vector<base::TimeDelta> stop_watch_durations_;
};
} // namespace browser
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index f179e93..0e34392 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-10999
\ No newline at end of file
+11130
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index cfbf8bf..3e07aab 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -153,6 +153,15 @@
# typefaces downloaded from a web page.
'remote_typeface_cache_size_in_bytes%': 5 * 1024 * 1024,
+ # Modifying this value to be non-1.0f will result in the image cache
+ # capacity being cleared and then temporarily reduced for the duration that
+ # a video is playing. This can be useful for some platforms if they are
+ # particularly constrained for (GPU) memory during video playback. When
+ # playing a video, the image cache is reduced to:
+ # image_cache_size_in_bytes *
+ # image_cache_capacity_multiplier_when_playing_video.
+ 'image_cache_capacity_multiplier_when_playing_video%': '1.0f',
+
# Compiler configuration.
# The following variables are used to specify compiler and linker
diff --git a/src/cobalt/content/fonts/MinimalRoboto.ttf b/src/cobalt/content/fonts/MinimalRoboto.ttf
new file mode 100644
index 0000000..abfa5e2
--- /dev/null
+++ b/src/cobalt/content/fonts/MinimalRoboto.ttf
Binary files differ
diff --git a/src/cobalt/content/fonts/README.md b/src/cobalt/content/fonts/README.md
new file mode 100644
index 0000000..acee96c
--- /dev/null
+++ b/src/cobalt/content/fonts/README.md
@@ -0,0 +1,29 @@
+# Generating a minimal font for devices with small space requirements
+
+[GlyphIGo](https://github.com/pettarin/glyphIgo) was used to generate a subset
+of the Roboto font
+
+`cobalt/content/fonts` contains a script called `create_minimized_roboto.sh`
+that can help recreate minimized font if needed
+
+Steps:
+
+1. `cd src/cobalt/content/fonts`
+1. `./create_minimized_roboto.sh`
+1. Download `fontforge` using apt. `sudo apt install fontforge`
+1. In `fontforge`, navigate the menu: `Encoding`->`Reencode`->`Glyph Order`.
+Scroll to the top, find the first glyph. By spec, this glyph is called
+`.notdef`, and is used when this font is the default font and there glyph for a
+character we're looking for is missing in the file. Often this will be blank
+after the last step, which can be undesired.
+1. Copy `.notdef` glyph from a different font.
+ 1. Open a different font.
+ 1. Find the `.notdef` glyph.
+ 1. Select the glyph without opening it.
+ 1. Navigate the menu: `Edit`->`Copy` from the font you want to copy from.
+ 1. Switch focus to the minimized font.
+ 1. Select `.notdef` glyph.
+ 1. Navigate the menu: `Edit`->`Paste`.
+1. Export the font using the menu: `File`->`Generate Fonts...`, make sure that
+the file name is correct.
+1. Fix any errors if found, or if you can.
diff --git a/src/cobalt/content/fonts/create_minimized_roboto.sh b/src/cobalt/content/fonts/create_minimized_roboto.sh
new file mode 100755
index 0000000..02ef746
--- /dev/null
+++ b/src/cobalt/content/fonts/create_minimized_roboto.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+# Copyright 2016 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script can be used as a convenience to launch an app under a Xephyr
+# X server. It will first launch Xephyr, and then launch the executable given
+# on the command line such that it targets and will appear within the Xephyr
+# window. It shuts down Xephyr after the main executable finishes.
+set -e
+
+SCRIPT_FILE="$(readlink -f "${BASH_SOURCE[0]}")"
+SCRIPT_DIR="$(dirname "${script_file}")"
+SCRIPT_NAME="$(basename "${script_file}")"
+
+GLPHYIGO_SRC=https://raw.githubusercontent.com/pettarin/glyphIgo/bb91c5f3746bcb17395acb6ffd436c982c41bd8a/src/glyphIgo.py
+
+function log() {
+ echo "${SCRIPT_NAME}: $@"
+}
+
+function deleteDirectory() {
+ if [[ -z "$1" ]]; then
+ log "deleteDirectory with no argument"
+ exit 1
+ fi
+
+ # Only delete target if it is an existing directory.
+ if [[ -d "$1" ]]; then
+ log "Deleting directory: $1"
+ rm -rf "$1"
+ fi
+}
+
+function deleteTempTrap() {
+ # If something interrupted the script, it might have printed a partial line.
+ echo
+ deleteDirectory "${TEMP_DIR}"
+}
+
+TEMP_DIR="$(mktemp -dt "${SCRIPT_NAME}.XXXXXXXXXX")"
+trap deleteTempTrap EXIT
+
+TEMP_GLYPHIGO="$TEMP_DIR/glyphIgo.py"
+
+# download the file
+curl -sSL $GLPHYIGO_SRC -o $TEMP_GLYPHIGO
+
+python $TEMP_GLYPHIGO subset --plain \
+ "$SCRIPT_DIR/minimized_roboto_subset_chars.txt" \
+ -f "$SCRIPT_DIR/Roboto-Regular.ttf" \
+ -o "$SCRIPT_DIR/minimized_roboto_needs_tofu.ttf"
+
+# Clear delete trap now that we have succeeded.
+trap - EXIT
+
+# Delete our temp directory on graceful exit.
+deleteDirectory "${TEMP_DIR}"
+
diff --git a/src/cobalt/content/fonts/fonts.xml b/src/cobalt/content/fonts/fonts.xml
index 9b1d31f..3e1ec53 100644
--- a/src/cobalt/content/fonts/fonts.xml
+++ b/src/cobalt/content/fonts/fonts.xml
@@ -27,6 +27,11 @@
<alias name="roboto" to="sans-serif" />
<alias name="tahoma" to="sans-serif" />
<alias name="verdana" to="sans-serif" />
+ <!-- Ideally, this font should only be used if there are no other fonts in
+ our final image. -->
+ <family name="Minimal Roboto">
+ <font weight="400" style="normal">MinimalRoboto.ttf</font>
+ </family>
<family name="serif">
<font weight="400" style="normal">NotoSerif-Regular.ttf</font>
<font weight="400" style="italic">NotoSerif-Italic.ttf</font>
@@ -281,4 +286,4 @@
<family fallback="true" pages="0,24,32,36-37,48,254">
<font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font>
</family>
-</familyset>
\ No newline at end of file
+</familyset>
diff --git a/src/cobalt/content/fonts/minimized_roboto_subset_chars.txt b/src/cobalt/content/fonts/minimized_roboto_subset_chars.txt
new file mode 100644
index 0000000..75498f5
--- /dev/null
+++ b/src/cobalt/content/fonts/minimized_roboto_subset_chars.txt
@@ -0,0 +1 @@
+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 (),.-/!
\ No newline at end of file
diff --git a/src/cobalt/cssom/complex_selector.cc b/src/cobalt/cssom/complex_selector.cc
index 5eb9047..b164c77 100644
--- a/src/cobalt/cssom/complex_selector.cc
+++ b/src/cobalt/cssom/complex_selector.cc
@@ -16,6 +16,7 @@
#include "cobalt/cssom/complex_selector.h"
+#include "base/logging.h"
#include "cobalt/cssom/combinator.h"
#include "cobalt/cssom/compound_selector.h"
#include "cobalt/cssom/selector_visitor.h"
@@ -23,6 +24,8 @@
namespace cobalt {
namespace cssom {
+const int ComplexSelector::kCombinatorLimit = 32;
+
void ComplexSelector::Accept(SelectorVisitor* visitor) {
visitor->VisitComplexSelector(this);
}
@@ -39,6 +42,18 @@
scoped_ptr<Combinator> combinator,
scoped_ptr<CompoundSelector> compound_selector) {
DCHECK(first_selector_);
+ DCHECK(last_selector_);
+
+ if (combinator_count_ >= kCombinatorLimit) {
+ if (!combinator_limit_exceeded_) {
+ LOG(WARNING)
+ << "Maximum number of calls to AppendCombinatorAndSelector exceeded."
+ " Ignoring additional selectors.";
+ combinator_limit_exceeded_ = true;
+ }
+ return;
+ }
+
specificity_.AddFrom(compound_selector->GetSpecificity());
combinator->set_left_selector(last_selector_);
@@ -48,6 +63,8 @@
last_selector_->set_right_combinator(combinator.Pass());
last_selector_ = last_selector_->right_combinator()->right_selector();
+
+ combinator_count_++;
}
} // namespace cssom
diff --git a/src/cobalt/cssom/complex_selector.h b/src/cobalt/cssom/complex_selector.h
index d8d2cae..e20ef8a 100644
--- a/src/cobalt/cssom/complex_selector.h
+++ b/src/cobalt/cssom/complex_selector.h
@@ -35,7 +35,12 @@
// https://www.w3.org/TR/selectors4/#complex
class ComplexSelector : public Selector {
public:
- ComplexSelector() : last_selector_(NULL) {}
+ static const int kCombinatorLimit;
+
+ ComplexSelector()
+ : last_selector_(NULL),
+ combinator_count_(0),
+ combinator_limit_exceeded_(false) {}
~ComplexSelector() OVERRIDE {}
// From Selector.
@@ -48,6 +53,10 @@
CompoundSelector* first_selector() { return first_selector_.get(); }
CompoundSelector* last_selector() { return last_selector_; }
+ int combinator_count() {
+ return combinator_count_;
+ }
+
// For a chain of compound selectors separated by combinators, AppendSelector
// should be first called with the left most compound selector, then
// AppendCombinatorAndSelector should be called with each (combinator,
@@ -63,6 +72,9 @@
scoped_ptr<CompoundSelector> first_selector_;
Specificity specificity_;
+ int combinator_count_;
+ bool combinator_limit_exceeded_;
+
DISALLOW_COPY_AND_ASSIGN(ComplexSelector);
};
diff --git a/src/cobalt/cssom/selector_test.cc b/src/cobalt/cssom/selector_test.cc
index 090d9d7..c120db8 100644
--- a/src/cobalt/cssom/selector_test.cc
+++ b/src/cobalt/cssom/selector_test.cc
@@ -115,5 +115,42 @@
EXPECT_EQ(Specificity(1, 2, 3), complex_selector->GetSpecificity());
}
+TEST(SelectorTest, ComplexSelectorAppendCallLimit) {
+ {
+ scoped_ptr<ComplexSelector> complex_selector(new ComplexSelector());
+ complex_selector->AppendSelector(
+ make_scoped_ptr<CompoundSelector>(new CompoundSelector()));
+
+ for (int i = 0; i < ComplexSelector::kCombinatorLimit;
+ i++) {
+ scoped_ptr<CompoundSelector> compound_selector(new CompoundSelector());
+ scoped_ptr<ChildCombinator> child_combinator(new ChildCombinator());
+ complex_selector->AppendCombinatorAndSelector(
+ child_combinator.PassAs<Combinator>(), compound_selector.Pass());
+ }
+
+ EXPECT_EQ(complex_selector->combinator_count(),
+ ComplexSelector::kCombinatorLimit);
+ }
+
+ {
+ scoped_ptr<ComplexSelector> complex_selector(new ComplexSelector());
+ complex_selector->AppendSelector(
+ make_scoped_ptr<CompoundSelector>(new CompoundSelector()));
+
+ for (int i = 0;
+ i < 2 * ComplexSelector::kCombinatorLimit + 1;
+ i++) {
+ scoped_ptr<CompoundSelector> compound_selector(new CompoundSelector());
+ scoped_ptr<ChildCombinator> child_combinator(new ChildCombinator());
+ complex_selector->AppendCombinatorAndSelector(
+ child_combinator.PassAs<Combinator>(), compound_selector.Pass());
+ }
+
+ EXPECT_EQ(complex_selector->combinator_count(),
+ ComplexSelector::kCombinatorLimit);
+ }
+}
+
} // namespace cssom
} // namespace cobalt
diff --git a/src/cobalt/dom/comment_test.cc b/src/cobalt/dom/comment_test.cc
index 2b8773d..6de330b 100644
--- a/src/cobalt/dom/comment_test.cc
+++ b/src/cobalt/dom/comment_test.cc
@@ -42,7 +42,7 @@
CommentTest::CommentTest()
: html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "") {
+ NULL, NULL, NULL, NULL, "") {
EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
document_ = new Document(&html_element_context_);
}
diff --git a/src/cobalt/dom/document_test.cc b/src/cobalt/dom/document_test.cc
index 39e118d..ee0f442 100644
--- a/src/cobalt/dom/document_test.cc
+++ b/src/cobalt/dom/document_test.cc
@@ -66,8 +66,8 @@
: css_parser_(css_parser::Parser::Create()),
dom_stat_tracker_(new DomStatTracker("DocumentTest")),
html_element_context_(NULL, css_parser_.get(), NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, dom_stat_tracker_.get(),
- "") {
+ NULL, NULL, NULL, NULL, NULL,
+ dom_stat_tracker_.get(), "") {
EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
}
diff --git a/src/cobalt/dom/document_type_test.cc b/src/cobalt/dom/document_type_test.cc
index 1fc4b6a..90f51c3 100644
--- a/src/cobalt/dom/document_type_test.cc
+++ b/src/cobalt/dom/document_type_test.cc
@@ -27,7 +27,7 @@
protected:
DocumentTypeTest()
: html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, ""),
+ NULL, NULL, NULL, NULL, ""),
document_(new Document(&html_element_context_)) {}
~DocumentTypeTest() OVERRIDE {}
diff --git a/src/cobalt/dom/dom_implementation_test.cc b/src/cobalt/dom/dom_implementation_test.cc
index 6226a89..a9687aa 100644
--- a/src/cobalt/dom/dom_implementation_test.cc
+++ b/src/cobalt/dom/dom_implementation_test.cc
@@ -27,7 +27,8 @@
TEST(DOMImplementationTest, CreateDocumentShouldCreateXMLDocument) {
HTMLElementContext html_element_context(NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, "");
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ "");
scoped_refptr<DOMImplementation> dom_implementation =
new DOMImplementation(&html_element_context);
scoped_refptr<Document> document =
diff --git a/src/cobalt/dom/dom_parser_test.cc b/src/cobalt/dom/dom_parser_test.cc
index d3dd079..0e5cde6 100644
--- a/src/cobalt/dom/dom_parser_test.cc
+++ b/src/cobalt/dom/dom_parser_test.cc
@@ -49,6 +49,7 @@
NULL /* can_play_type_handler */, NULL /* web_media_player_factory */,
&stub_script_runner_, NULL /* media_source_registry */,
NULL /* resource_provider */, NULL /* image_cache */,
+ NULL /* reduced_image_cache_capacity_manager */,
NULL /* remote_typeface_cache */, NULL /* dom_stat_tracker */,
"" /* language */),
dom_parser_(new DOMParser(&html_element_context_)) {}
diff --git a/src/cobalt/dom/dom_stat_tracker.cc b/src/cobalt/dom/dom_stat_tracker.cc
index d5ca09f..003645c 100644
--- a/src/cobalt/dom/dom_stat_tracker.cc
+++ b/src/cobalt/dom/dom_stat_tracker.cc
@@ -30,7 +30,7 @@
update_matching_rules_count_(0),
update_computed_style_count_(0),
are_stop_watches_enabled_(false) {
- stop_watch_durations_.resize(kNumStopWatchTypes, 0);
+ stop_watch_durations_.resize(kNumStopWatchTypes, base::TimeDelta());
}
DomStatTracker::~DomStatTracker() {
@@ -52,7 +52,7 @@
update_computed_style_count_ = 0;
for (size_t i = 0; i < kNumStopWatchTypes; ++i) {
- stop_watch_durations_[i] = 0;
+ stop_watch_durations_[i] = base::TimeDelta();
}
}
@@ -70,7 +70,8 @@
void DomStatTracker::DisableStopWatches() { are_stop_watches_enabled_ = false; }
-int64 DomStatTracker::GetStopWatchTypeDuration(StopWatchType type) const {
+base::TimeDelta DomStatTracker::GetStopWatchTypeDuration(
+ StopWatchType type) const {
return stop_watch_durations_[type];
}
@@ -78,7 +79,7 @@
return are_stop_watches_enabled_;
}
-void DomStatTracker::OnStopWatchStopped(int id, int64 time_elapsed) {
+void DomStatTracker::OnStopWatchStopped(int id, base::TimeDelta time_elapsed) {
stop_watch_durations_[static_cast<size_t>(id)] += time_elapsed;
}
diff --git a/src/cobalt/dom/dom_stat_tracker.h b/src/cobalt/dom/dom_stat_tracker.h
index e3accc0..e130da8 100644
--- a/src/cobalt/dom/dom_stat_tracker.h
+++ b/src/cobalt/dom/dom_stat_tracker.h
@@ -65,12 +65,12 @@
void EnableStopWatches();
void DisableStopWatches();
- int64 GetStopWatchTypeDuration(StopWatchType type) const;
+ base::TimeDelta GetStopWatchTypeDuration(StopWatchType type) const;
private:
// From base::StopWatchOwner
bool IsStopWatchEnabled(int id) const OVERRIDE;
- void OnStopWatchStopped(int id, int64 time_elapsed) OVERRIDE;
+ void OnStopWatchStopped(int id, base::TimeDelta time_elapsed) OVERRIDE;
// CVals. They are updated when the periodic counts are flushed.
base::CVal<int, base::CValPublic> total_html_elements_;
@@ -85,7 +85,7 @@
// Stop watch-related. The durations are cleared after the CVals are updated
// in |FlushPeriodicTracking|.
bool are_stop_watches_enabled_;
- std::vector<int64> stop_watch_durations_;
+ std::vector<base::TimeDelta> stop_watch_durations_;
};
} // namespace dom
diff --git a/src/cobalt/dom/dom_string_map_test.cc b/src/cobalt/dom/dom_string_map_test.cc
index 1825b19..d9c5521 100644
--- a/src/cobalt/dom/dom_string_map_test.cc
+++ b/src/cobalt/dom/dom_string_map_test.cc
@@ -45,7 +45,7 @@
DOMStringMapTest::DOMStringMapTest()
: html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, ""),
+ NULL, NULL, NULL, NULL, ""),
document_(new Document(&html_element_context_)),
element_(new Element(document_, base::Token("element"))),
dom_string_map_(new DOMStringMap(element_)) {}
diff --git a/src/cobalt/dom/dom_token_list_test.cc b/src/cobalt/dom/dom_token_list_test.cc
index 49c58dd..0ef5e3e 100644
--- a/src/cobalt/dom/dom_token_list_test.cc
+++ b/src/cobalt/dom/dom_token_list_test.cc
@@ -40,7 +40,7 @@
DOMTokenListTest::DOMTokenListTest()
: html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "") {
+ NULL, NULL, NULL, NULL, "") {
EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
document_ = new Document(&html_element_context_);
}
diff --git a/src/cobalt/dom/element_test.cc b/src/cobalt/dom/element_test.cc
index 30acb76..c8b5ea9 100644
--- a/src/cobalt/dom/element_test.cc
+++ b/src/cobalt/dom/element_test.cc
@@ -61,7 +61,7 @@
dom_parser_(new dom_parser::Parser()),
dom_stat_tracker_(new DomStatTracker("ElementTest")),
html_element_context_(NULL, css_parser_.get(), dom_parser_.get(), NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
dom_stat_tracker_.get(), "") {
EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
document_ = new Document(&html_element_context_);
diff --git a/src/cobalt/dom/global_stats.cc b/src/cobalt/dom/global_stats.cc
index cfedc69..acc3a78 100644
--- a/src/cobalt/dom/global_stats.cc
+++ b/src/cobalt/dom/global_stats.cc
@@ -96,7 +96,7 @@
void GlobalStats::IncreaseXHRMemoryUsage(size_t delta) { xhr_memory += delta; }
void GlobalStats::DecreaseXHRMemoryUsage(size_t delta) {
- DCHECK_GE(xhr_memory, delta);
+ DCHECK_GE(xhr_memory.value(), delta);
xhr_memory -= delta;
}
diff --git a/src/cobalt/dom/global_stats.h b/src/cobalt/dom/global_stats.h
index 4d29934..bb35c28 100644
--- a/src/cobalt/dom/global_stats.h
+++ b/src/cobalt/dom/global_stats.h
@@ -79,7 +79,7 @@
base::CVal<int, base::CValPublic> num_nodes;
base::CVal<int> num_node_lists;
base::CVal<int> num_xhrs;
- base::CVal<size_t> xhr_memory;
+ base::CVal<base::cval::SizeInBytes> xhr_memory;
friend struct DefaultSingletonTraits<GlobalStats>;
DISALLOW_COPY_AND_ASSIGN(GlobalStats);
diff --git a/src/cobalt/dom/html_element_context.cc b/src/cobalt/dom/html_element_context.cc
index 25d74f7..eee30eb 100644
--- a/src/cobalt/dom/html_element_context.cc
+++ b/src/cobalt/dom/html_element_context.cc
@@ -29,6 +29,8 @@
MediaSource::Registry* media_source_registry,
render_tree::ResourceProvider* resource_provider,
loader::image::ImageCache* image_cache,
+ loader::image::ReducedCacheCapacityManager*
+ reduced_image_cache_capacity_manager,
loader::font::RemoteTypefaceCache* remote_typeface_cache,
DomStatTracker* dom_stat_tracker, const std::string& language)
: fetcher_factory_(fetcher_factory),
@@ -40,6 +42,8 @@
media_source_registry_(media_source_registry),
resource_provider_(resource_provider),
image_cache_(image_cache),
+ reduced_image_cache_capacity_manager_(
+ reduced_image_cache_capacity_manager),
remote_typeface_cache_(remote_typeface_cache),
dom_stat_tracker_(dom_stat_tracker),
language_(language),
diff --git a/src/cobalt/dom/html_element_context.h b/src/cobalt/dom/html_element_context.h
index 642a4a0..8cdc86b 100644
--- a/src/cobalt/dom/html_element_context.h
+++ b/src/cobalt/dom/html_element_context.h
@@ -50,6 +50,8 @@
MediaSource::Registry* media_source_registry,
render_tree::ResourceProvider* resource_provider,
loader::image::ImageCache* image_cache,
+ loader::image::ReducedCacheCapacityManager*
+ reduced_image_cache_capacity_manager,
loader::font::RemoteTypefaceCache* remote_typeface_cache,
DomStatTracker* dom_stat_tracker,
const std::string& language);
@@ -93,6 +95,11 @@
return html_element_factory_.get();
}
+ loader::image::ReducedCacheCapacityManager*
+ reduced_image_cache_capacity_manager() {
+ return reduced_image_cache_capacity_manager_;
+ }
+
private:
loader::FetcherFactory* const fetcher_factory_;
cssom::CSSParser* const css_parser_;
@@ -103,6 +110,8 @@
MediaSource::Registry* const media_source_registry_;
render_tree::ResourceProvider* resource_provider_;
loader::image::ImageCache* const image_cache_;
+ loader::image::ReducedCacheCapacityManager* const
+ reduced_image_cache_capacity_manager_;
loader::font::RemoteTypefaceCache* const remote_typeface_cache_;
DomStatTracker* const dom_stat_tracker_;
const std::string language_;
diff --git a/src/cobalt/dom/html_element_factory_test.cc b/src/cobalt/dom/html_element_factory_test.cc
index 94b421f..2f0c00c 100644
--- a/src/cobalt/dom/html_element_factory_test.cc
+++ b/src/cobalt/dom/html_element_factory_test.cc
@@ -58,8 +58,10 @@
NULL /* can_play_type_handler */,
NULL /* web_media_player_factory */, &stub_script_runner_,
NULL /* media_source_registry */, NULL /* resource_provider */,
- NULL /* image_cache */, NULL /* remote_typeface_cache */,
- dom_stat_tracker_.get(), "" /* language */),
+ NULL /* image_cache */,
+ NULL /* reduced_image_cache_capacity_manager */,
+ NULL /* remote_typeface_cache */, dom_stat_tracker_.get(),
+ "" /* language */),
document_(new Document(&html_element_context_)) {}
~HTMLElementFactoryTest() OVERRIDE {}
diff --git a/src/cobalt/dom/html_element_test.cc b/src/cobalt/dom/html_element_test.cc
index 4561437..e445dcb 100644
--- a/src/cobalt/dom/html_element_test.cc
+++ b/src/cobalt/dom/html_element_test.cc
@@ -110,7 +110,8 @@
HTMLElementTest()
: dom_stat_tracker_(new DomStatTracker("HTMLElementTest")),
html_element_context_(NULL, &css_parser_, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, dom_stat_tracker_.get(), ""),
+ NULL, NULL, NULL, NULL, dom_stat_tracker_.get(),
+ ""),
document_(new Document(&html_element_context_)) {}
~HTMLElementTest() OVERRIDE {}
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index 3d7a596..55d1295 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -489,6 +489,29 @@
}
void HTMLMediaElement::CreateMediaPlayer() {
+ if (src().empty()) {
+ reduced_image_cache_capacity_request_ = base::nullopt;
+ } else if (html_element_context()
+ ->reduced_image_cache_capacity_manager()
+ ->reduced_capacity_percentage() != 1.0f) {
+ // Platforms with constrained GPU memory typically are placed in their most
+ // fragile position when a video is playing. Thus, we request a lower image
+ // cache size and empty the cache before we start playing a video, in
+ // an effort to make room in memory for video decoding. Reducing the
+ // image cache during this time should also be fine as the UI is not usually
+ // in the foreground during this time.
+
+ // Set a new reduced cache capacity.
+ reduced_image_cache_capacity_request_.emplace(
+ html_element_context()->reduced_image_cache_capacity_manager());
+ // Empty all non-referenced images from the image cache to make room for
+ // the video decoder.
+ html_element_context()->image_cache()->Purge();
+ // Ensure that all resource destructions are flushed and the memory is
+ // reclaimed.
+ html_element_context()->resource_provider()->Finish();
+ }
+
player_.reset();
player_ =
html_element_context()->web_media_player_factory()->CreateWebMediaPlayer(
@@ -711,6 +734,8 @@
pending_load_ = false;
load_state_ = kWaitingForSource;
+ reduced_image_cache_capacity_request_ = base::nullopt;
+
if (node_document()) {
node_document()->OnDOMMutation();
}
diff --git a/src/cobalt/dom/html_media_element.h b/src/cobalt/dom/html_media_element.h
index 300874f..7bd360e 100644
--- a/src/cobalt/dom/html_media_element.h
+++ b/src/cobalt/dom/html_media_element.h
@@ -30,6 +30,7 @@
#include "cobalt/dom/media_source.h"
#include "cobalt/dom/time_ranges.h"
#include "cobalt/dom/uint8_array.h"
+#include "cobalt/loader/image/image_cache.h"
#include "cobalt/script/exception_state.h"
#include "googleurl/src/gurl.h"
#include "media/player/web_media_player.h"
@@ -272,6 +273,10 @@
scoped_refptr<MediaError> error_;
+ // Helper object to reduce the image capacity while a video is playing.
+ base::optional<loader::image::ReducedCacheCapacityManager::Request>
+ reduced_image_cache_capacity_request_;
+
DISALLOW_COPY_AND_ASSIGN(HTMLMediaElement);
};
diff --git a/src/cobalt/dom/html_script_element.cc b/src/cobalt/dom/html_script_element.cc
index 0b6d3a9..fcfdf35 100644
--- a/src/cobalt/dom/html_script_element.cc
+++ b/src/cobalt/dom/html_script_element.cc
@@ -52,6 +52,7 @@
is_ready_(false),
load_option_(0),
inline_script_location_(GetSourceLocationName(), 1, 1),
+ is_sync_load_successful_(false),
prevent_garbage_collection_count_(0) {
DCHECK(document->html_element_context()->script_runner());
}
@@ -172,7 +173,8 @@
if (HasAttribute("src") && src() == "") {
LOG(WARNING) << "src attribute of script element is empty.";
- PostToDispatchEvent(FROM_HERE, base::Tokens::error());
+ PreventGarbageCollectionAndPostToDispatchEvent(FROM_HERE,
+ base::Tokens::error());
return;
}
@@ -184,7 +186,8 @@
if (!url_.is_valid()) {
LOG(WARNING) << src() << " cannot be resolved based on " << base_url << ".";
- PostToDispatchEvent(FROM_HERE, base::Tokens::error());
+ PreventGarbageCollectionAndPostToDispatchEvent(FROM_HERE,
+ base::Tokens::error());
return;
}
@@ -336,7 +339,8 @@
text)) {
ExecuteInternal();
} else {
- PostToDispatchEvent(FROM_HERE, base::Tokens::error());
+ PreventGarbageCollectionAndPostToDispatchEvent(FROM_HERE,
+ base::Tokens::error());
}
} break;
default: { NOTREACHED(); }
@@ -451,11 +455,8 @@
DCHECK(load_option_ == 4 || load_option_ == 5);
TRACE_EVENT0("cobalt::dom", "HTMLScriptElement::OnLoadingError()");
- // Allow garbage collection on the current object. No script will be executed
- // on it.
- AllowGarbageCollection();
-
if (!document_) {
+ AllowGarbageCollection();
return;
}
@@ -463,7 +464,9 @@
// Executing the script block must just consist of firing a simple event
// named error at the element.
+ DCHECK_GT(prevent_garbage_collection_count_, 0);
DispatchEvent(new Event(base::Tokens::error()));
+ AllowGarbageCollection();
switch (load_option_) {
case 4: {
@@ -513,14 +516,27 @@
// named load at the script element.
// TODO: Remove the firing of readystatechange once we support Promise.
if (is_external) {
+ DCHECK_GT(prevent_garbage_collection_count_, 0);
DispatchEvent(new Event(base::Tokens::load()));
DispatchEvent(new Event(base::Tokens::readystatechange()));
} else {
- PostToDispatchEvent(FROM_HERE, base::Tokens::load());
- PostToDispatchEvent(FROM_HERE, base::Tokens::readystatechange());
+ PreventGarbageCollectionAndPostToDispatchEvent(FROM_HERE,
+ base::Tokens::load());
+ PreventGarbageCollectionAndPostToDispatchEvent(
+ FROM_HERE, base::Tokens::readystatechange());
}
}
+void HTMLScriptElement::PreventGarbageCollectionAndPostToDispatchEvent(
+ const tracked_objects::Location& location, const base::Token& token) {
+ // Ensure that this HTMLScriptElement is not garbage collected until the event
+ // has been processed.
+ PreventGarbageCollection();
+ PostToDispatchEventAndRunCallback(
+ location, token,
+ base::Bind(&HTMLScriptElement::AllowGarbageCollection, this));
+}
+
void HTMLScriptElement::PreventGarbageCollection() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_GE(prevent_garbage_collection_count_, 0);
diff --git a/src/cobalt/dom/html_script_element.h b/src/cobalt/dom/html_script_element.h
index 9335314..17ab6d4 100644
--- a/src/cobalt/dom/html_script_element.h
+++ b/src/cobalt/dom/html_script_element.h
@@ -102,6 +102,8 @@
void Execute(const std::string& content,
const base::SourceLocation& script_location, bool is_external);
+ void PreventGarbageCollectionAndPostToDispatchEvent(
+ const tracked_objects::Location& location, const base::Token& token);
void PreventGarbageCollection();
void AllowGarbageCollection();
diff --git a/src/cobalt/dom/node_dispatch_event_test.cc b/src/cobalt/dom/node_dispatch_event_test.cc
index d3368ef..2051305 100644
--- a/src/cobalt/dom/node_dispatch_event_test.cc
+++ b/src/cobalt/dom/node_dispatch_event_test.cc
@@ -59,7 +59,7 @@
NodeDispatchEventTest::NodeDispatchEventTest()
: html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "") {
+ NULL, NULL, NULL, NULL, "") {
EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
document_ = new Document(&html_element_context_);
diff --git a/src/cobalt/dom/node_list_live_test.cc b/src/cobalt/dom/node_list_live_test.cc
index b8e6702..e3f757f 100644
--- a/src/cobalt/dom/node_list_live_test.cc
+++ b/src/cobalt/dom/node_list_live_test.cc
@@ -30,7 +30,7 @@
NodeListLiveTest()
: dom_stat_tracker_("NodeListLiveTest"),
html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, &dom_stat_tracker_, ""),
+ NULL, NULL, NULL, &dom_stat_tracker_, ""),
document_(new Document(&html_element_context_)) {}
~NodeListLiveTest() OVERRIDE {}
diff --git a/src/cobalt/dom/node_list_test.cc b/src/cobalt/dom/node_list_test.cc
index a93339a..c2e7b9a 100644
--- a/src/cobalt/dom/node_list_test.cc
+++ b/src/cobalt/dom/node_list_test.cc
@@ -30,7 +30,7 @@
NodeListTest()
: dom_stat_tracker_(new DomStatTracker("NodeListTest")),
html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, dom_stat_tracker_.get(), ""),
+ NULL, NULL, NULL, dom_stat_tracker_.get(), ""),
document_(new Document(&html_element_context_)) {}
~NodeListTest() OVERRIDE {}
diff --git a/src/cobalt/dom/node_test.cc b/src/cobalt/dom/node_test.cc
index 57153ae..a4abe5e 100644
--- a/src/cobalt/dom/node_test.cc
+++ b/src/cobalt/dom/node_test.cc
@@ -78,7 +78,7 @@
NodeTest::NodeTest()
: html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "") {
+ NULL, NULL, NULL, NULL, "") {
EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
document_ = new Document(&html_element_context_);
diff --git a/src/cobalt/dom/rule_matching_test.cc b/src/cobalt/dom/rule_matching_test.cc
index 2d1b118..7482605 100644
--- a/src/cobalt/dom/rule_matching_test.cc
+++ b/src/cobalt/dom/rule_matching_test.cc
@@ -45,7 +45,7 @@
dom_parser_(new dom_parser::Parser()),
dom_stat_tracker_(new DomStatTracker("RuleMatchingTest")),
html_element_context_(NULL, css_parser_.get(), dom_parser_.get(), NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
dom_stat_tracker_.get(), ""),
document_(new Document(&html_element_context_)),
root_(document_->CreateElement("html")->AsHTMLElement()) {
diff --git a/src/cobalt/dom/serializer_test.cc b/src/cobalt/dom/serializer_test.cc
index ec16354..dedcbe1 100644
--- a/src/cobalt/dom/serializer_test.cc
+++ b/src/cobalt/dom/serializer_test.cc
@@ -47,7 +47,7 @@
: dom_parser_(new dom_parser::Parser()),
dom_stat_tracker_(new DomStatTracker("SerializerTest")),
html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, dom_stat_tracker_.get(), ""),
+ NULL, NULL, NULL, dom_stat_tracker_.get(), ""),
document_(new Document(&html_element_context_)),
root_(new Element(document_, base::Token("root"))),
source_location_(base::SourceLocation("[object SerializerTest]", 1, 1)) {}
diff --git a/src/cobalt/dom/text_test.cc b/src/cobalt/dom/text_test.cc
index 536b42f..5b504b8 100644
--- a/src/cobalt/dom/text_test.cc
+++ b/src/cobalt/dom/text_test.cc
@@ -41,7 +41,7 @@
TextTest::TextTest()
: html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, "") {
+ NULL, NULL, NULL, NULL, "") {
EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
document_ = new Document(&html_element_context_);
}
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index 295c8f9..8a57e10 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -64,6 +64,8 @@
Parser* dom_parser, loader::FetcherFactory* fetcher_factory,
render_tree::ResourceProvider* resource_provider,
loader::image::ImageCache* image_cache,
+ loader::image::ReducedCacheCapacityManager*
+ reduced_image_cache_capacity_manager,
loader::font::RemoteTypefaceCache* remote_typeface_cache,
LocalStorageDatabase* local_storage_database,
media::CanPlayTypeHandler* can_play_type_handler,
@@ -86,8 +88,8 @@
html_element_context_(new HTMLElementContext(
fetcher_factory, css_parser, dom_parser, can_play_type_handler,
web_media_player_factory, script_runner, media_source_registry,
- resource_provider, image_cache, remote_typeface_cache,
- dom_stat_tracker, language)),
+ resource_provider, image_cache, reduced_image_cache_capacity_manager,
+ remote_typeface_cache, dom_stat_tracker, language)),
performance_(new Performance(new base::SystemMonotonicClock())),
ALLOW_THIS_IN_INITIALIZER_LIST(document_(new Document(
html_element_context_.get(),
diff --git a/src/cobalt/dom/window.h b/src/cobalt/dom/window.h
index 2bb6c07..6b2e776 100644
--- a/src/cobalt/dom/window.h
+++ b/src/cobalt/dom/window.h
@@ -89,6 +89,8 @@
Parser* dom_parser, loader::FetcherFactory* fetcher_factory,
render_tree::ResourceProvider* resource_provider,
loader::image::ImageCache* image_cache,
+ loader::image::ReducedCacheCapacityManager*
+ reduced_image_cache_capacity_manager,
loader::font::RemoteTypefaceCache* remote_typeface_cache,
LocalStorageDatabase* local_storage_database,
media::CanPlayTypeHandler* can_play_type_handler,
diff --git a/src/cobalt/dom/window_test.cc b/src/cobalt/dom/window_test.cc
index 2a5db90..43650c0 100644
--- a/src/cobalt/dom/window_test.cc
+++ b/src/cobalt/dom/window_test.cc
@@ -53,9 +53,10 @@
url_("about:blank"),
window_(new Window(
1920, 1080, css_parser_.get(), dom_parser_.get(),
- fetcher_factory_.get(), NULL, NULL, NULL, &local_storage_database_,
- stub_media_module_.get(), stub_media_module_.get(), NULL, NULL,
- NULL, NULL, url_, "", "en-US", base::Callback<void(const GURL &)>(),
+ fetcher_factory_.get(), NULL, NULL, NULL, NULL,
+ &local_storage_database_, stub_media_module_.get(),
+ stub_media_module_.get(), NULL, NULL, NULL, NULL, url_, "", "en-US",
+ base::Callback<void(const GURL &)>(),
base::Bind(&MockErrorCallback::Run,
base::Unretained(&mock_error_callback_)),
NULL, network_bridge::PostSender(),
diff --git a/src/cobalt/dom/xml_document_test.cc b/src/cobalt/dom/xml_document_test.cc
index 34d8e11..4603520 100644
--- a/src/cobalt/dom/xml_document_test.cc
+++ b/src/cobalt/dom/xml_document_test.cc
@@ -26,7 +26,8 @@
TEST(XMLDocumentTest, IsXMLDocument) {
HTMLElementContext html_element_context(NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, "");
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ "");
scoped_refptr<Document> document = new XMLDocument(&html_element_context);
EXPECT_TRUE(document->IsXMLDocument());
}
diff --git a/src/cobalt/dom_parser/html_decoder_test.cc b/src/cobalt/dom_parser/html_decoder_test.cc
index e00a271..ab5f6a1 100644
--- a/src/cobalt/dom_parser/html_decoder_test.cc
+++ b/src/cobalt/dom_parser/html_decoder_test.cc
@@ -69,7 +69,7 @@
html_element_context_(&fetcher_factory_, &stub_css_parser_,
dom_parser_.get(), NULL /* can_play_type_handler */,
NULL /* web_media_player_factory */,
- &stub_script_runner_, NULL, NULL, NULL, NULL,
+ &stub_script_runner_, NULL, NULL, NULL, NULL, NULL,
dom_stat_tracker_.get(), ""),
document_(
new dom::Document(&html_element_context_, dom::Document::Options())),
diff --git a/src/cobalt/dom_parser/xml_decoder_test.cc b/src/cobalt/dom_parser/xml_decoder_test.cc
index a7540c0..e7336eb 100644
--- a/src/cobalt/dom_parser/xml_decoder_test.cc
+++ b/src/cobalt/dom_parser/xml_decoder_test.cc
@@ -51,7 +51,7 @@
XMLDecoderTest::XMLDecoderTest()
: html_element_context_(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, ""),
+ NULL, NULL, NULL, NULL, ""),
document_(new dom::XMLDocument(&html_element_context_)),
source_location_(base::SourceLocation("[object XMLDecoderTest]", 1, 1)) {}
diff --git a/src/cobalt/layout/layout_stat_tracker.cc b/src/cobalt/layout/layout_stat_tracker.cc
index 53dc4d4..1ef39bf 100644
--- a/src/cobalt/layout/layout_stat_tracker.cc
+++ b/src/cobalt/layout/layout_stat_tracker.cc
@@ -27,7 +27,7 @@
boxes_created_count_(0),
boxes_destroyed_count_(0),
are_stop_watches_enabled_(false) {
- stop_watch_durations_.resize(kNumStopWatchTypes, 0);
+ stop_watch_durations_.resize(kNumStopWatchTypes, base::TimeDelta());
}
LayoutStatTracker::~LayoutStatTracker() {
@@ -46,7 +46,7 @@
boxes_destroyed_count_ = 0;
for (size_t i = 0; i < kNumStopWatchTypes; ++i) {
- stop_watch_durations_[i] = 0;
+ stop_watch_durations_[i] = base::TimeDelta();
}
}
@@ -62,7 +62,8 @@
are_stop_watches_enabled_ = false;
}
-int64 LayoutStatTracker::GetStopWatchTypeDuration(StopWatchType type) const {
+base::TimeDelta LayoutStatTracker::GetStopWatchTypeDuration(
+ StopWatchType type) const {
return stop_watch_durations_[type];
}
@@ -70,7 +71,8 @@
return are_stop_watches_enabled_;
}
-void LayoutStatTracker::OnStopWatchStopped(int id, int64 time_elapsed) {
+void LayoutStatTracker::OnStopWatchStopped(int id,
+ base::TimeDelta time_elapsed) {
stop_watch_durations_[static_cast<size_t>(id)] += time_elapsed;
}
diff --git a/src/cobalt/layout/layout_stat_tracker.h b/src/cobalt/layout/layout_stat_tracker.h
index 87269b3..2f89a9b 100644
--- a/src/cobalt/layout/layout_stat_tracker.h
+++ b/src/cobalt/layout/layout_stat_tracker.h
@@ -56,12 +56,12 @@
void EnableStopWatches();
void DisableStopWatches();
- int64 GetStopWatchTypeDuration(StopWatchType type) const;
+ base::TimeDelta GetStopWatchTypeDuration(StopWatchType type) const;
private:
// From base::StopWatchOwner
bool IsStopWatchEnabled(int id) const OVERRIDE;
- void OnStopWatchStopped(int id, int64 time_elapsed) OVERRIDE;
+ void OnStopWatchStopped(int id, base::TimeDelta time_elapsed) OVERRIDE;
// CVals. They are updated when the periodic counts are flushed.
base::CVal<int, base::CValPublic> total_boxes_;
@@ -74,7 +74,7 @@
// Stop watch-related. The durations are cleared after the CVals are updated
// in |FlushPeriodicTracking|.
bool are_stop_watches_enabled_;
- std::vector<int64> stop_watch_durations_;
+ std::vector<base::TimeDelta> stop_watch_durations_;
};
} // namespace layout
diff --git a/src/cobalt/loader/image/image_cache.h b/src/cobalt/loader/image/image_cache.h
index 032582c..78a64a1 100644
--- a/src/cobalt/loader/image/image_cache.h
+++ b/src/cobalt/loader/image/image_cache.h
@@ -79,6 +79,67 @@
fetcher_factory));
}
+// The ReducedCacheCapacityManager is a helper class that manages state which
+// makes it easy for clients to place the image cache in a reduced memory state,
+// at times when GPU memory is at a premium, such as when playing a video.
+// Clients should create ReducedCacheCapacityManager::Request objects to
+// indicate that they would like the image cache to enter a reduced capacity
+// state, internally, the manager keeps a reference count of how many Request
+// objects exist and enables the reduced capacity state if there is more than
+// one of them.
+class ReducedCacheCapacityManager {
+ public:
+ class Request {
+ public:
+ explicit Request(ReducedCacheCapacityManager* manager) : manager_(manager) {
+ manager_->IncrementRequestRefCount();
+ }
+ ~Request() { manager_->DecrementRequestRefCount(); }
+
+ private:
+ ReducedCacheCapacityManager* manager_;
+ };
+
+ ReducedCacheCapacityManager(ImageCache* cache,
+ float reduced_capacity_percentage)
+ : cache_(cache),
+ request_ref_count_(0),
+ reduced_capacity_percentage_(reduced_capacity_percentage),
+ original_capacity_(cache_->capacity()),
+ reduced_capacity_(static_cast<uint32>(reduced_capacity_percentage_ *
+ original_capacity_)) {
+ DCHECK_GE(1.0f, reduced_capacity_percentage);
+ }
+
+ float reduced_capacity_percentage() const {
+ return reduced_capacity_percentage_;
+ }
+
+ private:
+ void IncrementRequestRefCount() {
+ if (request_ref_count_ == 0) {
+ cache_->SetCapacity(reduced_capacity_);
+ }
+ ++request_ref_count_;
+ }
+
+ void DecrementRequestRefCount() {
+ DCHECK_LT(0, request_ref_count_);
+ --request_ref_count_;
+ if (request_ref_count_ == 0) {
+ cache_->SetCapacity(original_capacity_);
+ }
+ }
+
+ ImageCache* cache_;
+ int request_ref_count_;
+ float reduced_capacity_percentage_;
+ const uint32 original_capacity_;
+ const uint32 reduced_capacity_;
+
+ friend class Request;
+};
+
} // namespace image
} // namespace loader
} // namespace cobalt
diff --git a/src/cobalt/loader/resource_cache.h b/src/cobalt/loader/resource_cache.h
index 0d58b8c..f522f5b 100644
--- a/src/cobalt/loader/resource_cache.h
+++ b/src/cobalt/loader/resource_cache.h
@@ -409,6 +409,11 @@
return security_callback_;
}
+ uint32 capacity() const { return cache_capacity_; }
+ void SetCapacity(uint32 capacity);
+
+ void Purge();
+
private:
friend class CachedResource<CacheType>;
@@ -428,12 +433,15 @@
// cache is over its memory limit.
void NotifyResourceDestroyed(CachedResourceType* cached_resource);
- void ReclaimMemory();
+ // Releases unreferenced cache objects until our total cache memory usage is
+ // less than or equal to |bytes_to_reclaim_down_to|, or until there are no
+ // more unreferenced cache objects to release.
+ void ReclaimMemory(uint32 bytes_to_reclaim_down_to);
// The name of this resource cache object, useful while debugging.
const std::string name_;
- const uint32 cache_capacity_;
+ uint32 cache_capacity_;
scoped_ptr<DecoderProviderType> decoder_provider_;
loader::FetcherFactory* const fetcher_factory_;
@@ -450,8 +458,8 @@
base::ThreadChecker resource_cache_thread_checker_;
- base::CVal<uint32, base::CValPublic> size_in_bytes_;
- base::CVal<uint32, base::CValPublic> capacity_in_bytes_;
+ base::CVal<base::cval::SizeInBytes, base::CValPublic> size_in_bytes_;
+ base::CVal<base::cval::SizeInBytes, base::CValPublic> capacity_in_bytes_;
DISALLOW_COPY_AND_ASSIGN(ResourceCache);
};
@@ -517,6 +525,20 @@
}
template <typename CacheType>
+void ResourceCache<CacheType>::SetCapacity(uint32 capacity) {
+ DCHECK(resource_cache_thread_checker_.CalledOnValidThread());
+ cache_capacity_ = capacity;
+ capacity_in_bytes_ = capacity;
+ ReclaimMemory(cache_capacity_);
+}
+
+template <typename CacheType>
+void ResourceCache<CacheType>::Purge() {
+ DCHECK(resource_cache_thread_checker_.CalledOnValidThread());
+ ReclaimMemory(0);
+}
+
+template <typename CacheType>
void ResourceCache<CacheType>::NotifyResourceSuccessfullyLoaded(
CachedResourceType* cached_resource) {
DCHECK(resource_cache_thread_checker_.CalledOnValidThread());
@@ -525,7 +547,7 @@
size_in_bytes_ +=
CacheType::GetEstimatedSizeInBytes(cached_resource->TryGetResource());
if (size_in_bytes_ > cache_capacity_) {
- ReclaimMemory();
+ ReclaimMemory(cache_capacity_);
}
}
}
@@ -547,15 +569,15 @@
unreference_cached_resource_map_.insert(
std::make_pair(url, cached_resource->TryGetResource()));
// Try to reclaim some memory.
- ReclaimMemory();
+ ReclaimMemory(cache_capacity_);
}
}
template <typename CacheType>
-void ResourceCache<CacheType>::ReclaimMemory() {
+void ResourceCache<CacheType>::ReclaimMemory(uint32 bytes_to_reclaim_down_to) {
DCHECK(resource_cache_thread_checker_.CalledOnValidThread());
- while (size_in_bytes_ > cache_capacity_ &&
+ while (size_in_bytes_.value() > bytes_to_reclaim_down_to &&
!unreference_cached_resource_map_.empty()) {
// The first element is the earliest-inserted element.
scoped_refptr<ResourceType> resource =
@@ -574,7 +596,7 @@
// have to increase the size of |cache_capacity_| if the system memory is
// large enough or evict resources from the cache even though they are still
// in use.
- DLOG_IF(WARNING, size_in_bytes_ > cache_capacity_)
+ DLOG_IF(WARNING, size_in_bytes_.value() > cache_capacity_)
<< "cached size: " << size_in_bytes_
<< ", cache capacity: " << cache_capacity_;
}
diff --git a/src/cobalt/render_tree/resource_provider.h b/src/cobalt/render_tree/resource_provider.h
index 9b6aa08..72c106a 100644
--- a/src/cobalt/render_tree/resource_provider.h
+++ b/src/cobalt/render_tree/resource_provider.h
@@ -49,6 +49,12 @@
virtual ~ResourceProvider() {}
+ // Blocks until it can be guaranteed that all resource-related operations have
+ // completed. This might be important if we would like to ensure that memory
+ // allocations or deallocations have occurred before proceeding with a memory
+ // intensive operation.
+ virtual void Finish() = 0;
+
// Returns true if AllocateImageData() supports the given |pixel_format|.
virtual bool PixelFormatSupported(PixelFormat pixel_format) = 0;
diff --git a/src/cobalt/render_tree/resource_provider_stub.h b/src/cobalt/render_tree/resource_provider_stub.h
index e45c349..1430f5f 100644
--- a/src/cobalt/render_tree/resource_provider_stub.h
+++ b/src/cobalt/render_tree/resource_provider_stub.h
@@ -162,6 +162,8 @@
public:
~ResourceProviderStub() OVERRIDE {}
+ void Finish() OVERRIDE {}
+
bool PixelFormatSupported(PixelFormat pixel_format) OVERRIDE {
UNREFERENCED_PARAMETER(pixel_format);
return true;
diff --git a/src/cobalt/renderer/rasterizer/blitter/resource_provider.h b/src/cobalt/renderer/rasterizer/blitter/resource_provider.h
index cbce361..078a683 100644
--- a/src/cobalt/renderer/rasterizer/blitter/resource_provider.h
+++ b/src/cobalt/renderer/rasterizer/blitter/resource_provider.h
@@ -40,6 +40,8 @@
render_tree::ResourceProvider* skia_resource_provider);
~ResourceProvider() OVERRIDE {}
+ void Finish() OVERRIDE {}
+
bool PixelFormatSupported(render_tree::PixelFormat pixel_format) OVERRIDE;
bool AlphaFormatSupported(render_tree::AlphaFormat alpha_format) OVERRIDE;
diff --git a/src/cobalt/renderer/rasterizer/common/surface_cache.cc b/src/cobalt/renderer/rasterizer/common/surface_cache.cc
index 1464d11..5ce019f 100644
--- a/src/cobalt/renderer/rasterizer/common/surface_cache.cc
+++ b/src/cobalt/renderer/rasterizer/common/surface_cache.cc
@@ -38,7 +38,7 @@
// Since caching elements is expensive, we limit the number of new entries added
// to the cache each frame.
-const size_t kMaxElementsToCachePerFrame = 3;
+const size_t kMaxElementsToCachePerFrame = 1;
// If a node has been seen for kConsecutiveFramesForPreference consecutive
// frames, it is preferred for being cached over nodes that have been seen less
@@ -56,40 +56,23 @@
const float kApplySurfaceTimeMultipleCacheCriteria = 1.2f;
} // namespace
-void SurfaceCache::Block::InitBlock() {
+void SurfaceCache::Block::InitBlock(render_tree::Node* node) {
start_time_ = base::TimeTicks::Now();
+ key_ = NodeMapKey(node,
+ cache_->delegate_->GetRenderSize(node->GetBounds().size()));
+
// Keep track of the stack of blocks currently being rendered.
parent_ = cache_->current_block_;
cache_->current_block_ = this;
- math::RectF node_bounds = node_->GetBounds();
-
- NodeMap::iterator seen_iter = cache_->seen_.find(node_);
+ NodeMap::iterator seen_iter = cache_->seen_.find(key_);
node_data_ = (seen_iter == cache_->seen_.end() ? NULL : &seen_iter->second);
if (node_data_) {
// In order for the cache to function, it needs to know which nodes are
// seen frequently and which are not. Setting this flag is the main signal.
node_data_->visited_this_frame = true;
-
- // Check that the actual size that we are rendering to now is compatible
- // with the size when this node was originally inserted into the cache. If
- // the sizes are incompatible, remove the old version from the cache so that
- // it can be replaced by this new version.
- // The new size is compatible with the old size if the new size is smaller
- // than the old size, or the new size is smaller than the local size of
- // the node being rendered.
- math::Size render_size =
- cache_->delegate_->GetRenderSize(node_bounds.size());
- if ((render_size.width() > node_bounds.size().width() &&
- render_size.width() > node_data_->render_size.width()) ||
- (render_size.height() > node_bounds.size().height() &&
- render_size.height() > node_data_->render_size.height())) {
- // Sizes are incompatible, remove the old cached version of this node.
- cache_->RemoveFromSeen(seen_iter);
- node_data_ = NULL;
- }
}
if (node_data_ && node_data_->cached()) {
@@ -123,14 +106,9 @@
cache_->recording_ = true;
cache_->PurgeUntilSpaceAvailable(node_data_->size_in_bytes());
- // Since we are now caching the surface, make sure the recorded render
- // size is up to date as this will reflect the size of the cached surface
- // allocated for this node.
- node_data_->render_size =
- cache_->delegate_->GetRenderSize(node_bounds.size());
// Signal to the delegate that we would like to record this block for
// caching.
- cache_->delegate_->StartRecording(node_bounds);
+ cache_->delegate_->StartRecording(key_.node->GetBounds());
} else {
// The node is not cached, and it should not become cached, so just do
// nothing besides record how long it takes via |start_time_|, set above.
@@ -161,6 +139,11 @@
IncreaseAncestorBlockDurations(node_data_->duration - duration);
} break;
case kStateNotRecording: {
+ if (key_.render_size.GetArea() == 0) {
+ // Do not consider degenerate render tree nodes for the cache.
+ break;
+ }
+
// We're done now, get metrics from the delegate and determine whether or
// not we should cache the result for next time.
base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
@@ -169,15 +152,12 @@
// so.
if (!node_data_) {
std::pair<NodeMap::iterator, bool> insert_results =
- cache_->seen_.insert(std::make_pair(node_, NodeData(node_)));
+ cache_->seen_.insert(std::make_pair(key_, NodeData(key_)));
DCHECK(insert_results.second);
node_data_ = &insert_results.first->second;
}
// Update the recorded entry with new timing information.
- DCHECK_LT(0.0f, node_->GetBounds().size().GetArea());
- node_data_->render_size =
- cache_->delegate_->GetRenderSize(node_->GetBounds().size());
node_data_->duration = duration;
} break;
case kStateInvalid: {
@@ -565,7 +545,7 @@
NodeData* node_data_to_purge = to_purge_.back();
to_purge_.pop_back();
- if (seen_.find(node_data_to_purge->node) != seen_.end()) {
+ if (seen_.find(node_data_to_purge->key()) != seen_.end()) {
FreeCachedSurface(node_data_to_purge);
}
}
diff --git a/src/cobalt/renderer/rasterizer/common/surface_cache.h b/src/cobalt/renderer/rasterizer/common/surface_cache.h
index c1a53a3..deb93de 100644
--- a/src/cobalt/renderer/rasterizer/common/surface_cache.h
+++ b/src/cobalt/renderer/rasterizer/common/surface_cache.h
@@ -104,16 +104,36 @@
};
private:
+ // The key to our cache's map of which items it has seen before. We use
+ // the address of a render node along with its on-screen render size to
+ // determine whether there is a cache match or not.
+ struct NodeMapKey {
+ NodeMapKey() {}
+ NodeMapKey(render_tree::Node* node, const math::Size& render_size)
+ : node(node), render_size(render_size) {}
+
+ bool operator<(const NodeMapKey& rhs) const {
+ return (node == rhs.node
+ ? (render_size.width() == rhs.render_size.width()
+ ? render_size.height() < rhs.render_size.height()
+ : render_size.width() < rhs.render_size.width())
+ : node < rhs.node);
+ }
+
+ render_tree::Node* node;
+ math::Size render_size;
+ };
// NodeData contains a set of data stored for every node that we have seen
// and helps determine whether that node should be cached or not, or if it
// is already cached.
struct NodeData {
- explicit NodeData(render_tree::Node* node)
- : surface(NULL),
+ explicit NodeData(const NodeMapKey& key)
+ : render_size(key.render_size),
+ surface(NULL),
visited_this_frame(true),
consecutive_frames_visited(0),
is_cache_candidate(false),
- node(node) {}
+ node(key.node) {}
// The size in bytes occupied by a cached surface representing this node.
int size_in_bytes() { return render_size.GetArea() * 4; }
@@ -121,6 +141,9 @@
// Returns whether or not this node is cached or not.
bool cached() const { return surface != NULL; }
+ // Creates a key from the NodeData.
+ NodeMapKey key() const { return NodeMapKey(node.get(), render_size); }
+
// Tracks how long it last took to render this node.
base::TimeDelta duration;
@@ -145,7 +168,7 @@
// A reference to the actual node.
scoped_refptr<render_tree::Node> node;
};
- typedef base::hash_map<render_tree::Node*, NodeData> NodeMap;
+ typedef std::map<NodeMapKey, NodeData> NodeMap;
public:
// The main public interface to SurfaceCache is via SurfaceCache::Block.
@@ -159,7 +182,6 @@
// We like this to be inlined so that this call makes very little
// performance impact if |surface_cache| is null.
cache_ = surface_cache;
- node_ = node;
if (!cache_) {
// If there is no cache, we have nothing to do besides indicate that we
// are not recording and the surface for this node is not already
@@ -167,7 +189,7 @@
state_ = kStateNotRecording;
return;
} else {
- InitBlock();
+ InitBlock(node);
}
}
~Block() {
@@ -190,7 +212,7 @@
kStateNotRecording,
kStateInvalid
};
- void InitBlock();
+ void InitBlock(render_tree::Node* node);
void ShutdownBlock();
// If any blocks on the stack are performing any timing, this method
@@ -202,7 +224,7 @@
State state_;
SurfaceCache* cache_;
- render_tree::Node* node_;
+ NodeMapKey key_;
base::TimeTicks start_time_;
NodeData* node_data_;
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
index 51f3f6d..20ddfd5 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
@@ -16,6 +16,8 @@
#include "cobalt/renderer/rasterizer/skia/hardware_rasterizer.h"
+#include <algorithm>
+
#include "base/debug/trace_event.h"
#include "cobalt/renderer/backend/egl/graphics_context.h"
#include "cobalt/renderer/rasterizer/common/surface_cache.h"
@@ -161,11 +163,14 @@
new HardwareResourceProvider(graphics_context_, gr_context_));
graphics_context_->ReleaseCurrentContext();
+ int max_surface_size = std::max(gr_context_->getMaxRenderTargetSize(),
+ gr_context_->getMaxTextureSize());
+ DLOG(INFO) << "Max renderer surface size: " << max_surface_size;
+
if (surface_cache_size_in_bytes > 0) {
surface_cache_delegate_.emplace(
create_sk_surface_function,
- math::Size(gr_context_->getMaxTextureSize(),
- gr_context_->getMaxTextureSize()));
+ math::Size(max_surface_size, max_surface_size));
surface_cache_.emplace(&surface_cache_delegate_.value(),
surface_cache_size_in_bytes);
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
index 2cb69c9..d79a244 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
@@ -17,6 +17,7 @@
#include "cobalt/renderer/rasterizer/skia/hardware_resource_provider.h"
#include "base/debug/trace_event.h"
+#include "base/synchronization/waitable_event.h"
#include "cobalt/base/polymorphic_downcast.h"
#include "cobalt/renderer/backend/egl/graphics_system.h"
#include "cobalt/renderer/rasterizer/skia/cobalt_skia_type_conversions.h"
@@ -47,6 +48,18 @@
font_manager_(SkFontMgr::RefDefault()),
self_message_loop_(MessageLoop::current()) {}
+void HardwareResourceProvider::Finish() {
+ // Wait for any resource-related to complete (by waiting for all tasks to
+ // complete).
+ if (MessageLoop::current() != self_message_loop_) {
+ base::WaitableEvent completion(true, false);
+ self_message_loop_->PostTask(FROM_HERE,
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&completion)));
+ completion.Wait();
+ }
+}
+
bool HardwareResourceProvider::PixelFormatSupported(
render_tree::PixelFormat pixel_format) {
return pixel_format == render_tree::kPixelFormatRGBA8;
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
index 5e01f73..54a439d 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.h
@@ -39,6 +39,8 @@
HardwareResourceProvider(backend::GraphicsContextEGL* cobalt_context,
GrContext* gr_context);
+ void Finish() OVERRIDE;
+
bool PixelFormatSupported(render_tree::PixelFormat pixel_format) OVERRIDE;
bool AlphaFormatSupported(render_tree::AlphaFormat alpha_format) OVERRIDE;
diff --git a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
index 8a34aff..b0b493f 100644
--- a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
@@ -670,6 +670,10 @@
draw_state_.render_target->restore();
+ if (surface_cache_delegate_) {
+ surface_cache_delegate_->UpdateCanvasScale();
+ }
+
#if ENABLE_FLUSH_AFTER_EVERY_NODE
draw_state_.render_target->flush();
#endif
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
index b0c4956..013d0dc 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
@@ -267,11 +267,6 @@
}
}
-void FontFileNameHandler(void* data, const char* s, int len) {
- FamilyData* family_data = reinterpret_cast<FamilyData*>(data);
- family_data->current_font_info->file_name.set(s, len);
-}
-
void FontElementHandler(FontFileInfo* file, const char** attributes) {
// A <font> should have weight (integer) and style (normal, italic)attributes.
// The element should contain a filename.
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
index 478d9c6..21b6b4c 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
@@ -519,12 +519,12 @@
DefaultSingletonTraits<SkFontMgrCVals> >::get();
}
- const base::CVal<int32_t, base::CValPublic>&
+ const base::CVal<base::cval::SizeInBytes, base::CValPublic>&
system_typeface_open_stream_cache_limit_in_bytes() {
return system_typeface_open_stream_cache_limit_in_bytes_;
}
- base::CVal<int32_t, base::CValPublic>&
+ base::CVal<base::cval::SizeInBytes, base::CValPublic>&
system_typeface_open_stream_cache_size_in_bytes() {
return system_typeface_open_stream_cache_size_in_bytes_;
}
@@ -540,9 +540,9 @@
"Memory.SystemTypeface.Size", 0,
"Total number of bytes currently used by the cache.") {}
- const base::CVal<int32_t, base::CValPublic>
+ const base::CVal<base::cval::SizeInBytes, base::CValPublic>
system_typeface_open_stream_cache_limit_in_bytes_;
- mutable base::CVal<int32_t, base::CValPublic>
+ mutable base::CVal<base::cval::SizeInBytes, base::CValPublic>
system_typeface_open_stream_cache_size_in_bytes_;
friend struct DefaultSingletonTraits<SkFontMgrCVals>;
@@ -922,9 +922,10 @@
// The cache size is not over the memory limit. No open streams are released
// while the cache is under its limit. Simply break out.
if (SkFontMgrCVals::GetInstance()
- ->system_typeface_open_stream_cache_size_in_bytes() <
- SkFontMgrCVals::GetInstance()
- ->system_typeface_open_stream_cache_limit_in_bytes()) {
+ ->system_typeface_open_stream_cache_size_in_bytes()
+ .value() < SkFontMgrCVals::GetInstance()
+ ->system_typeface_open_stream_cache_limit_in_bytes()
+ .value()) {
break;
}
diff --git a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h
index fd4419e..7be9105 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h
+++ b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.h
@@ -34,6 +34,8 @@
public:
SoftwareResourceProvider();
+ void Finish() OVERRIDE{};
+
bool PixelFormatSupported(render_tree::PixelFormat pixel_format) OVERRIDE;
bool AlphaFormatSupported(render_tree::AlphaFormat alpha_format) OVERRIDE;
diff --git a/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.cc b/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.cc
index 598de2c..354a899 100644
--- a/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.cc
+++ b/src/cobalt/renderer/rasterizer/skia/surface_cache_delegate.cc
@@ -16,6 +16,7 @@
#include "cobalt/renderer/rasterizer/skia/surface_cache_delegate.h"
+#include <algorithm>
#include <string>
#include "base/debug/trace_event.h"
@@ -143,12 +144,24 @@
return;
}
+#if !defined(NDEBUG)
+ // Ensure that the surface we ultimately render to is not larger than what
+ // we are reporting with GetRenderSize().
+ math::Size render_size = GetRenderSize(local_bounds.size());
+ DCHECK_LE(coord_mapping.output_bounds.width(), render_size.width());
+ DCHECK_LE(coord_mapping.output_bounds.height(), render_size.height());
+#endif
+
// Now create a SkSurface and set it up as the new canvas for our client to
// target.
SkSurface* surface = create_sk_surface_function_.Run(
math::Size(coord_mapping.output_bounds.width(),
coord_mapping.output_bounds.height()));
- CHECK(surface);
+ if (!surface) {
+ LOG(WARNING) << "Could not create a " << coord_mapping.output_bounds.width()
+ << "x" << coord_mapping.output_bounds.height() << ".";
+ NOTREACHED();
+ }
recording_data_.emplace(*draw_state_, coord_mapping, surface);
@@ -189,8 +202,16 @@
}
math::Size SurfaceCacheDelegate::GetRenderSize(const math::SizeF& local_size) {
- math::Size size(static_cast<int>(local_size.width() * scale_.x() + 0.5f),
- static_cast<int>(local_size.height() * scale_.y() + 0.5f));
+ // All surfaces scaled down would get rendered at their unscaled size, while
+ // surfaces scaled up will be rendered at their scaled size. This is so that
+ // we can keep in the cache items that have animating scale, as long as the
+ // scale is less than 1 (which is common). The cost is that we may use more
+ // memory than necessary for these down-scaled surfaces.
+ math::Vector2dF scale(std::max(1.0f, scale_.x()), std::max(1.0f, scale_.y()));
+
+ // Add 2.0f to account for any rounding out that may occur.
+ math::Size size(static_cast<int>(local_size.width() * scale.x() + 2.0f),
+ static_cast<int>(local_size.height() * scale.y() + 2.0f));
return size;
}
diff --git a/src/cobalt/renderer/submission_queue.cc b/src/cobalt/renderer/submission_queue.cc
index 594861a..88debd1 100644
--- a/src/cobalt/renderer/submission_queue.cc
+++ b/src/cobalt/renderer/submission_queue.cc
@@ -31,8 +31,8 @@
: max_queue_size_(max_queue_size),
dispose_function_(dispose_function),
to_submission_time_in_ms_(time_to_converge),
- to_submission_time_in_ms_cval_(
- "Renderer.ToSubmissionTimeInMS", 0,
+ to_submission_time_cval_(
+ "Renderer.ToSubmissionTime", base::TimeDelta(),
"The current difference in milliseconds between the layout's clock "
"and the renderer's clock. The absolute value does not mean much, "
"but how it changes as the user navigates can show how the "
@@ -176,8 +176,8 @@
// Update our CVal tracking the current (smoothed) to_submission_time value
// and the one tracking submission queue size.
- to_submission_time_in_ms_cval_ =
- to_submission_time_in_ms_.GetValueAtTime(time);
+ to_submission_time_cval_ = base::TimeDelta::FromMilliseconds(
+ to_submission_time_in_ms_.GetValueAtTime(time));
queue_size_ = submission_queue_.size();
}
diff --git a/src/cobalt/renderer/submission_queue.h b/src/cobalt/renderer/submission_queue.h
index 4b6ada6..987a57c 100644
--- a/src/cobalt/renderer/submission_queue.h
+++ b/src/cobalt/renderer/submission_queue.h
@@ -164,7 +164,7 @@
// increasing.
base::optional<base::TimeTicks> last_now_;
- base::CVal<float> to_submission_time_in_ms_cval_;
+ base::CVal<base::TimeDelta> to_submission_time_cval_;
base::CVal<size_t> queue_size_;
};
diff --git a/src/cobalt/script/javascriptcore/jsc_engine.cc b/src/cobalt/script/javascriptcore/jsc_engine.cc
index 2555ddf..08cfcbb 100644
--- a/src/cobalt/script/javascriptcore/jsc_engine.cc
+++ b/src/cobalt/script/javascriptcore/jsc_engine.cc
@@ -63,13 +63,13 @@
void Update() {
base::AutoLock auto_lock(lock_);
- if (js_engine_count_ > 0) {
+ if (js_engine_count_.value() > 0) {
js_memory_ = OSAllocator::getCurrentBytesAllocated();
}
}
base::Lock lock_;
- base::CVal<size_t, base::CValPublic> js_memory_;
+ base::CVal<base::cval::SizeInBytes, base::CValPublic> js_memory_;
base::CVal<size_t> js_engine_count_;
scoped_ptr<base::PollerWithThread> poller_;
};
diff --git a/src/cobalt/script/mozjs/mozjs_global_environment.cc b/src/cobalt/script/mozjs/mozjs_global_environment.cc
index 84a8d91..bf2648c 100644
--- a/src/cobalt/script/mozjs/mozjs_global_environment.cc
+++ b/src/cobalt/script/mozjs/mozjs_global_environment.cc
@@ -122,6 +122,7 @@
MozjsGlobalEnvironment::MozjsGlobalEnvironment(JSRuntime* runtime)
: context_(NULL),
+ garbage_collection_count_(0),
cached_interface_data_deleter_(&cached_interface_data_),
context_destructor_(&context_),
environment_settings_(NULL),
@@ -311,19 +312,28 @@
}
void MozjsGlobalEnvironment::BeginGarbageCollection() {
- DCHECK(!opaque_root_state_);
- JSAutoRequest auto_request(context_);
- JSAutoCompartment auto_comparment(context_, global_object_proxy_);
- // Get the current state of opaque root relationships. Keep this object
- // alive for the duration of the GC phase to ensure that reachability between
- // roots and reachable objects is maintained.
- opaque_root_state_ = opaque_root_tracker_->GetCurrentOpaqueRootState();
+ // It's possible that a GC could be triggered from within the
+ // BeginGarbageCollection callback. Only create the OpaqueRootState the first
+ // time we enter.
+ garbage_collection_count_++;
+ if (global_object_proxy_ && garbage_collection_count_ == 1) {
+ DCHECK(!opaque_root_state_);
+ JSAutoRequest auto_request(context_);
+ JSAutoCompartment auto_comparment(context_, global_object_proxy_);
+ // Get the current state of opaque root relationships. Keep this object
+ // alive for the duration of the GC phase to ensure that reachability
+ // between roots and reachable objects is maintained.
+ opaque_root_state_ = opaque_root_tracker_->GetCurrentOpaqueRootState();
+ }
}
void MozjsGlobalEnvironment::EndGarbageCollection() {
- DCHECK(opaque_root_state_);
// Reset opaque root reachability relationships.
- opaque_root_state_.reset(NULL);
+ garbage_collection_count_--;
+ DCHECK_GE(garbage_collection_count_, 0);
+ if (garbage_collection_count_ == 0) {
+ opaque_root_state_.reset(NULL);
+ }
}
MozjsGlobalEnvironment* MozjsGlobalEnvironment::GetFromContext(
diff --git a/src/cobalt/script/mozjs/mozjs_global_environment.h b/src/cobalt/script/mozjs/mozjs_global_environment.h
index eb0d2eb..a774cb2 100644
--- a/src/cobalt/script/mozjs/mozjs_global_environment.h
+++ b/src/cobalt/script/mozjs/mozjs_global_environment.h
@@ -153,6 +153,7 @@
base::ThreadChecker thread_checker_;
JSContext* context_;
+ int garbage_collection_count_;
WeakHeapObjectManager weak_object_manager_;
CachedWrapperMultiMap kept_alive_objects_;
scoped_ptr<ReferencedObjectMap> referenced_objects_;
diff --git a/src/cobalt/script/mozjs/opaque_root_tracker.cc b/src/cobalt/script/mozjs/opaque_root_tracker.cc
index 22bfc40..1ae8d32 100644
--- a/src/cobalt/script/mozjs/opaque_root_tracker.cc
+++ b/src/cobalt/script/mozjs/opaque_root_tracker.cc
@@ -89,29 +89,52 @@
// Get the current opaque root for all objects that are being tracked.
for (WrapperPrivateSet::iterator it = all_objects_.begin();
it != all_objects_.end(); ++it) {
- WrapperPrivate* reachable_object_wrapper_private = *it;
- Wrappable* opaque_root = reachable_object_wrapper_private->GetOpaqueRoot();
- if (opaque_root) {
- WrapperPrivate* opaque_root_private = WrapperPrivate::GetFromWrappable(
- opaque_root, context_, wrapper_factory_);
- // Always mark the root as reachable from the non-root object.
- state->TrackReachability(reachable_object_wrapper_private,
- opaque_root_private);
-
- // Only mark the non-root object as reachable if we need to keep the
- // wrapper alive for some reason. In general it's okay for a wrapper to
- // get GC'd because the Cobalt object will still be kept alive, and a new
- // JS object can be created if needed again.
- if (reachable_object_wrapper_private
- ->ShouldKeepWrapperAliveIfReachable()) {
- state->TrackReachability(opaque_root_private,
- reachable_object_wrapper_private);
- }
- }
+ WrapperPrivate* wrapper_private = *it;
+ TrackReachabilityToOpaqueRoot(state.get(), wrapper_private);
+ TrackReachableWrappables(state.get(), wrapper_private);
}
return state.PassAs<OpaqueRootState>();
}
+void OpaqueRootTracker::TrackReachabilityToOpaqueRoot(
+ OpaqueRootState* state, WrapperPrivate* wrapper_private) {
+ OpaqueRootStateImpl* state_impl =
+ base::polymorphic_downcast<OpaqueRootStateImpl*>(state);
+ // If this wrappable has an opaque root, track reachability between this
+ // wrappable and its root.
+ Wrappable* opaque_root = wrapper_private->GetOpaqueRoot();
+ if (opaque_root) {
+ WrapperPrivate* opaque_root_private = WrapperPrivate::GetFromWrappable(
+ opaque_root, context_, wrapper_factory_);
+ // Always mark the root as reachable from the non-root object.
+ state_impl->TrackReachability(wrapper_private, opaque_root_private);
+
+ // Only mark the non-root object as reachable if we need to keep the
+ // wrapper alive for some reason. In general it's okay for a wrapper to
+ // get GC'd because the Cobalt object will still be kept alive, and a new
+ // JS object can be created if needed again.
+ if (wrapper_private->ShouldKeepWrapperAliveIfReachable()) {
+ state_impl->TrackReachability(opaque_root_private, wrapper_private);
+ }
+ }
+}
+
+void OpaqueRootTracker::TrackReachableWrappables(
+ OpaqueRootState* state, WrapperPrivate* wrapper_private) {
+ OpaqueRootStateImpl* state_impl =
+ base::polymorphic_downcast<OpaqueRootStateImpl*>(state);
+ // Track any wrappables that are explicitly marked as reachable from
+ // this wrappable.
+ typedef std::vector<Wrappable*> WrappableVector;
+ WrappableVector reachable_objects;
+ wrapper_private->GetReachableWrappables(&reachable_objects);
+ for (size_t i = 0; i < reachable_objects.size(); ++i) {
+ WrapperPrivate* reachable_object_private = WrapperPrivate::GetFromWrappable(
+ reachable_objects[i], context_, wrapper_factory_);
+ state_impl->TrackReachability(wrapper_private, reachable_object_private);
+ }
+}
+
} // namespace mozjs
} // namespace script
} // namespace cobalt
diff --git a/src/cobalt/script/mozjs/opaque_root_tracker.h b/src/cobalt/script/mozjs/opaque_root_tracker.h
index bd9ef2a..10517a6 100644
--- a/src/cobalt/script/mozjs/opaque_root_tracker.h
+++ b/src/cobalt/script/mozjs/opaque_root_tracker.h
@@ -73,6 +73,10 @@
scoped_ptr<OpaqueRootState> GetCurrentOpaqueRootState();
private:
+ void TrackReachabilityToOpaqueRoot(OpaqueRootState* state,
+ WrapperPrivate* wrapper_private);
+ void TrackReachableWrappables(OpaqueRootState* state,
+ WrapperPrivate* wrapper_private);
typedef base::hash_set<WrapperPrivate*> WrapperPrivateSet;
JSContext* context_;
diff --git a/src/cobalt/script/mozjs/wrapper_private.cc b/src/cobalt/script/mozjs/wrapper_private.cc
index ad2113a..7dc1410 100644
--- a/src/cobalt/script/mozjs/wrapper_private.cc
+++ b/src/cobalt/script/mozjs/wrapper_private.cc
@@ -33,6 +33,13 @@
return NULL;
}
+void WrapperPrivate::GetReachableWrappables(
+ std::vector<Wrappable*>* reachable) {
+ if (!get_reachable_wrappables_function_.is_null()) {
+ return get_reachable_wrappables_function_.Run(wrappable_, reachable);
+ }
+}
+
bool WrapperPrivate::ShouldKeepWrapperAliveIfReachable() {
ProxyHandler* proxy_handler = base::polymorphic_downcast<ProxyHandler*>(
js::GetProxyHandler(wrapper_proxy_));
@@ -45,10 +52,12 @@
void WrapperPrivate::AddPrivateData(
JSContext* context, JS::HandleObject wrapper_proxy,
const scoped_refptr<Wrappable>& wrappable,
- const GetOpaqueRootFunction& get_opaque_root_function) {
+ const GetOpaqueRootFunction& get_opaque_root_function,
+ const GetReachableWrappablesFunction& get_reachable_wrappables_function) {
DCHECK(js::IsProxy(wrapper_proxy));
WrapperPrivate* private_data = new WrapperPrivate(
- context, wrappable, wrapper_proxy, get_opaque_root_function);
+ context, wrappable, wrapper_proxy, get_opaque_root_function,
+ get_reachable_wrappables_function);
JS::RootedObject target_object(context,
js::GetProxyTargetObject(wrapper_proxy));
JS_SetPrivate(target_object, private_data);
@@ -135,13 +144,16 @@
WrapperPrivate::WrapperPrivate(
JSContext* context, const scoped_refptr<Wrappable>& wrappable,
JS::HandleObject wrapper_proxy,
- const GetOpaqueRootFunction& get_opaque_root_function)
+ const GetOpaqueRootFunction& get_opaque_root_function,
+ const GetReachableWrappablesFunction& get_reachable_wrappables_function)
: context_(context),
wrappable_(wrappable),
wrapper_proxy_(wrapper_proxy),
- get_opaque_root_function_(get_opaque_root_function) {
+ get_opaque_root_function_(get_opaque_root_function),
+ get_reachable_wrappables_function_(get_reachable_wrappables_function) {
DCHECK(js::IsProxy(wrapper_proxy));
- if (!get_opaque_root_function_.is_null()) {
+ if (!get_opaque_root_function_.is_null() ||
+ !get_reachable_wrappables_function_.is_null()) {
MozjsGlobalEnvironment* global_environment =
MozjsGlobalEnvironment::GetFromContext(context_);
global_environment->opaque_root_tracker()->AddObjectWithOpaqueRoot(this);
@@ -149,7 +161,8 @@
}
WrapperPrivate::~WrapperPrivate() {
- if (!get_opaque_root_function_.is_null()) {
+ if (!get_opaque_root_function_.is_null() ||
+ !get_reachable_wrappables_function_.is_null()) {
MozjsGlobalEnvironment* global_environment =
MozjsGlobalEnvironment::GetFromContext(context_);
global_environment->opaque_root_tracker()->RemoveObjectWithOpaqueRoot(this);
diff --git a/src/cobalt/script/mozjs/wrapper_private.h b/src/cobalt/script/mozjs/wrapper_private.h
index 5bce933..d7ebfb1 100644
--- a/src/cobalt/script/mozjs/wrapper_private.h
+++ b/src/cobalt/script/mozjs/wrapper_private.h
@@ -16,6 +16,8 @@
#ifndef COBALT_SCRIPT_MOZJS_WRAPPER_PRIVATE_H_
#define COBALT_SCRIPT_MOZJS_WRAPPER_PRIVATE_H_
+#include <vector>
+
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
@@ -34,8 +36,11 @@
// must be destroyed when its JSObject is garbage collected.
class WrapperPrivate : public base::SupportsWeakPtr<WrapperPrivate> {
public:
+ typedef std::vector<Wrappable*> WrappableVector;
typedef base::Callback<Wrappable*(const scoped_refptr<Wrappable>&)>
GetOpaqueRootFunction;
+ typedef base::Callback<void(const scoped_refptr<Wrappable>&,
+ WrappableVector*)> GetReachableWrappablesFunction;
template <typename T>
scoped_refptr<T> wrappable() const {
@@ -45,6 +50,7 @@
JSObject* js_object_proxy() const { return wrapper_proxy_; }
Wrappable* GetOpaqueRoot() const;
+ void GetReachableWrappables(std::vector<Wrappable*>* reachable);
// Return true if the GC should avoid collecting this wrapper. Note that if
// the wrapper is unreachable, it may still be collected.
@@ -54,11 +60,13 @@
static void AddPrivateData(
JSContext* context, JS::HandleObject wrapper_proxy,
const scoped_refptr<Wrappable>& wrappable,
- const GetOpaqueRootFunction& get_opaque_root_function);
+ const GetOpaqueRootFunction& get_opaque_root_function,
+ const GetReachableWrappablesFunction& get_reachable_wrappables_function);
static void AddPrivateData(JSContext* context, JS::HandleObject wrapper_proxy,
const scoped_refptr<Wrappable>& wrappable) {
- AddPrivateData(context, wrapper_proxy, wrappable, GetOpaqueRootFunction());
+ AddPrivateData(context, wrapper_proxy, wrappable, GetOpaqueRootFunction(),
+ GetReachableWrappablesFunction());
}
// Get the WrapperPrivate associated with the given Wrappable. A new JSObject
@@ -86,15 +94,18 @@
static void Trace(JSTracer* trace, JSObject* object);
private:
- WrapperPrivate(JSContext* context, const scoped_refptr<Wrappable>& wrappable,
- JS::HandleObject wrapper_proxy,
- const GetOpaqueRootFunction& get_opaque_root_function);
+ WrapperPrivate(
+ JSContext* context, const scoped_refptr<Wrappable>& wrappable,
+ JS::HandleObject wrapper_proxy,
+ const GetOpaqueRootFunction& get_opaque_root_function,
+ const GetReachableWrappablesFunction& get_reachable_wrappables_function);
~WrapperPrivate();
JSContext* context_;
scoped_refptr<Wrappable> wrappable_;
JS::Heap<JSObject*> wrapper_proxy_;
GetOpaqueRootFunction get_opaque_root_function_;
+ GetReachableWrappablesFunction get_reachable_wrappables_function_;
};
} // namespace mozjs
diff --git a/src/cobalt/webdriver/get_element_text_test.cc b/src/cobalt/webdriver/get_element_text_test.cc
index fd9881b..b9a87e9 100644
--- a/src/cobalt/webdriver/get_element_text_test.cc
+++ b/src/cobalt/webdriver/get_element_text_test.cc
@@ -43,8 +43,8 @@
: css_parser_(css_parser::Parser::Create()),
dom_stat_tracker_(new dom::DomStatTracker("GetElementTextTest")),
html_element_context_(NULL, css_parser_.get(), NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, dom_stat_tracker_.get(),
- "") {}
+ NULL, NULL, NULL, NULL, NULL,
+ dom_stat_tracker_.get(), "") {}
void SetUp() OVERRIDE {
dom::Document::Options options;
diff --git a/src/cobalt/webdriver/is_displayed_test.cc b/src/cobalt/webdriver/is_displayed_test.cc
index 8953ec5..37d366a 100644
--- a/src/cobalt/webdriver/is_displayed_test.cc
+++ b/src/cobalt/webdriver/is_displayed_test.cc
@@ -61,8 +61,9 @@
NULL /* can_play_type_handler */,
NULL /* web_media_player_factory */, &script_runner_,
NULL /* media_source_registry */, resource_provider_stub_.get(),
- image_cache_.get(), NULL /* remote_font_cache */,
- dom_stat_tracker_.get(), "" /* language */) {}
+ image_cache_.get(), NULL /* reduced_image_cache_capacity_manager */,
+ NULL /* remote_font_cache */, dom_stat_tracker_.get(),
+ "" /* language */) {}
void SetUp() OVERRIDE {
// Load the document in a nested message loop.
diff --git a/src/crypto/run_all_unittests.cc b/src/crypto/run_all_unittests.cc
index 4571f08..585601f 100644
--- a/src/crypto/run_all_unittests.cc
+++ b/src/crypto/run_all_unittests.cc
@@ -5,30 +5,17 @@
#include "base/test/main_hook.h"
#include "base/test/test_suite.h"
#include "crypto/nss_util.h"
+#include "starboard/client_porting/wrap_main/wrap_main.h"
-#if !defined(OS_STARBOARD)
-int main(int argc, char** argv) {
- MainHook hook(main, argc, argv);
-
+int TestSuiteRun(int argc, char** argv) {
+ MainHook hook(NULL, argc, argv);
#if defined(USE_NSS)
// This is most likely not needed, but it basically replaces a similar call
// that was performed on test_support_base.
// TODO(rvargas) Bug 79359: remove this.
crypto::EnsureNSSInit();
#endif // defined(USE_NSS)
-
return base::TestSuite(argc, argv).Run();
}
-#else
-#include "starboard/event.h"
-#include "starboard/system.h"
-void SbEventHandle(const SbEvent* event) {
- if (event->type == kSbEventTypeStart) {
- SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
- MainHook hook(NULL, data->argument_count, data->argument_values);
- SbSystemRequestStop(
- base::TestSuite(data->argument_count, data->argument_values).Run());
- }
-}
-#endif
+STARBOARD_WRAP_SIMPLE_MAIN(TestSuiteRun);
diff --git a/src/media/base/sbplayer_pipeline.cc b/src/media/base/sbplayer_pipeline.cc
index 4130b45..ead7b85 100644
--- a/src/media/base/sbplayer_pipeline.cc
+++ b/src/media/base/sbplayer_pipeline.cc
@@ -299,7 +299,7 @@
bool video_read_in_progress_;
TimeDelta duration_;
- PipelineStatistics statistics_;
+ mutable PipelineStatistics statistics_;
SbPlayer player_;
@@ -372,7 +372,9 @@
if (SbPlayerIsValid(player_)) {
set_bounds_caller_->SetPlayer(kSbPlayerInvalid);
+ DLOG(INFO) << "Destroying SbPlayer.";
SbPlayerDestroy(player_);
+ DLOG(INFO) << "SbPlayer destroyed.";
player_ = kSbPlayerInvalid;
}
// When Stop() is in progress, we no longer need to call |error_cb_|.
@@ -461,6 +463,8 @@
}
SbPlayerInfo info;
SbPlayerGetInfo(player_, &info);
+ statistics_.video_frames_decoded = info.total_video_frames;
+ statistics_.video_frames_dropped = info.dropped_video_frames;
return SbMediaTimeToTimeDelta(info.current_media_pts);
}
diff --git a/src/media/player/web_media_player_impl.cc b/src/media/player/web_media_player_impl.cc
index 42a2f87..1defe0f 100644
--- a/src/media/player/web_media_player_impl.cc
+++ b/src/media/player/web_media_player_impl.cc
@@ -1161,8 +1161,10 @@
// Make sure to kill the pipeline so there's no more media threads running.
// Note: stopping the pipeline might block for a long time.
base::WaitableEvent waiter(false, false);
+ DLOG(INFO) << "Trying to stop media pipeline.";
pipeline_->Stop(
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter)));
+ DLOG(INFO) << "Media pipeline stopped.";
waiter.Wait();
message_loop_factory_.reset();
diff --git a/src/nb/reuse_allocator_benchmark.cc b/src/nb/reuse_allocator_benchmark.cc
index 42e5c45..4117d5c 100644
--- a/src/nb/reuse_allocator_benchmark.cc
+++ b/src/nb/reuse_allocator_benchmark.cc
@@ -23,6 +23,7 @@
#include "nb/allocator_decorator.h"
#include "nb/fixed_no_free_allocator.h"
#include "nb/reuse_allocator.h"
+#include "starboard/client_porting/wrap_main/wrap_main.h"
#include "starboard/event.h"
#include "starboard/file.h"
#include "starboard/log.h"
@@ -238,10 +239,4 @@
} // namespace
-void SbEventHandle(const SbEvent* event) {
- if (event->type == kSbEventTypeStart) {
- SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
- SbSystemRequestStop(
- BenchmarkMain(data->argument_count, data->argument_values));
- }
-}
+STARBOARD_WRAP_SIMPLE_MAIN(BenchmarkMain);
diff --git a/src/nb/run_all_unittests.cc b/src/nb/run_all_unittests.cc
index de25a95..f100b11 100644
--- a/src/nb/run_all_unittests.cc
+++ b/src/nb/run_all_unittests.cc
@@ -12,15 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "starboard/event.h"
-#include "starboard/system.h"
+#include "starboard/client_porting/wrap_main/wrap_main.h"
#include "testing/gtest/include/gtest/gtest.h"
-void SbEventHandle(const SbEvent* event) {
- if (event->type == kSbEventTypeStart) {
- SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
- ::testing::InitGoogleTest(&data->argument_count, data->argument_values);
- int result = RUN_ALL_TESTS();
- SbSystemRequestStop(result);
- }
+namespace {
+int InitAndRunAllTests(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
+} // namespace
+
+STARBOARD_WRAP_SIMPLE_MAIN(InitAndRunAllTests);
diff --git a/src/net/base/run_all_unittests.cc b/src/net/base/run_all_unittests.cc
index 2fc6fca..c08963c 100644
--- a/src/net/base/run_all_unittests.cc
+++ b/src/net/base/run_all_unittests.cc
@@ -9,6 +9,7 @@
#include "build/build_config.h"
#include "crypto/nss_util.h"
#include "net/base/net_test_suite.h"
+#include "starboard/client_porting/wrap_main/wrap_main.h"
#if !__LB_ENABLE_NATIVE_HTTP_STACK__
#include "net/socket/client_socket_pool_base.h"
@@ -27,8 +28,7 @@
#endif
int test_main(int argc, char** argv) {
- MainHook hook(test_main, argc, argv);
-
+ MainHook hook(NULL, argc, argv);
#if !defined(OS_STARBOARD)
scoped_ptr<base::ObjectWatchMultiplexer> watcher(
new base::ObjectWatchMultiplexer());
@@ -61,17 +61,4 @@
return test_suite.Run();
}
-#if !defined(OS_STARBOARD)
-int main(int argc, char** argv) {
- return test_main(argc, argv);
-}
-#else
-#include "starboard/event.h"
-#include "starboard/system.h"
-void SbEventHandle(const SbEvent* event) {
- if (event->type == kSbEventTypeStart) {
- SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
- SbSystemRequestStop(test_main(data->argument_count, data->argument_values));
- }
-}
-#endif
+STARBOARD_WRAP_SIMPLE_MAIN(test_main);
diff --git a/src/sql/run_all_unittests.cc b/src/sql/run_all_unittests.cc
index f63d4d5..ca6109b 100644
--- a/src/sql/run_all_unittests.cc
+++ b/src/sql/run_all_unittests.cc
@@ -5,28 +5,14 @@
#include "base/test/main_hook.h"
#include "base/test/test_suite.h"
#include "sql/test_vfs.h"
+#include "starboard/client_porting/wrap_main/wrap_main.h"
-#if !defined(OS_STARBOARD)
-int main(int argc, char** argv) {
- MainHook hook(main, argc, argv);
+int TestSuiteRun(int argc, char** argv) {
+ MainHook hook(NULL, argc, argv);
sql::RegisterTestVfs();
- int result = base::TestSuite(argc, argv).Run();
+ int error_level = base::TestSuite(argc, argv).Run();
sql::UnregisterTestVfs();
- return result;
+ return error_level;
}
-#else
-#include "starboard/event.h"
-#include "starboard/system.h"
-void SbEventHandle(const SbEvent* event) {
- if (event->type == kSbEventTypeStart) {
- SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
- MainHook hook(NULL, data->argument_count, data->argument_values);
- sql::RegisterTestVfs();
- int error_level =
- base::TestSuite(data->argument_count, data->argument_values).Run();
- sql::UnregisterTestVfs();
- SbSystemRequestStop(error_level);
- }
-}
-#endif
+STARBOARD_WRAP_SIMPLE_MAIN(TestSuiteRun);
diff --git a/src/starboard/client_porting/wrap_main/wrap_main.h b/src/starboard/client_porting/wrap_main/wrap_main.h
new file mode 100644
index 0000000..e4879d3
--- /dev/null
+++ b/src/starboard/client_porting/wrap_main/wrap_main.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This header defines two macros, COBALT_WRAP_SIMPLE_MAIN() and
+// COBALT_WRAP_BASE_MAIN(). Simple main is for programs that are
+// run-and-terminate, like unit tests. Base main is for programs that need a
+// main message loop, and will terminate when the quit_closure is called.
+
+#ifndef STARBOARD_CLIENT_PORTING_WRAP_MAIN_WRAP_MAIN_H_
+#define STARBOARD_CLIENT_PORTING_WRAP_MAIN_WRAP_MAIN_H_
+
+#if defined(STARBOARD)
+#include "starboard/event.h"
+#include "starboard/system.h"
+
+namespace starboard {
+namespace client_porting {
+namespace wrap_main {
+// A main-style function.
+typedef int (*MainFunction)(int argc, char** argv);
+
+template <MainFunction main_function>
+void SimpleEventHandler(const SbEvent* event) {
+ switch (event->type) {
+ case kSbEventTypeStart: {
+ SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
+ SbSystemRequestStop(
+ main_function(data->argument_count, data->argument_values));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+} // namespace wrap_main
+} // namespace client_porting
+} // namespace starboard
+
+#define STARBOARD_WRAP_SIMPLE_MAIN(main_function) \
+ void SbEventHandle(const SbEvent* event) { \
+ ::starboard::client_porting::wrap_main::SimpleEventHandler< \
+ main_function>(event); \
+ }
+
+#else
+#define STARBOARD_WRAP_SIMPLE_MAIN(main_function) \
+ int main(int argc, char** argv) { \
+ return main_function(argc, argv); \
+ }
+
+#endif // STARBOARD
+#endif // STARBOARD_CLIENT_PORTING_WRAP_MAIN_WRAP_MAIN_H_
diff --git a/src/starboard/nplb/main.cc b/src/starboard/nplb/main.cc
index 170a452..69f61b6 100644
--- a/src/starboard/nplb/main.cc
+++ b/src/starboard/nplb/main.cc
@@ -12,15 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "starboard/client_porting/wrap_main/wrap_main.h"
#include "starboard/event.h"
#include "starboard/system.h"
#include "testing/gtest/include/gtest/gtest.h"
-void SbEventHandle(const SbEvent* event) {
- if (event->type == kSbEventTypeStart) {
- SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
- ::testing::InitGoogleTest(&data->argument_count, data->argument_values);
- int result = RUN_ALL_TESTS();
- SbSystemRequestStop(result);
- }
+namespace {
+int InitAndRunAllTests(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
+} // namespace
+
+STARBOARD_WRAP_SIMPLE_MAIN(InitAndRunAllTests);
diff --git a/src/starboard/player.h b/src/starboard/player.h
index c897cc7..bc19c20 100644
--- a/src/starboard/player.h
+++ b/src/starboard/player.h
@@ -99,6 +99,18 @@
// The current player volume in [0, 1].
double volume;
+
+ // The number of video frames sent to the player since the creation of the
+ // player.
+ int total_video_frames;
+
+ // The number of video frames decoded but not displayed since the creation of
+ // the player.
+ int dropped_video_frames;
+
+ // The number of video frames that failed to be decoded since the creation of
+ // the player.
+ int corrupted_video_frames;
} SbPlayerInfo;
// An opaque handle to an implementation-private structure representing a
diff --git a/src/starboard/shared/starboard/player/player_internal.cc b/src/starboard/shared/starboard/player/player_internal.cc
index e14da96..2c7c9f6 100644
--- a/src/starboard/shared/starboard/player/player_internal.cc
+++ b/src/starboard/shared/starboard/player/player_internal.cc
@@ -49,6 +49,7 @@
frame_height_(0),
is_paused_(true),
volume_(1.0),
+ total_video_frames_(0),
worker_(this,
window,
video_codec,
@@ -80,6 +81,9 @@
SbMediaTime sample_pts,
const SbMediaVideoSampleInfo* video_sample_info,
const SbDrmSampleInfo* sample_drm_info) {
+ if (sample_type == kSbMediaTypeVideo) {
+ ++total_video_frames_;
+ }
InputBuffer* input_buffer = new InputBuffer(
sample_deallocate_func_, this, context_, sample_buffer,
sample_buffer_size, sample_pts, video_sample_info, sample_drm_info);
@@ -115,6 +119,9 @@
out_player_info->frame_height = frame_height_;
out_player_info->is_paused = is_paused_;
out_player_info->volume = volume_;
+ out_player_info->total_video_frames = total_video_frames_;
+ out_player_info->dropped_video_frames = 0;
+ out_player_info->corrupted_video_frames = 0;
}
void SbPlayerPrivate::SetPause(bool pause) {
diff --git a/src/starboard/shared/starboard/player/player_internal.h b/src/starboard/shared/starboard/player/player_internal.h
index 58b350d..7ecc299 100644
--- a/src/starboard/shared/starboard/player/player_internal.h
+++ b/src/starboard/shared/starboard/player/player_internal.h
@@ -69,6 +69,7 @@
int frame_height_;
bool is_paused_;
double volume_;
+ int total_video_frames_;
starboard::shared::starboard::player::PlayerWorker worker_;
};