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