Import Cobalt 12.88774 Change-Id: Id685e20e1b1f8fec13607b39f552fad3cc76ebae
diff --git a/src/.gn b/src/.gn new file mode 100644 index 0000000..13e4348 --- /dev/null +++ b/src/.gn
@@ -0,0 +1,18 @@ +# Copyright 2017 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. + +# The location of the build configuration file. +buildconfig = "//cobalt/build/config/BUILDCONFIG.gn" + +# TODO: add exec_script_whitelist
diff --git a/src/BUILD.gn b/src/BUILD.gn new file mode 100644 index 0000000..aaf5d17 --- /dev/null +++ b/src/BUILD.gn
@@ -0,0 +1,81 @@ +# Copyright 2017 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. + +# TODO: uncomment when //cobalt/browser:cobalt is converted over. Then this +# group will become the default target built when ninja is run, paralleling GYP +# behavior. +# group("default") { +# deps = [ +# "//cobalt/browser:cobalt" +# ] +# } + +# TODO: consider splitting test and non-test +group("all") { + testonly = true + deps = [ + # TODO: convert all of the targets below from GYP to GN + # Uncomment as each target is converted. + # See cobalt/build/all.gyp for the GYP names. + # In particular, each :all target (corresponding to GYP's foo/bar.gyp:*) + # mentioned here will have to be manually defined in the appropriate + # BUILD.gn file. Ditto for :all_test. + # "//base:unittests", + # "//cobalt/accessibility:all_test", + # "//cobalt/audio:all", + # "//cobalt/base:all", + # "//cobalt/bindings/testing:all", + # "//cobalt/browser:all", + # "//cobalt/browser:all_cobalt", + # "//cobalt/csp:all", + # "//cobalt/css_parser:all", + # "//cobalt/cssom:all", + # "//cobalt/cssom:all_test", + # "//cobalt/debug:all", + # "//cobalt/dom:all", + # "//cobalt/dom/dom_test.gyp:all", + # "//cobalt/dom_parser:all", + # "//cobalt/h5vcc:all", + # "//cobalt/input:all", + # "//cobalt/layout:all", + # "//cobalt/layout_tests:all", + # "//cobalt/loader/image/sandbox:all", + # "//cobalt/loader:all", + # "//cobalt/math:all", + # "//cobalt/media/sandbox:all", + # "//cobalt/media_session:all", + # "//cobalt/media_session:all_test", + # "//cobalt/network:all", + # "//cobalt/render_tree:all", + # "//cobalt/renderer:all", + # "//cobalt/renderer/sandbox:all", + # "//cobalt/samples/simple_example:all", + # "//cobalt/script:all", + # "//cobalt/script/engine:all", + # "//cobalt/speech/sandbox:all", + # "//cobalt/speech:all", + # "//cobalt/storage:all", + # "//cobalt/trace_event:all", + # "//cobalt/web_animations:all", + # "//cobalt/webdriver:all", + # "//cobalt/webdriver:all_test", + # "//cobalt/websocket:all", + # "//cobalt/xhr:all", + # "//crypto:crypto_unittests", + # "//sql:sql_unittests", + # "//nb/nb:test", + # "//nb:reuse_allocator_benchmark", + "//starboard:all", + ] +}
diff --git a/src/base/allocator/allocator.gyp b/src/base/allocator/allocator.gyp index 3c62f47..a2ed293 100644 --- a/src/base/allocator/allocator.gyp +++ b/src/base/allocator/allocator.gyp
@@ -315,124 +315,11 @@ }, }, 'conditions': [ - ['OS=="linux" and clang_type_profiler==1', { - 'dependencies': [ - 'type_profiler_tcmalloc', - ], - # It is undoing dependencies and cflags_cc for type_profiler which - # build/common.gypi injects into all targets. - 'dependencies!': [ - 'type_profiler', - ], - 'cflags_cc!': [ - '-fintercept-allocation-functions', - ], - }], - ['OS=="win"', { - 'defines': [ - 'PERFTOOLS_DLL_DECL=', - ], - 'defines!': [ - # tcmalloc source files unconditionally define this, remove it from - # the list of defines that common.gypi defines globally. - 'NOMINMAX', - ], - 'dependencies': [ - 'libcmt', - ], - 'include_dirs': [ - '<(jemalloc_dir)', - '<(tcmalloc_dir)/src/windows', - ], - 'sources!': [ - '<(tcmalloc_dir)/src/base/elf_mem_image.cc', - '<(tcmalloc_dir)/src/base/elf_mem_image.h', - '<(tcmalloc_dir)/src/base/linuxthreads.cc', - '<(tcmalloc_dir)/src/base/linuxthreads.h', - '<(tcmalloc_dir)/src/base/vdso_support.cc', - '<(tcmalloc_dir)/src/base/vdso_support.h', - '<(tcmalloc_dir)/src/maybe_threads.cc', - '<(tcmalloc_dir)/src/maybe_threads.h', - '<(tcmalloc_dir)/src/symbolize.h', - '<(tcmalloc_dir)/src/system-alloc.cc', - '<(tcmalloc_dir)/src/system-alloc.h', - - # included by allocator_shim.cc - 'debugallocation_shim.cc', - - # heap-profiler/checker/cpuprofiler - '<(tcmalloc_dir)/src/base/thread_lister.c', - '<(tcmalloc_dir)/src/base/thread_lister.h', - '<(tcmalloc_dir)/src/deep-heap-profile.cc', - '<(tcmalloc_dir)/src/deep-heap-profile.h', - '<(tcmalloc_dir)/src/heap-profiler.cc', - '<(tcmalloc_dir)/src/heap-profile-table.cc', - '<(tcmalloc_dir)/src/heap-profile-table.h', - '<(tcmalloc_dir)/src/memory_region_map.cc', - '<(tcmalloc_dir)/src/memory_region_map.h', - '<(tcmalloc_dir)/src/profiledata.cc', - '<(tcmalloc_dir)/src/profiledata.h', - '<(tcmalloc_dir)/src/profile-handler.cc', - '<(tcmalloc_dir)/src/profile-handler.h', - '<(tcmalloc_dir)/src/profiler.cc', - ], - }], - ['OS=="linux" or OS=="freebsd" or OS=="solaris"', { - 'sources!': [ - '<(tcmalloc_dir)/src/system-alloc.h', - '<(tcmalloc_dir)/src/windows/port.cc', - '<(tcmalloc_dir)/src/windows/port.h', - - # TODO(willchan): Support allocator shim later on. - 'allocator_shim.cc', - - # TODO(willchan): support jemalloc on other platforms - # jemalloc files - '<(jemalloc_dir)/jemalloc.c', - '<(jemalloc_dir)/jemalloc.h', - '<(jemalloc_dir)/ql.h', - '<(jemalloc_dir)/qr.h', - '<(jemalloc_dir)/rb.h', - - ], - # We enable all warnings by default, but upstream disables a few. - # Keep "-Wno-*" flags in sync with upstream by comparing against: - # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am - 'cflags': [ - '-Wno-sign-compare', - '-Wno-unused-result', - ], - 'cflags!': [ - '-fvisibility=hidden', - ], - 'link_settings': { - 'ldflags': [ - # Don't let linker rip this symbol out, otherwise the heap&cpu - # profilers will not initialize properly on startup. - '-Wl,-uIsHeapProfilerRunning,-uProfilerStart', - # Do the same for heap leak checker. - '-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi', - '-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl', - '-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv', - ]}, - }], - [ 'use_vtable_verify==1', { - 'cflags': [ - '-fvtable-verify=preinit', - ], - }], [ 'clang==1', { 'cflags': [ '-Wno-non-literal-null-conversion', ], }], - ['order_profiling != 0', { - 'target_conditions' : [ - ['_toolset=="target"', { - 'cflags!': [ '-finstrument-functions' ], - }], - ], - }], ], }, { @@ -449,18 +336,6 @@ 'include_dirs': [ '../../' ], - 'conditions': [ - ['OS=="linux" and clang_type_profiler==1', { - # It is undoing dependencies and cflags_cc for type_profiler which - # build/common.gypi injects into all targets. - 'dependencies!': [ - 'type_profiler', - ], - 'cflags_cc!': [ - '-fintercept-allocation-functions', - ], - }], - ], }, ], 'conditions': [
diff --git a/src/base/base.gyp b/src/base/base.gyp index d9c7764..56a0c9a 100644 --- a/src/base/base.gyp +++ b/src/base/base.gyp
@@ -239,7 +239,6 @@ 'metrics/statistics_recorder_unittest.cc', 'object_tracker.h', 'observer_list_unittest.cc', - 'optional_unittest.cc', 'path_service_unittest.cc', 'pickle_unittest.cc', 'platform_file_unittest.cc', @@ -248,7 +247,6 @@ 'rand_util_unittest.cc', 'scoped_observer.h', 'sha1_unittest.cc', - 'state_machine_shell_unittest.cc', 'stl_util_unittest.cc', 'string16_unittest.cc', 'string_number_conversions_unittest.cc',
diff --git a/src/base/base.gypi b/src/base/base.gypi index dc08b0c..fe57218 100644 --- a/src/base/base.gypi +++ b/src/base/base.gypi
@@ -183,9 +183,7 @@ 'native_library.h', 'observer_list.h', 'observer_list_threadsafe.h', - 'optional.cc', 'optional.h', - 'optional_internal.h', 'path_service.cc', 'path_service.h', 'pending_task.cc', @@ -218,7 +216,6 @@ 'sha1.h', 'sha1_portable.cc', 'single_thread_task_runner.h', - 'state_machine_shell.cc', 'state_machine_shell.h', 'stl_util.h', 'string16.cc',
diff --git a/src/base/optional.cc b/src/base/optional.cc deleted file mode 100644 index 59100ad..0000000 --- a/src/base/optional.cc +++ /dev/null
@@ -1,24 +0,0 @@ -/* - * Copyright 2014 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "optional.h" - -namespace base { - -const nullopt_t nullopt; -const in_place_t in_place; - -} // namespace base
diff --git a/src/base/optional.h b/src/base/optional.h index 66bc53f..ce973ea 100644 --- a/src/base/optional.h +++ b/src/base/optional.h
@@ -17,377 +17,17 @@ #ifndef BASE_OPTIONAL_H_ #define BASE_OPTIONAL_H_ -#include <iosfwd> - -#include "base/base_export.h" -#include "base/hash_tables.h" #include "base/logging.h" #include "base/memory/aligned_memory.h" +#include "starboard/common/optional.h" namespace base { - -// This class is based off of std::experimental::optional: -// http://en.cppreference.com/w/cpp/experimental/optional -// -// It is a template class where instances parameterized by type T contain -// memory for an instance of type T, but it may or may not be constructed. -// If it is not constructed, it cannot be accessed, and if it is, it can -// be accessed. This allows one to check if the inner object exists or not -// before using it, and is useful for functions that may or may not return -// a value. Note that the memory for the object is stored internally, so -// no heap allocations are made over the course of construction and destruction -// of the internal object (unless the internal object allocates memory within -// its constructor). -// -// Some functionality is left out. For example, most C++11 functionality -// is not implemented, since we would like this to be friendly to non-C++11 -// compilers. -// -// In the future, if C++11 functionality is needed, it can be implemented -// and surrounded by preprocessor guards to maintain compatibility with non -// C++11 compilers. -// - -// The nullopt_t type is used as a signal for an empty optional. If any -// optional is assigned the value of nullopt, it will be disengaged. -// For example, -// base::optional<int> my_int_optional(5); -// EXPECT_FALSE(!my_int_optional); -// my_int_optional = base::nullopt; -// EXPECT_TRUE(!my_int_optional); -// -struct nullopt_t { - nullopt_t() {} -}; -extern const nullopt_t nullopt; - -// The in_place_t type is used to signal in-place construction of the internal -// object. This is used by the in place constructor of optional, which forwards -// its parameters to the internal object's constructor. -// For example, -// class Foo { -// public: -// Foo(int x, int y) { x_ = x; y_ = y; } -// int x() const { return x_; } -// int y() const { return y_; } -// -// private: -// int x_; -// int y_; -// }; -// -// ... -// -// base::optional<Foo> my_foo(base::in_place, 2, 3); -// EXPECT_FALSE(!my_foo); -// EXPECT_EQ(2, my_foo->x()); -// EXPECT_EQ(3, my_foo->y()); -// -struct in_place_t { - in_place_t() {} -}; -extern const in_place_t in_place; - -template <typename T> -class BASE_EXPORT optional { - public: - // Construction via the default constructor results in an optional that is - // not engaged. - optional() { InitializeAsDisengaged(); } - - optional(nullopt_t) { InitializeAsDisengaged(); } - - // This non-explicit singleton constructor is provided so users can pass in a - // T wherever a optional<T> is expected. - optional(const T& value) { SetValue(value); } - - optional(const optional<T>& other) { - if (other.engaged_) { - SetValue(other.value()); - } else { - InitializeAsDisengaged(); - } - } - - // Destruct contained object upon optional's destruction. - ~optional() { EnsureDisengaged(); } - - // Disengages the optional, calling the destructor of the contained object - // if it is engaged. - optional<T>& operator=(nullopt_t) { - EnsureDisengaged(); - return *this; - } - - // Reassigns the underlying optional to value passed in on the right hand - // side. This will destruct the lhs contained object first if it exists. - template <typename U> - optional<T>& operator=(const U& other) { - if (engaged_) { - value() = other; - } else { - SetValue(other); - } - return *this; - } - - // Copy assignment - optional<T>& operator=(const optional<T>& other) { - if (engaged_ && other.engaged_) { - value() = other.value(); - } else if (!engaged_ && other.engaged_) { - SetValue(other.value()); - } else if (engaged_ && !other.engaged_) { - EnsureDisengaged(); - } - // Do nothing if lhs and rhs are both not engaged. - return *this; - } - - // Overloaded conversion to bool operator for determining whether the optional - // is engaged or not. It returns true if the optional is engaged, and false - // otherwise. -#if (defined(_MSC_VER) && (_MSC_VER < 1800)) || \ - (defined(__GNUC__) && \ - (__GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 5)))) - // MSVC 2012 does not support explicit cast operators. - // http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx - - // For any compiler that doesn't support explicit bool operators, we instead - // use the Safe Bool Idiom: http://www.artima.com/cppsource/safebool.html - private: - // The type of SafeBoolIdiomType (pointer to data member of a private type) is - // limited in functionality so much that the only thing a user can do with it - // is test for null, or apply to operator==/operator!=. Since both operators - // == and != are already overloaded for optional, this leaves null tests, - // which we use for boolean testing. - class PrivateSafeBoolIdiomFakeMemberType; - typedef PrivateSafeBoolIdiomFakeMemberType optional::*SafeBoolIdiomType; - public: - operator const SafeBoolIdiomType() const { - // If we wish to return true, we cast engaged_ to our private type giving - // a non-null pointer to data member. Otherwise, we return NULL. The - // only thing the user can do with the return type is test for NULL. - return engaged_ ? - reinterpret_cast<const SafeBoolIdiomType>(&optional::engaged_) : - NULL; - } -#else - explicit operator bool() const { return engaged_; } -#endif - - // Dereferences the internal object. - const T* operator->() const { return &(value()); } - - T* operator->() { return &(value()); } - - const T& operator*() const { return value(); } - - T& operator*() { return value(); } - - // Dereferences and returns the internal object. - const T& value() const { - DCHECK(engaged_) << "Attempted to access object in a disengaged optional."; - return *static_cast<const T*>(value_memory_.void_data()); - } - - T& value() { - DCHECK(engaged_) << "Attempted to access object in a disengaged optional."; - return *static_cast<T*>(value_memory_.void_data()); - } - - template <typename U> - T value_or(const U& value) const { - if (engaged_) { - return this->value(); - } else { - return value; - } - } - - // Swaps the values of two optionals. - void swap(optional<T>& other) { - if (engaged_ && other.engaged_) { - // Swap the value contents with each other. - std::swap(value(), other.value()); - } else if (engaged_) { - other.SetValue(value()); - EnsureDisengaged(); - } else if (other.engaged_) { - SetValue(other.value()); - other.EnsureDisengaged(); - } - // If both the lhs and rhs are not engaged, we do nothing. - } - -// include the pump.py-generated declaration and impelmentation for -// forwarding constructor and emplace. -#include "optional_internal.h" - - private: - // Sets a non-engaged optional to a specified value, and marks it as engaged. - template <typename U> - void SetValue(const U& value) { - new (value_memory_.void_data()) T(value); - engaged_ = true; -#if !defined(NDEBUG) - value_ptr_ = static_cast<const T*>(value_memory_.void_data()); -#endif - } - - // If an optional is engaged, it destructs the wrapped value and marks the - // optional as disengaged. Does nothing to a disengaged optional. - void EnsureDisengaged() { - if (engaged_) { - static_cast<T*>(value_memory_.void_data())->~T(); - engaged_ = false; -#if !defined(NDEBUG) - value_ptr_ = NULL; -#endif - } - } - - // Called upon object construction to initialize the object into a disengaged - // state. - void InitializeAsDisengaged() { - engaged_ = false; -#if !defined(NDEBUG) - value_ptr_ = NULL; -#endif - } - - // The actual memory reserved for the object that may or may not exist. - base::AlignedMemory<sizeof(T), ALIGNOF(T)> value_memory_; - // This boolean tracks whether or not the object is constructed yet or not. - bool engaged_; -#if !defined(NDEBUG) - // In debug builds, this member makes it easy to inspect the value contained - // in the optional via a debugger. - const T* value_ptr_; -#endif -}; - -// Comparison between 2 optionals -template <typename T> -inline bool operator==(const optional<T>& lhs, const optional<T>& rhs) { - if (!lhs) { - return !rhs; - } - - return rhs == lhs.value(); -} - -template <typename T> -inline bool operator<(const optional<T>& lhs, const optional<T>& rhs) { - if (lhs && rhs) { - return lhs.value() < rhs.value(); - } else { - // Handle all other cases simply in terms of whether the optionals are - // engaged or not. - return static_cast<bool>(lhs) < static_cast<bool>(rhs); - } -} - -// Comparison with nullopt_t -template <typename T> -inline bool operator==(nullopt_t, const optional<T>& rhs) { - return !rhs; -} - -template <typename T> -inline bool operator==(const optional<T>& lhs, nullopt_t rhs) { - return rhs == lhs; -} - -template <typename T> -inline bool operator<(const optional<T>& /* lhs */, nullopt_t) { - return false; -} - -template <typename T> -inline bool operator<(nullopt_t, const optional<T>& rhs) { - return static_cast<bool>(rhs); -} - -// Comparison between an optional and a value -template <typename T> -inline bool operator==(const optional<T>& lhs, const T& rhs) { - return (!lhs ? false : lhs.value() == rhs); -} - -template <typename T> -inline bool operator==(const T& lhs, const optional<T>& rhs) { - return rhs == lhs; -} - -template <typename T> -inline bool operator<(const T& lhs, const optional<T>& rhs) { - return rhs && lhs < rhs.value(); -} - -template <typename T> -inline bool operator<(const optional<T>& lhs, const T& rhs) { - return !lhs || lhs.value() < rhs; -} - -// This is a convenient but non-standard method, do not rely on it if you expect -// the compatibility with upcoming C++ versions. -template <typename T> -inline std::ostream& operator<<(std::ostream& stream, - const optional<T>& maybe_value) { - if (maybe_value) { - stream << *maybe_value; - } else { - stream << "nullopt"; - } - return stream; -} - -template <typename T> -optional<T> make_optional(const T& value) { - return optional<T>(value); -} - +using starboard::nullopt_t; +using starboard::nullopt; +using starboard::in_place_t; +using starboard::in_place; +using starboard::optional; +using starboard::make_optional; } // namespace base -namespace BASE_HASH_NAMESPACE { - -#if defined(BASE_HASH_USE_HASH_STRUCT) -template <typename T> -struct hash<base::optional<T> > { - public: - size_t operator()(const base::optional<T>& value) const { - if (!value) { - return 0; - } else { - return value_hash_(value.value()); - } - } - - private: - hash<T> value_hash_; -}; - -#else -template <typename T> -inline size_t hash_value(const base::optional<T>& value) { - if (!value) { - return 0; - } else { - return hash_value(value.value()); - } -} - -#endif // defined(BASE_HASH_USE_HASH_STRUCT) -} // namespace BASE_HASH_NAMESPACE - -namespace std { - -template <typename T> -void swap(base::optional<T>& lhs, base::optional<T>& rhs) { - lhs.swap(rhs); -} - -} // namespace std - #endif // BASE_OPTIONAL_H_
diff --git a/src/base/optional_unittest.cc b/src/base/optional_unittest.cc deleted file mode 100644 index 3fe99c8..0000000 --- a/src/base/optional_unittest.cc +++ /dev/null
@@ -1,730 +0,0 @@ -/* - * Copyright 2014 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <set> -#include <string> -#include <vector> - -#include "base/hash_tables.h" -#include "base/optional.h" - -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::InSequence; - -typedef base::optional<int> OptionalInt; - -TEST(OptionalTest, EnsureDefaultConstructorGivesDisengagedOptional) { - OptionalInt test; - EXPECT_TRUE(!test); -} - -TEST(OptionalTest, EnsureNullOptConstructorGivesDisengagedOptional) { - OptionalInt test(base::nullopt); - EXPECT_TRUE(!test); -} - -TEST(OptionalTest, InitializeConstructor) { - OptionalInt test(2); - EXPECT_FALSE(!test); - EXPECT_EQ(2, test.value()); -} - -TEST(OptionalTest, BoolCastOperator) { - OptionalInt test; - EXPECT_FALSE(static_cast<bool>(test)); - - test = 5; - EXPECT_TRUE(static_cast<bool>(test)); -} - -TEST(OptionalTest, InitializeAssign) { - OptionalInt test = 2; - EXPECT_FALSE(!test); - EXPECT_EQ(2, test.value()); -} - -TEST(OptionalTest, ReassignValue) { - OptionalInt test(2); - test = 5; - EXPECT_FALSE(!test); - EXPECT_EQ(5, test.value()); -} - -TEST(OptionalTest, CopyAssignment) { - OptionalInt a; - OptionalInt b = 2; - OptionalInt c = 3; - a = b; - EXPECT_FALSE(!a); - EXPECT_EQ(2, a.value()); - - a = c; - EXPECT_FALSE(!a); - EXPECT_EQ(3, a.value()); -} - -TEST(OptionalTest, ClearAssignment) { - OptionalInt test(2); - test = OptionalInt(); - EXPECT_FALSE(test); -} - -TEST(OptionalTest, EnsureAssignmentOfNullOptResultsInDisengagement) { - OptionalInt test(2); - test = base::nullopt; - EXPECT_FALSE(test); -} - -TEST(OptionalTest, EnsureAssignmentOfDefaultOptionalResultsInDisengagement) { - OptionalInt test(2); - test = OptionalInt(); - EXPECT_FALSE(test); -} - -TEST(OptionalTest, CopyConstruction) { - OptionalInt test1(2); - OptionalInt test2(test1); - - EXPECT_FALSE(!test2); - EXPECT_EQ(2, test2.value()); -} - -TEST(OptionalTest, Swap) { - OptionalInt test1(1); - OptionalInt test2(2); - - // Swap two engaged optionals. - test1.swap(test2); - EXPECT_FALSE(!test1); - EXPECT_EQ(2, test1.value()); - EXPECT_EQ(1, test2.value()); - - // Swap two optionals where only one is engaged. - test1 = base::nullopt; - test1.swap(test2); - EXPECT_FALSE(test2); - EXPECT_FALSE(!test1); - EXPECT_EQ(1, test1.value()); - - // Swap two optionals where only one is engaged, except the other way around. - test1.swap(test2); - EXPECT_FALSE(test1); - EXPECT_FALSE(!test2); - EXPECT_EQ(1, test2.value()); - - // Swap two disengaged optionals. - test2 = base::nullopt; - test1.swap(test2); - EXPECT_FALSE(test1); - EXPECT_FALSE(test2); -} - -TEST(OptionalTest, StdSwap) { - OptionalInt test1(1); - OptionalInt test2(2); - - // Swap two engaged optionals. - std::swap(test1, test2); - EXPECT_FALSE(!test1); - EXPECT_EQ(2, test1.value()); - EXPECT_EQ(1, test2.value()); - - // Swap two optionals where only one is engaged. - test1 = base::nullopt; - std::swap(test1, test2); - EXPECT_FALSE(test2); - EXPECT_FALSE(!test1); - EXPECT_EQ(1, test1.value()); - - // Swap two optionals where only one is engaged, except the other way around. - std::swap(test1, test2); - EXPECT_FALSE(test1); - EXPECT_FALSE(!test2); - EXPECT_EQ(1, test2.value()); - - // Swap two disengaged optionals. - test2 = base::nullopt; - std::swap(test1, test2); - EXPECT_FALSE(test1); - EXPECT_FALSE(test2); -} - -TEST(OptionalTest, SwapWithSelf) { - OptionalInt test(1); - - test.swap(test); - EXPECT_EQ(1, test.value()); - - std::swap(test, test); - EXPECT_EQ(1, test.value()); -} - -TEST(OptionalTest, AsteriskDereference) { - OptionalInt test(2); - EXPECT_EQ(2, *test); - - *test = 5; - EXPECT_EQ(5, test.value()); -} - -namespace { -struct TestStruct { - int foobar; -}; -} // namespace - -TEST(OptionalTest, ArrowDereference) { - TestStruct a; - a.foobar = 2; - - base::optional<TestStruct> test(a); - EXPECT_EQ(2, test->foobar); - - test->foobar = 5; - EXPECT_EQ(5, test.value().foobar); - - // Test const arrow dereference. - const base::optional<TestStruct> test_const(a); - EXPECT_EQ(2, test_const->foobar); -} - -namespace { -class NoDefaultTest { - public: - explicit NoDefaultTest(int i) { foobar_ = i; } - int foobar() const { return foobar_; } - - private: - NoDefaultTest(); - - int foobar_; -}; -} // namespace - -TEST(OptionalTest, NoDefaultConstructorIsSupported) { - // First test with an object passed in upon construction - base::optional<NoDefaultTest> test1(NoDefaultTest(2)); - EXPECT_EQ(2, test1.value().foobar()); - - // Now test with an object assignment after construction - base::optional<NoDefaultTest> test2; - test2 = NoDefaultTest(5); - EXPECT_EQ(5, test2.value().foobar()); -} - -TEST(OptionalTest, TestEquivalenceComparisons) { - OptionalInt test1 = 1; - OptionalInt test2 = 2; - OptionalInt test3; - OptionalInt test4 = 2; - - EXPECT_FALSE(test1 == test2); - EXPECT_FALSE(test2 == test1); - EXPECT_FALSE(test1 == test3); - EXPECT_FALSE(test3 == test1); - EXPECT_FALSE(2 == test1); - EXPECT_FALSE(test1 == 2); - EXPECT_EQ(1, test1); - EXPECT_EQ(test1, 1); - EXPECT_EQ(test4, test2); - EXPECT_EQ(test2, test4); - - // Test nullopt comparisons - EXPECT_TRUE(test3 == base::nullopt); - EXPECT_TRUE(base::nullopt == test3); - EXPECT_FALSE(test1 == base::nullopt); - EXPECT_FALSE(base::nullopt == test1); -} - -TEST(OptionalTest, TestLessThanComparisons) { - OptionalInt test1 = 1; - OptionalInt test2 = 2; - OptionalInt test3; - OptionalInt test4 = 2; - - EXPECT_TRUE(test1 < test2); - EXPECT_FALSE(test2 < test1); - EXPECT_FALSE(test1 < test1); - EXPECT_TRUE(test3 < test1); - EXPECT_FALSE(test1 < test3); - EXPECT_FALSE(test3 < test3); - - EXPECT_TRUE(base::nullopt < test1); - EXPECT_FALSE(test1 < base::nullopt); - - EXPECT_TRUE(test1 < 2); - EXPECT_FALSE(2 < test1); -} - -TEST(OptionalTest, EnsureOptionalWorksWithFunnyAlignments) { - struct { - char c; - base::optional<uint64_t> number; - } foo; - - EXPECT_FALSE(!!foo.number); - foo.number = 1; - EXPECT_TRUE(!!foo.number); - EXPECT_EQ(1, foo.number.value()); -} - -namespace { - -class DestructorCallTester { - public: - DestructorCallTester() {}; - DestructorCallTester(const DestructorCallTester&) {}; - ~DestructorCallTester() { Die(); } - MOCK_METHOD0(Die, void()); -}; - -} // namespace - -TEST(OptionalTest, EnsureDestructorIsCalled) { - { - // Ensure destructor is called upon optional destruction - base::optional<DestructorCallTester> test(base::in_place); - EXPECT_CALL(test.value(), Die()); - } - - { - // Ensure destructor is called upon assignment to null - base::optional<DestructorCallTester> test1(base::in_place); - base::optional<DestructorCallTester> test2(base::in_place); - { - InSequence s; - EXPECT_CALL(test1.value(), Die()); - EXPECT_CALL(test2.value(), Die()); - } - test1 = base::nullopt; - } -} - -namespace { - -// This class counts all calls to the set of methods declared in the class. -// It can be used to verify that certain methods are indeed called. -class MethodCallCounter { - public: - MethodCallCounter() { - ResetCounts(); - ++default_constructor_calls_; - } - - MethodCallCounter(const MethodCallCounter& other) { - // A very non-standard copy constructor, since this is a test object - // intended to count method calls on this object and only this object. - ResetCounts(); - ++copy_constructor_calls_; - } - - MethodCallCounter& operator=(const MethodCallCounter& other) { - ++operator_equals_calls_; - return *this; - } - - int default_constructor_calls() const { return default_constructor_calls_; } - int copy_constructor_calls() const { return copy_constructor_calls_; } - int operator_equals_calls() const { return operator_equals_calls_; } - - private: - void ResetCounts() { - default_constructor_calls_ = 0; - copy_constructor_calls_ = 0; - operator_equals_calls_ = 0; - } - - int default_constructor_calls_; - int copy_constructor_calls_; - int operator_equals_calls_; -}; - -} // namespace - -TEST(OptionalTest, CopyConstructorIsCalledByValueCopyConstructor) { - MethodCallCounter original_counter; - base::optional<MethodCallCounter> test(original_counter); - EXPECT_EQ(0, test->default_constructor_calls()); - EXPECT_EQ(1, test->copy_constructor_calls()); - EXPECT_EQ(0, test->operator_equals_calls()); -} - -TEST(OptionalTest, CopyConstructorIsCalledByOptionalCopyConstructor) { - MethodCallCounter original_counter; - base::optional<MethodCallCounter> test1(original_counter); - base::optional<MethodCallCounter> test2(test1); - EXPECT_EQ(0, test2->default_constructor_calls()); - EXPECT_EQ(1, test2->copy_constructor_calls()); - EXPECT_EQ(0, test2->operator_equals_calls()); -} - -TEST(OptionalTest, CopyConstructorIsCalledByValueAssignment) { - MethodCallCounter original_counter; - base::optional<MethodCallCounter> test; - test = original_counter; - EXPECT_EQ(0, test->default_constructor_calls()); - EXPECT_EQ(1, test->copy_constructor_calls()); - EXPECT_EQ(0, test->operator_equals_calls()); -} - -TEST(OptionalTest, CopyConstructorIsCalledByOptionalAssignment) { - MethodCallCounter original_counter; - base::optional<MethodCallCounter> test1(original_counter); - base::optional<MethodCallCounter> test2; - test2 = test1; - EXPECT_EQ(0, test2->default_constructor_calls()); - EXPECT_EQ(1, test2->copy_constructor_calls()); - EXPECT_EQ(0, test2->operator_equals_calls()); -} - -TEST(OptionalTest, AssignmentIsCalledByValueAssignment) { - MethodCallCounter original_counter; - base::optional<MethodCallCounter> test(original_counter); - test = original_counter; - EXPECT_EQ(0, test->default_constructor_calls()); - EXPECT_EQ(1, test->copy_constructor_calls()); - EXPECT_EQ(1, test->operator_equals_calls()); -} - -TEST(OptionalTest, AssignmentIsCalledByOptionalAssignment) { - MethodCallCounter original_counter; - base::optional<MethodCallCounter> test1(original_counter); - base::optional<MethodCallCounter> test2(original_counter); - test2 = test1; - EXPECT_EQ(0, test2->default_constructor_calls()); - EXPECT_EQ(1, test2->copy_constructor_calls()); - EXPECT_EQ(1, test2->operator_equals_calls()); -} - -TEST(OptionalTest, EnsureSelfAssignmentIsOkay) { - // Ensure that values are as we expect them to be. - OptionalInt test1(5); - - test1 = test1; - - EXPECT_FALSE(!test1); - EXPECT_EQ(5, test1.value()); - - // Ensure that the methods we expect to be called are actually called. - base::optional<MethodCallCounter> test2(base::in_place); - - test2 = test2; - - EXPECT_EQ(1, test2->default_constructor_calls()); - EXPECT_EQ(0, test2->copy_constructor_calls()); - EXPECT_EQ(1, test2->operator_equals_calls()); -} - -namespace { - -// Helper classes to ensure that we can assign different values to optionals -// so long as the wrapped value can be assigned and constructed from the other. -struct XType { - XType(int number) { number_ = number; } - - int number_; -}; - -struct YType { - explicit YType(int number) { number_ = number; } - - explicit YType(const XType& x_type) { number_ = x_type.number_; } - - YType& operator=(const XType& x_type) { - number_ = x_type.number_; - return *this; - } - - int number_; -}; - -} // namespace - -TEST(OptionalTest, CopyConstructorIsCalledByValueAssignmentFromOtherType) { - XType x_type(1); - base::optional<YType> test; - test = x_type; - EXPECT_FALSE(!test); - EXPECT_EQ(1, test->number_); -} - -TEST(OptionalTest, AssignmentIsCalledByValueAssignmentFromOtherType) { - XType x_type(1); - base::optional<YType> test(base::in_place, 2); - test = x_type; - EXPECT_FALSE(!test); - EXPECT_EQ(1, test->number_); -} - -TEST(OptionalTest, TestMakeOptional) { - OptionalInt test = base::make_optional(5); - - EXPECT_FALSE(!test); - EXPECT_EQ(5, test.value()); -} - -TEST(OptionalTest, ValueOrTest) { - OptionalInt test; - - EXPECT_EQ(4, test.value_or(4)); - - test = 2; - - EXPECT_EQ(2, test.value_or(4)); -} - -TEST(OptionalTest, ConstOptionalsTest) { - const OptionalInt test1(5); - - EXPECT_FALSE(!test1); - EXPECT_EQ(5, test1.value()); - EXPECT_EQ(5, *test1); - - const OptionalInt test2(test1); - - EXPECT_FALSE(!test2); - EXPECT_EQ(5, test2.value()); - EXPECT_EQ(5, *test2); - - OptionalInt test3; - test3 = test2; - - EXPECT_FALSE(!test3); - EXPECT_EQ(5, test3.value()); - EXPECT_EQ(5, *test3); -} - -TEST(OptionalTest, EmplaceInt) { - OptionalInt test; - - test.emplace(5); - EXPECT_FALSE(!test); - EXPECT_EQ(5, test.value()); -} - -TEST(OptionalTest, EmplaceWithDefaultConstructor) { - base::optional<MethodCallCounter> test; - test.emplace(); - - EXPECT_FALSE(!test); - EXPECT_EQ(1, test->default_constructor_calls()); - EXPECT_EQ(0, test->copy_constructor_calls()); - EXPECT_EQ(0, test->operator_equals_calls()); -} - -namespace { - -class NoDefaultOrCopyConstructor { - public: - NoDefaultOrCopyConstructor(int x, int y) { - x_ = x; - y_ = y; - } - - int x() const { return x_; } - int y() const { return y_; } - - private: - NoDefaultOrCopyConstructor(); - NoDefaultOrCopyConstructor(const NoDefaultOrCopyConstructor&); - - int x_; - int y_; -}; - -} // namespace - -TEST(OptionalTest, EmplaceObjectWithNoDefaultOrCopyConstructor) { - base::optional<NoDefaultOrCopyConstructor> test; - test.emplace(1, 2); - EXPECT_FALSE(!test); - EXPECT_EQ(1, test->x()); - EXPECT_EQ(2, test->y()); -} - -namespace { - -class NonConstPointerInConstructor { - public: - explicit NonConstPointerInConstructor(int* param) { param_ = param; } - - void SetParam(int value) { *param_ = value; } - - private: - int* param_; -}; - -} // namespace - -TEST(OptionalTest, EmplaceObjectWithNonConstPointer) { - int value = 0; - base::optional<NonConstPointerInConstructor> test; - test.emplace(&value); - test->SetParam(5); - EXPECT_EQ(5, value); -} - -TEST(OptionalTest, ForwardingConstructorInt) { - OptionalInt test(base::in_place, 5); - EXPECT_FALSE(!test); - EXPECT_EQ(5, test.value()); -} - -TEST(OptionalTest, ForwardingConstructorWithDefaultConstructor) { - base::optional<MethodCallCounter> test(base::in_place); - EXPECT_FALSE(!test); - EXPECT_EQ(1, test->default_constructor_calls()); - EXPECT_EQ(0, test->copy_constructor_calls()); - EXPECT_EQ(0, test->operator_equals_calls()); -} - -TEST(OptionalTest, ForwardingConstructorObjectWithNoDefaultOrCopyConstructor) { - base::optional<NoDefaultOrCopyConstructor> test(base::in_place, 1, 2); - EXPECT_FALSE(!test); - EXPECT_EQ(1, test->x()); - EXPECT_EQ(2, test->y()); -} - -TEST(OptionalTest, ForwardingConstructorObjectWithNonConstPointer) { - int value = 0; - base::optional<NonConstPointerInConstructor> test(base::in_place, &value); - test->SetParam(5); - EXPECT_EQ(5, value); -} - -namespace { -typedef base::optional<std::string> OptionalString; -} // namespace - -TEST(OptionalTest, OptionalStringTest) { - { - OptionalString test; - EXPECT_TRUE(!test); - - test = std::string("foo"); - EXPECT_STREQ("foo", test->c_str()); - } - - { - OptionalString test(std::string("foo")); - EXPECT_FALSE(!test); - - EXPECT_STREQ("foo", test->c_str()); - OptionalString test2(test); - EXPECT_STREQ("foo", test2->c_str()); - } -} - -TEST(OptionalTest, OptionalStringInSetTest) { - // Optional strings in map test - std::set<OptionalString> optional_string_set; - - optional_string_set.insert(std::string("foo")); - optional_string_set.insert(std::string("bar")); - - EXPECT_TRUE(optional_string_set.find(std::string("foo")) != - optional_string_set.end()); - EXPECT_TRUE(optional_string_set.find(std::string("bar")) != - optional_string_set.end()); - EXPECT_FALSE(optional_string_set.find(OptionalString()) != - optional_string_set.end()); - - optional_string_set.insert(OptionalString()); - - EXPECT_TRUE(optional_string_set.find(std::string("foo")) != - optional_string_set.end()); - EXPECT_TRUE(optional_string_set.find(std::string("bar")) != - optional_string_set.end()); - EXPECT_TRUE(optional_string_set.find(OptionalString()) != - optional_string_set.end()); -} - -TEST(OptionalTest, StdVectorOfOptionalsWorksFine) { - std::vector<OptionalInt> test_vector; - - test_vector.reserve(test_vector.capacity() + 1); - test_vector.resize(test_vector.capacity()); - - // Make sure all current optionals are disengaged. - for (std::vector<OptionalInt>::const_iterator iter = test_vector.begin(); - iter != test_vector.end(); - ++iter) { - EXPECT_TRUE(!*iter); - } - EXPECT_TRUE(!test_vector[0]); - - test_vector.clear(); - test_vector.resize(test_vector.capacity() + 1, 5); - for (std::vector<OptionalInt>::const_iterator iter = test_vector.begin(); - iter != test_vector.end(); - ++iter) { - ASSERT_FALSE(!*iter); - EXPECT_EQ(5, **iter); - } - ASSERT_FALSE(!test_vector[0]); - EXPECT_EQ(5, *test_vector[0]); - - test_vector.push_back(8); - ASSERT_FALSE(!test_vector.back()); - EXPECT_EQ(8, *test_vector.back()); -} - -TEST(OptionalTest, OptionalStringInHashSetTest) { - // Optional strings in map test - base::hash_set<OptionalString> optional_string_set; - - optional_string_set.insert(std::string("foo")); - optional_string_set.insert(std::string("bar")); - - EXPECT_TRUE(optional_string_set.find(std::string("foo")) != - optional_string_set.end()); - EXPECT_TRUE(optional_string_set.find(std::string("bar")) != - optional_string_set.end()); - EXPECT_FALSE(optional_string_set.find(OptionalString()) != - optional_string_set.end()); - - optional_string_set.insert(OptionalString()); - - EXPECT_TRUE(optional_string_set.find(std::string("foo")) != - optional_string_set.end()); - EXPECT_TRUE(optional_string_set.find(std::string("bar")) != - optional_string_set.end()); - EXPECT_TRUE(optional_string_set.find(OptionalString()) != - optional_string_set.end()); -} - -namespace { - -OptionalInt ConditionallyMakeOptional(bool should_make, int value) { - if (should_make) { - return OptionalInt(value); - } else { - return base::nullopt; - } -} - -} // namespace - -TEST(OptionalTest, OptionalCanBeReturnedFromFunction) { - OptionalInt test1 = ConditionallyMakeOptional(true, 5); - ASSERT_FALSE(!test1); - EXPECT_EQ(5, test1.value()); - - OptionalInt test2 = ConditionallyMakeOptional(false, 5); - EXPECT_TRUE(!test2); -}
diff --git a/src/base/state_machine_shell.h b/src/base/state_machine_shell.h index 8d3200f..38371d3 100644 --- a/src/base/state_machine_shell.h +++ b/src/base/state_machine_shell.h
@@ -5,547 +5,14 @@ #ifndef BASE_STATE_MACHINE_SHELL_H_ #define BASE_STATE_MACHINE_SHELL_H_ -#include <stdint.h> - -#include <algorithm> -#include <climits> -#include <queue> -#include <string> -#include <vector> - -#include "base/base_export.h" -#include "base/bind.h" -#include "base/callback.h" -#include "base/logging.h" -#include "base/optional.h" +#include "starboard/common/state_machine.h" namespace base { +using ::starboard::StateMachineBase; +using ::starboard::StateMachine; -// An approximate implementation of a run-to-completion (RTC) Hierarchical State -// Machine (HSM), supporting most UML Statechart semantics. -// -// Some good background information on UML Statecharts, mostly written by Miro -// Samek: -// http://en.wikipedia.org/wiki/UML_state_machine -// -// And Miro Samek's 3-part article on practical UML Statecharts: -// http://www.embedded.com/design/prototyping-and-development/4008247/A-crash-course-in-UML-state-machines-Part-1 -// -// This class does not provide any intrinsic support for "orthogonal regions," -// "extended state," or "deferred events." "Guard conditions" are easily -// implemented by the client directly in the event handler. It also minorly -// deviates from the UML Statechart specification by calling transition handlers -// before exiting the current states. This is because this implementation uses a -// simplification which combines the transition handlers and the -// state-event-transition map into a single function (HandleUserStateEvent). -// -// This class is not thread-safe. It is the user's responsibility to synchronize -// calls into the state machine, either with locks or by simply using from a -// single thread. -// -// Terse suggestions for using this class: -// * Use the templated StateMachineShell wrapper class instead of this class -// directly. -// * Define two enums, one for your states, and one for your events. -// * Subclass to define your state machine and event handlers. -// * Avoid directly exposing or passing around state machines (wrap instead). -// Handle() is not a great public interface. -// * Include your state machine in another class as a private by-value member. -// * Synchronize access to the state machine. -// * Prefer writing state machine event handlers over checking if the machine -// IsIn() a particular state. -// * Convert public methods into events, get into the state machine as quickly -// as possible. -// * You only need to define a state when you are going to leave the state -// machine in a particular condition where events can occur. -// * Create a superstate when you have an event you want to handle the same -// way for a collection of states. -// * When managing resources, create a state or superstate that represents the -// acquisition of that resource, and release the resource in the Exit -// handler. -// -// Some Definitions: -// Simple State - A State with no substates. The state machine is always -// left in exactly one Simple State. -// Composite State - A State with at least one substate. -// Guard Condition - An external condition on which an event handler -// branches. -// Run-To-Completion - A property specifying that the state machine handles -// one event at a time, and no events are handled until -// the previous event is done being handled. -// -// See the unittests for this class for a contrived example state machine -// implementation. -class BASE_EXPORT StateMachineBaseShell { - public: - // --- Nested Types and Constants --- - - typedef uint32_t State; - typedef uint32_t Event; - - typedef optional<State> StateN; - typedef optional<Event> EventN; - - // --- Public Methods --- - - // Constructor with name. The name is helpful for debugging. - explicit StateMachineBaseShell(const std::string &name); - virtual ~StateMachineBaseShell() { } - - // Enters the initial state, as specified by |GetUserInitialState()| and - // follows the initial substates down to the first simple (childless) state - // found. Idempotent. Will happen automatically on the first |Handle()| call, - // if not done explicitly. - void Initialize(); - - // Gets the name of this state machine, for logging purposes. - const char *name() const { - return name_.c_str(); - } - - // Gets a version number that increases monotonically with each state - // transition (unless it overflows |uint64_t|). This can be useful for timers - // and asynchronous events that only want to do their action if the state has - // not changed since they were queued. - // - // The state version changes exactly once per transition. In other words, it - // doesn't change for every Enter and Exit for a transition. - uint64_t version() const { - return version_; - } - - // Gets the simplest current state that this state machine is in. To check if - // the state machine is in a particular composite state, use |IsIn()|. Returns - // null if uninitialized. - StateN state() const { - return state_; - } - - // Reports whether the state machine is currently in the given state. A state - // machine is considered to be "in" the current simple state, but also "in" - // all superstates of the current simple state. - bool IsIn(State state) const; - - // Gets a printable string for the given state. - const char *GetStateString(StateN state) const; - - // Gets a printable string for the given event. - const char *GetEventString(EventN event) const; - - // Handles the given event in the context of the state machine's current - // state, executing the appropriate event handlers and performing any - // precipitate state transitions. If called reentrantly, the event will be - // queued until the current event has run to completion. - // - // |data| is a way to pass auxiliary data to the event handler. No retention - // or ref-counting is done on that data, it is simply passed through to the - // event handler. Since |Handle()| will queue the event if (and only if) - // called from an event handler, it is up to the caller to ensure the lifetime - // of whatever is passed in here. - void Handle(Event event, void *data = NULL); - - - protected: - // --- Protected Nested Types --- - - // A type that can be returned from a state-event handler, which will be - // coerced into the appropriate Result structure. - enum HandledState { - // The event handler returns this to say that the handler consume the event, - // but caused no state transition. - kHandled, - - // The event handler returns this to say that the handler did not consume - // the event, and it should bubble up to the parent state, if any. - kNotHandled, - }; - - // Structure that handlers return, allowing them to cause state transitions or - // prevent the event from bubbling. State-event handlers may just return a - // HandledState or a state to transition to, and it will be coerced into this - // structure. - struct Result { - // Default constructor is unhandled. - Result() - : is_transition(false), - is_external(false), - is_handled(false) { } - - // The no-transition constructor. Non-explicit so that the implementor of - // |HandleUserStateEvent()| just needs to return a |HandledState| and it - // does the right thing. - Result(HandledState handled) - : is_transition(false), - is_external(false), - is_handled(handled == kHandled) { } - - // The state transition constructor. This implies that the event was - // handled. Non-explicit so that the implementor of |HandleUserStateEvent()| - // just needs to return a State and it does a non-external transition. - Result(State transition_target, bool external = false) - : target(transition_target), - is_transition(true), - is_external(external), - is_handled(true) { } - - Result &operator=(HandledState rhs) { - target = base::nullopt; - is_transition = false; - is_external = false; - is_handled = (rhs == kHandled); - return *this; - } - - Result &operator=(State transition_target) { - target = transition_target; - is_transition = true; - is_external = false; - is_handled = true; - return *this; - } - - // State to transition to. Only valid if is_transition is true. - StateN target; - - // Whether this result indicates a state transition. - bool is_transition; - - // Whether the specified transition is external. Only meaningful if - // is_transition is true. - // - // For more on state transitions, see: - // http://en.wikipedia.org/wiki/UML_state_machine#Transition_execution_sequence - bool is_external; - - // Whether the event was handled by the handler. If true, consumes the - // event, and prevents bubbling up to superstates. False propagates the - // event to superstates. - bool is_handled; - }; - - - // --- Implementation Interface for Subclasses --- - - // Abstract method for subclasses to define the state hierarchy. It is - // recommended that all user-defined states be descendents of a single "top" - // state. - virtual StateN GetUserParentState(State state) const = 0; - - // Abstract method for subclasses to define the initial substate of their - // states, which is required for all complex states. If a state is a simple - // state (no substates), returns null. - virtual StateN GetUserInitialSubstate(State state) const = 0; - - // Abstract method for subclasses to define the initial (top) state of their - // state machine. This must be a state that has no parent. This state will be - // entered upon calling |Initialize()|. - virtual State GetUserInitialState() const = 0; - - // Optional method for subclasses to define strings for their states, solely - // used for debugging purposes. - virtual const char *GetUserStateString(State state) const { return NULL; } - - // Optional method for subclasses to define strings for their events, solely - // used for debugging purposes. - virtual const char *GetUserEventString(Event event) const { return NULL; } - - // Abstract method for subclasses to define handlers for events in given - // states. This method must return either: - // a) a state to transition to, meaning the event was handled and caused - // a transition - // b) |kHandled| meaning the event was handled but no transition occurred - // c) |kNotHandled|, meaning the event should bubble up to the parent state - // d) an explicit Result structure, mainly for external transitions. - // - // Implementations wishing to catch all unhandled events may do so in their - // top state. - // - // This method is generally implemented as a nested switch statement, with the - // outer switch on |state| and the inner switch on |event|. You may want to - // break this apart into per-state or per-state-event functions for - // readability and maintainability. - virtual Result HandleUserStateEvent(State state, Event event, void *data) = 0; - - // Abstract method for subclasses to define state entry behaviors. - virtual void HandleUserStateEnter(State state) = 0; - - // Abstract method for subclasses to define state exit behaviors. - virtual void HandleUserStateExit(State state) = 0; - - - // --- Helper Methods for Subclasses --- - - // Subclasses can call this method to turn on logging. Logging is opt-in, - // because it can be very verbose, and is likely only useful during - // development of a particular state machine. - void EnableLogging() { - should_log_ = true; - } - - - private: - // --- Private Helper Methods --- - - // Gets the parent state of the given state. - StateN GetParentState(StateN state) const; - - // Gets the initial substate of given state. - StateN GetInitialSubstate(StateN state) const; - - // Handles all queued events until there are no more to run. Event handlers - // may queue more events by calling |Handle()|, and this method will also - // process all precipitate events. - void HandleQueuedEvents(); - - // Workhorse method for handling a single event. Event handling is queued by - // binding the parameters to this method and queueing the resulting Closure. - void HandleOneEvent(Event event, void *data); - - // Gets the path from the Top state to the given |state|, storing it in the - // given |out_path| array, up to |max_depth| entries. If specified, - // |out_depth| will be set to the number of valid states that fit in the given - // array. - void GetPath(State state, size_t max_depth, State *out_path, - size_t *out_depth) const; - - // Transitions between the given source and target states, assuming that the - // source state is in the current state path to the Top state. The source - // state is the state whose handler generated the transition. - // - // See: http://en.wikipedia.org/wiki/UML_state_machine#Transition_execution_sequence - void Transition(Event event, State source, State target, bool is_external); - - // Follows the initial substates from the current state until it reaches a - // simple state. - void FollowInitialSubstates(); - - // Enters the given state. - void EnterState(State state); - - // Exits the current state to its parent. - void ExitCurrentState(); - - - // --- Members --- - - // The name of this state machine, for debugging purposes. - const std::string name_; - - // The current state of this state machine. Null until initialized. - StateN state_; - - // The unique version of this state machine's state, updated on every - // transition. - uint64_t version_; - - // Queue of events to handle once the current event is done being - // handled. Should always be empty unless |is_handling_| is true. - std::queue<Closure> event_queue_; - - // Whether this state machine is actively handling an event. Used to detect - // reentrant calls to |Handle()|. - bool is_handling_; - - // Whether the state machine has been initialized into its initial state - // yet. Used to make |Initialize()| idempotent. - bool is_initialized_; - - // Whether the state machine should DLOG information about state transitions. - bool should_log_; -}; - - -// A convenience template wrapper for StateMachineBaseShell. See the above class -// for complete documentation. Basically, you define your states and events as -// two enums, and then pass them as template args to this template class. Your -// state machine should then subclass this template class. It then does the work -// of casting and converting back and forth from your enums to -// StateMachineBaseShell's numeric State and Event definitions. -// -// All the methods in this class, protected and public, match the description -// and behavioral contracts of the equivalently named method in -// StateMachineBaseShell. template <typename StateEnum, typename EventEnum> -class BASE_EXPORT StateMachineShell { - public: - // --- Nested Types and Constants --- - - typedef optional<StateEnum> StateEnumN; - typedef optional<EventEnum> EventEnumN; - - explicit StateMachineShell(const std::string &name) - : machine_(this, name) { } - virtual ~StateMachineShell() { } - - void Initialize() { - machine_.Initialize(); - } - - const char *name() const { - return machine_.name(); - } - - uint64_t version() const { - return machine_.version(); - } - - StateEnumN state() const { - BaseStateN wrappedState = machine_.state(); - return (wrappedState ? static_cast<StateEnum>(*wrappedState) - : StateEnumN()); - } - - bool IsIn(StateEnum state) const { - return machine_.IsIn(static_cast<BaseState>(state)); - } - - const char *GetStateString(StateEnumN state) const { - return machine_.GetStateString(state ? static_cast<BaseState>(*state) - : BaseStateN()); - } - - const char *GetEventString(EventEnumN event) const { - return machine_.GetEventString(event ? static_cast<BaseEvent>(*event) - : BaseEventN()); - } - - void Handle(EventEnum event, void *data = NULL) { - machine_.Handle(static_cast<BaseEvent>(event), data); - } - - protected: - // See the other HandledState in StateMachineBaseShell. - enum HandledState { - kHandled, - kNotHandled, - }; - - // See the other Result in StateMachineBaseShell. - struct Result { - // Not explicit on purpose, please see the other Result for justification. - Result(HandledState handled) - : target(), - is_transition(false), - is_external(false), - is_handled(handled == kHandled) { } - - // Not explicit on purpose, please see the other Result for justification. - Result(StateEnum transition_target, bool external = false) - : target(transition_target), - is_transition(true), - is_external(external), - is_handled(true) { } - - Result &operator=(HandledState rhs) { - target = base::nullopt; - is_transition = false; - is_external = false; - is_handled = (rhs == kHandled); - return *this; - } - - Result &operator=(StateEnum transition_target) { - target = transition_target; - is_transition = true; - is_external = false; - is_handled = true; - return *this; - } - - StateEnumN target; - bool is_transition; - bool is_external; - bool is_handled; - }; - - virtual StateEnumN GetUserParentState(StateEnum state) const = 0; - virtual StateEnumN GetUserInitialSubstate(StateEnum state) const = 0; - virtual StateEnum GetUserInitialState() const = 0; - virtual const char *GetUserStateString(StateEnum state) const { return NULL; } - virtual const char *GetUserEventString(EventEnum event) const { return NULL; } - virtual Result HandleUserStateEvent(StateEnum state, - EventEnum event, - void *data) = 0; - virtual void HandleUserStateEnter(StateEnum state) = 0; - virtual void HandleUserStateExit(StateEnum state) = 0; - - void EnableLogging() { - machine_.EnableLoggingPublic(); - } - - private: - typedef StateMachineBaseShell::State BaseState; - typedef StateMachineBaseShell::Event BaseEvent; - typedef StateMachineBaseShell::StateN BaseStateN; - typedef StateMachineBaseShell::EventN BaseEventN; - - // Private contained subclass that forwards and adapts all virtual methods - // into this class's equivalent virtual methods. - class WrappedMachine : public StateMachineBaseShell { - public: - WrappedMachine(StateMachineShell<StateEnum, EventEnum> *wrapper, - const std::string &name) - : StateMachineBaseShell(name), - wrapper_(wrapper) { - } - - StateN GetUserParentState(State state) const OVERRIDE { - StateEnumN result = - wrapper_->GetUserParentState(static_cast<StateEnum>(state)); - return (result ? static_cast<State>(*result) : StateN()); - } - - StateN GetUserInitialSubstate(State state) const OVERRIDE { - StateEnumN result = - wrapper_->GetUserInitialSubstate(static_cast<StateEnum>(state)); - return (result ? static_cast<State>(*result) : StateN()); - } - - State GetUserInitialState() const OVERRIDE { - return static_cast<State>(wrapper_->GetUserInitialState()); - } - - const char *GetUserStateString(State state) const OVERRIDE { - return wrapper_->GetUserStateString(static_cast<StateEnum>(state)); - } - - const char *GetUserEventString(Event event) const OVERRIDE { - return wrapper_->GetUserEventString(static_cast<EventEnum>(event)); - } - - Result HandleUserStateEvent(State state, Event event, void *data) OVERRIDE { - typename StateMachineShell<StateEnum, EventEnum>::Result result = - wrapper_->HandleUserStateEvent(static_cast<StateEnum>(state), - static_cast<EventEnum>(event), - data); - if (result.is_transition) { - return Result(static_cast<State>(*result.target), - result.is_external); - } - - return result.is_handled ? kHandled : kNotHandled; - } - - void HandleUserStateEnter(State state) OVERRIDE { - wrapper_->HandleUserStateEnter(static_cast<StateEnum>(state)); - } - - void HandleUserStateExit(State state) OVERRIDE { - wrapper_->HandleUserStateExit(static_cast<StateEnum>(state)); - } - - // A public exposure of EnableLogging so the wrapper can access it. Since - // this class is private to the wrapper, it is the only one who can see it. - void EnableLoggingPublic() { - EnableLogging(); - } - - private: - StateMachineShell<StateEnum, EventEnum> *wrapper_; - }; - - WrappedMachine machine_; -}; +using StateMachineShell = StateMachine<StateEnum, EventEnum>; } // namespace base
diff --git a/src/build/common.gypi b/src/build/common.gypi index 901b1eb..7078e81 100644 --- a/src/build/common.gypi +++ b/src/build/common.gypi
@@ -2,6 +2,12 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +##################################################################### +# If you modify this file, PLEASE REMEMBER TO UPDATE +# //cobalt/build/config/base.gni or //starboard/build/config/base.gni +# AS WELL +##################################################################### + # IMPORTANT: # Please don't directly include this file if you are building via gyp_cobalt, # since gyp_cobalt is automatically forcing its inclusion. @@ -38,12 +44,6 @@ 'target_arch%': '<(target_arch)', 'android_build_type%': '<(android_build_type)', - # Set to 1 to enable dcheck in release without having to use the flag. - 'dcheck_always_on%': 0, - - # Python version. - 'python_ver%': '2.6', - # Set ARM-v7 compilation flags 'armv7%': 0, @@ -74,24 +74,10 @@ # See http://clang.llvm.org/docs/ThreadSanitizer.html 'tsan%': 0, - # Use a modified version of Clang to intercept allocated types and sizes - # for allocated objects. clang_type_profiler=1 implies clang=1. - # See http://dev.chromium.org/developers/deep-memory-profiler/cpp-object-type-identifier - # TODO(dmikurube): Support mac. See http://crbug.com/123758#c11 - 'clang_type_profiler%': 0, - - # Set to true to instrument the code with function call logger. - # See src/third_party/cygprofile/cyg-profile.cc for details. - 'order_profiling%': 0, - # Set this to true when building with Clang. # See http://code.google.com/p/chromium/wiki/Clang for details. 'clang%': 0, - # Set to "tsan", "memcheck", or "drmemory" to configure the build to work - # with one of those tools. - 'build_for_tool%': '', - 'os_posix%': 0, 'os_bsd%': 0, }, @@ -107,16 +93,12 @@ 'library%': 'static_library', 'os_bsd%': '<(os_bsd)', 'os_posix%': '<(os_posix)', - 'dcheck_always_on%': '<(dcheck_always_on)', - 'python_ver%': '<(python_ver)', 'armv7%': '<(armv7)', 'arm_neon%': '<(arm_neon)', 'sysroot%': '<(sysroot)', 'component%': '<(component)', 'asan%': '<(asan)', 'tsan%': '<(tsan)', - 'clang_type_profiler%': '<(clang_type_profiler)', - 'order_profiling%': '<(order_profiling)', 'use_system_libjpeg%': '<(use_system_libjpeg)', 'android_build_type%': '<(android_build_type)', @@ -143,10 +125,6 @@ 'clang_load%': '', 'clang_add_plugin%': '', - # Enable sampling based profiler. - # See http://google-perftools.googlecode.com/svn/trunk/doc/cpuprofile.html - 'profiling%': '0', - # Set Thumb compilation flags. 'arm_thumb%': 0, @@ -163,8 +141,6 @@ # whether warnings are treated as errors. 'chromium_code%': 0, - 'release_valgrind_build%': 0, - # TODO(thakis): Make this a blacklist instead, http://crbug.com/101600 'enable_wexit_time_destructors%': 0, @@ -241,59 +217,6 @@ ['tsan==1', { 'clang%': 1, }], - - # On valgrind bots, override the optimizer settings so we don't inline too - # much and make the stacks harder to figure out. - # - # TODO(rnk): Kill off variables that no one else uses and just implement - # them under a build_for_tool== condition. - ['build_for_tool=="memcheck" or build_for_tool=="tsan"', { - # gcc flags - 'mac_debug_optimization': '1', - 'mac_release_optimization': '1', - 'release_optimize': '1', - 'no_gc_sections': 1, - 'debug_extra_cflags': '-g -fno-inline -fno-omit-frame-pointer ' - '-fno-builtin -fno-optimize-sibling-calls', - 'release_extra_cflags': '-g -fno-inline -fno-omit-frame-pointer ' - '-fno-builtin -fno-optimize-sibling-calls', - - # MSVS flags for TSan on Pin and Windows. - 'win_debug_RuntimeChecks': '0', - 'win_debug_disable_iterator_debugging': '1', - 'win_debug_Optimization': '1', - 'win_debug_InlineFunctionExpansion': '0', - 'win_release_InlineFunctionExpansion': '0', - 'win_release_OmitFramePointers': '0', - - 'linux_use_tcmalloc': 1, - 'release_valgrind_build': 1, - 'werror': '', - 'component': 'static_library', - 'use_system_zlib': 0, - }], - - # Build tweaks for DrMemory. - # TODO(rnk): Combine with tsan config to share the builder. - # http://crbug.com/108155 - ['build_for_tool=="drmemory"', { - # These runtime checks force initialization of stack vars which blocks - # DrMemory's uninit detection. - 'win_debug_RuntimeChecks': '0', - # Iterator debugging is slow. - 'win_debug_disable_iterator_debugging': '1', - # Try to disable optimizations that mess up stacks in a release build. - # DrM-i#1054 (http://code.google.com/p/drmemory/issues/detail?id=1054) - # /O2 and /Ob0 (disable inline) cannot be used together because of a - # compiler bug, so we use /Ob1 instead. - 'win_release_InlineFunctionExpansion': '1', - 'win_release_OmitFramePointers': '0', - # Ditto for debug, to support bumping win_debug_Optimization. - 'win_debug_InlineFunctionExpansion': 0, - 'win_debug_OmitFramePointers': 0, - # Keep the code under #ifndef NVALGRIND. - 'release_valgrind_build': 1, - }], ], }, 'target_defaults': { @@ -336,8 +259,6 @@ 'release_extra_cflags%': '', 'debug_extra_cflags%': '', - 'release_valgrind_build%': '<(release_valgrind_build)', - # the non-qualified versions are widely assumed to be *nix-only 'win_release_extra_cflags%': '', 'win_debug_extra_cflags%': '', @@ -379,12 +300,6 @@ ['component=="shared_library"', { 'defines': ['COMPONENT_BUILD'], }], - ['profiling==1', { - 'defines': ['ENABLE_PROFILING=1'], - }], - ['dcheck_always_on!=0', { - 'defines': ['DCHECK_ALWAYS_ON=1'], - }], # dcheck_always_on!=0 ], # conditions for 'target_defaults' 'target_conditions': [ ['enable_wexit_time_destructors==1', {
diff --git a/src/cobalt/CHANGELOG.md b/src/cobalt/CHANGELOG.md index 2abcfc8..9d943ae 100644 --- a/src/cobalt/CHANGELOG.md +++ b/src/cobalt/CHANGELOG.md
@@ -40,6 +40,14 @@ `kSbInputEventTypeMove` events. These will be passed into the WebModule to be processed by JavaScript. + - **Custom Web Extension Support** + + Cobalt now allows platforms to inject a custom namespace property into + the JavaScript global `window` object visible to the web apps. This allows + for custom web apps to interface with custom C++ code written outside of + Cobalt common code. See + [doc/webapi_extension.md](doc/webapi_extension.md) for more details. + - **Playback Rate** Cobalt now supports adjusting the video playback rate.
diff --git a/src/cobalt/accessibility/screen_reader_tests.cc b/src/cobalt/accessibility/screen_reader_tests.cc index 2814b21..9adc74d 100644 --- a/src/cobalt/accessibility/screen_reader_tests.cc +++ b/src/cobalt/accessibility/screen_reader_tests.cc
@@ -104,7 +104,9 @@ scoped_refptr<script::Wrappable> CreateWindowAttribute( const scoped_refptr<dom::Window>& window, - dom::MutationObserverTaskManager* mutation_observer_task_manager) { + dom::MutationObserverTaskManager* mutation_observer_task_manager, + script::GlobalEnvironment* global_environment) { + UNREFERENCED_PARAMETER(global_environment); screen_reader_.reset(new accessibility::ScreenReader( window->document(), &tts_engine_, mutation_observer_task_manager)); screen_reader_->set_enabled(GetParam().screen_reader_enabled);
diff --git a/src/cobalt/base/base.gyp b/src/cobalt/base/base.gyp index f4f9f34..ccbcc85 100644 --- a/src/cobalt/base/base.gyp +++ b/src/cobalt/base/base.gyp
@@ -41,6 +41,8 @@ 'event.h', 'event_dispatcher.cc', 'event_dispatcher.h', + 'get_application_key.cc', + 'get_application_key.h', 'init_cobalt.cc', 'init_cobalt.h', 'language.cc',
diff --git a/src/cobalt/base/get_application_key.cc b/src/cobalt/base/get_application_key.cc new file mode 100644 index 0000000..15e9175 --- /dev/null +++ b/src/cobalt/base/get_application_key.cc
@@ -0,0 +1,60 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/base/get_application_key.h" + +#include <string> + +#include "base/base64.h" +#include "base/logging.h" +#include "base/string_piece.h" +#include "base/string_util.h" + +namespace base { + +namespace { +// The Application Origin is like the origin, but it supports nonstandard +// schemes, and preserves the path. +GURL GetApplicationOrigin(const GURL& url) { + if (!url.is_valid()) { + return GURL(); + } + + url_canon::Replacements<char> replacements; + replacements.ClearUsername(); + replacements.ClearPassword(); + replacements.ClearQuery(); + replacements.ClearRef(); + + return url.ReplaceComponents(replacements); +} +} // namespace + +optional<std::string> GetApplicationKey(const GURL& url) { + if (!url.is_valid()) { + return base::nullopt; + } + + std::string raw_url = GetApplicationOrigin(url).spec(); + std::string encoded_url; + base::Base64Encode(raw_url, &encoded_url); + + // Make web-safe. + ReplaceChars(encoded_url, "/", "_", &encoded_url); + ReplaceChars(encoded_url, "+", "-", &encoded_url); + + return encoded_url; +} + +} // namespace base
diff --git a/src/cobalt/base/get_application_key.h b/src/cobalt/base/get_application_key.h new file mode 100644 index 0000000..ab9a995 --- /dev/null +++ b/src/cobalt/base/get_application_key.h
@@ -0,0 +1,31 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef COBALT_BASE_GET_APPLICATION_KEY_H_ +#define COBALT_BASE_GET_APPLICATION_KEY_H_ + +#include <string> + +#include "base/optional.h" +#include "googleurl/src/gurl.h" + +namespace base { + +// Returns a filesystem-safe key that corresponds to the application whose start +// URL is |url|. Returns nullopt if |url| is not a valid URL. +optional<std::string> GetApplicationKey(const GURL& url); + +} // namespace base + +#endif // COBALT_BASE_GET_APPLICATION_KEY_H_
diff --git a/src/cobalt/base/tokens.h b/src/cobalt/base/tokens.h index 35d8e57..5c826de 100644 --- a/src/cobalt/base/tokens.h +++ b/src/cobalt/base/tokens.h
@@ -64,6 +64,7 @@ MacroOpWithNameOnly(hashchange) \ MacroOpWithNameOnly(keydown) \ MacroOpWithNameOnly(keypress) \ + MacroOpWithNameOnly(keystatuseschange) \ MacroOpWithNameOnly(keyup) \ MacroOpWithNameOnly(load) \ MacroOpWithNameOnly(loadeddata) \
diff --git a/src/cobalt/bindings/bindings.gypi b/src/cobalt/bindings/bindings.gypi index 29c4d39..9260d08 100644 --- a/src/cobalt/bindings/bindings.gypi +++ b/src/cobalt/bindings/bindings.gypi
@@ -553,6 +553,7 @@ 'inputs': [ '<@(jinja_module_files)', '<(DEPTH)/cobalt/bindings/code_generator_cobalt.py', + '<(DEPTH)/cobalt/bindings/path_generator.py', '<@(code_generator_template_files)', ], 'outputs': [
diff --git a/src/cobalt/bindings/code_generator_cobalt.py b/src/cobalt/bindings/code_generator_cobalt.py index 7227af8..c9dd3ac 100644 --- a/src/cobalt/bindings/code_generator_cobalt.py +++ b/src/cobalt/bindings/code_generator_cobalt.py
@@ -483,8 +483,7 @@ referenced_interface_names.update(IdlType.callback_interfaces) else: # Build the set of referenced interfaces from this interface's members. - referenced_interface_names = set() - referenced_interface_names.update( + referenced_interface_names = set( get_interface_type_names_from_typed_objects(self.info_provider, interface.attributes)) referenced_interface_names.update(
diff --git a/src/cobalt/bindings/contexts.py b/src/cobalt/bindings/contexts.py index c67a214..702090e 100644 --- a/src/cobalt/bindings/contexts.py +++ b/src/cobalt/bindings/contexts.py
@@ -56,6 +56,15 @@ return str(idl_literal) +def get_dictionary_default_value(idl_type, idl_literal, name): + """Mapping to cobalt value filtering for dictionary acceptable values.""" + if is_any_type(idl_type) and not idl_literal.is_null: + raise ValueError('Unsupported default value in dictionary: ' + '\'%s %s = %s\'. Only null default is supported.' % + (idl_type, name, idl_literal)) + return idl_literal_to_cobalt_literal(idl_type, idl_literal) + + def idl_primitive_type_to_cobalt(idl_type): """Map IDL primitive type to C++ type.""" type_map = { @@ -198,7 +207,7 @@ not idl_type.is_callback_interface), 'Callback types not supported.' element_cobalt_type = self.idl_type_to_cobalt_type( self.resolve_typedef(element_idl_type)) - return 'script::Sequence< %s >' % element_cobalt_type + return '::cobalt::script::Sequence< %s >' % element_cobalt_type def idl_union_type_to_cobalt(self, idl_type): """Map IDL union type to C++ union type implementation.""" @@ -216,8 +225,8 @@ flattened_types.append(member) cobalt_types = [self.idl_type_to_cobalt_type(t) for t in flattened_types] - return 'script::UnionType%d<%s >' % (len(cobalt_types), - ', '.join(cobalt_types)) + return '::cobalt::script::UnionType%d<%s >' % (len(cobalt_types), + ', '.join(cobalt_types)) def idl_type_to_cobalt_type(self, idl_type): """Map IDL type to C++ type.""" @@ -228,8 +237,8 @@ elif idl_type.is_string_type: cobalt_type = 'std::string' elif idl_type.is_callback_interface: - cobalt_type = 'CallbackInterfaceTraits<%s >' % get_interface_name( - idl_type) + cobalt_type = '::cobalt::script::CallbackInterfaceTraits<%s >' % ( + get_interface_name(idl_type)) elif idl_type.is_interface_type: cobalt_type = 'scoped_refptr<%s>' % get_interface_name(idl_type) elif idl_type.is_union_type: @@ -241,13 +250,13 @@ elif idl_type.name == 'void': cobalt_type = 'void' elif is_object_type(idl_type): - cobalt_type = 'OpaqueHandle' + cobalt_type = '::cobalt::script::OpaqueHandle' elif is_any_type(idl_type): - cobalt_type = 'ValueHandle' + cobalt_type = '::cobalt::script::ValueHandle' elif idl_type.is_dictionary: cobalt_type = get_interface_name(idl_type) elif is_promise_type(idl_type): - cobalt_type = 'NativePromise' + cobalt_type = '::cobalt::script::NativePromise' assert cobalt_type, 'Unsupported idl_type %s' % idl_type @@ -275,6 +284,8 @@ if (idl_type.is_callback_function or idl_type.is_object_type or idl_type.is_callback_interface): return base_type + '*' + if is_any_type(idl_type): + return 'const ::cobalt::script::ScriptValue<%s>*' % base_type if idl_type.is_string_type or idl_type.is_interface_type: return 'const %s&' % base_type return base_type @@ -600,6 +611,8 @@ dictionary_member.idl_type, 'name': convert_to_cobalt_name(dictionary_member.name), + 'is_script_value': + is_any_type(dictionary_member.idl_type), 'idl_name': dictionary_member.name, 'type': @@ -611,7 +624,8 @@ self.resolve_typedef(dictionary_member.idl_type), dictionary_member.extended_attributes), 'default_value': - idl_literal_to_cobalt_literal(dictionary_member.idl_type, - dictionary_member.default_value) + get_dictionary_default_value(dictionary_member.idl_type, + dictionary_member.default_value, + dictionary_member.name) if dictionary_member.default_value else None, }
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/dictionary_with_dictionary_member.h b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/dictionary_with_dictionary_member.h index eee757a..02dbce6 100644 --- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/dictionary_with_dictionary_member.h +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/dictionary_with_dictionary_member.h
@@ -25,7 +25,9 @@ #include <string> #include "base/optional.h" +#include "cobalt/script/script_value.h" #include "cobalt/script/sequence.h" +#include "cobalt/script/value_handle.h" #include "cobalt/bindings/testing/test_dictionary.h" using cobalt::bindings::testing::TestDictionary; @@ -41,6 +43,17 @@ nested_dictionary_ = TestDictionary(); } + DictionaryWithDictionaryMember(const DictionaryWithDictionaryMember& other) { + has_nested_dictionary_ = other.has_nested_dictionary_; + nested_dictionary_ = other.nested_dictionary_; + } + + DictionaryWithDictionaryMember& operator=(const DictionaryWithDictionaryMember& other) { + has_nested_dictionary_ = other.has_nested_dictionary_; + nested_dictionary_ = other.nested_dictionary_; + return *this; + } + bool has_nested_dictionary() const { return has_nested_dictionary_; }
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc index 09b1d08..045f8e2 100644 --- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc
@@ -265,7 +265,7 @@ WrapperPrivate::GetFromObject(context, object); CallbackInterfaceInterface* impl = wrapper_private->wrappable<CallbackInterfaceInterface>().get(); - TypeTraits<CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType value; + TypeTraits<::cobalt::script::CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType value; FromJSValue(context, vp, (kConversionFlagNullable), &exception_state, &value); if (exception_state.is_exception_set()) { @@ -323,7 +323,7 @@ return false; } // Non-optional arguments - TypeTraits<CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType callback_interface; + TypeTraits<::cobalt::script::CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType callback_interface; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0(
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc index 1b341be..e40be08 100644 --- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc
@@ -265,7 +265,7 @@ WrapperPrivate::GetFromObject(context, object); DictionaryInterface* impl = wrapper_private->wrappable<DictionaryInterface>().get(); - TypeTraits<script::Sequence< TestDictionary > >::ConversionType value; + TypeTraits<::cobalt::script::Sequence< TestDictionary > >::ConversionType value; FromJSValue(context, vp, kNoConversionFlags, &exception_state, &value); if (exception_state.is_exception_set()) {
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_interface_with_any.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_interface_with_any.cc index 07aeddb..e5b69e4 100644 --- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_interface_with_any.cc +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_interface_with_any.cc
@@ -291,7 +291,7 @@ return false; } // Non-optional arguments - TypeTraits<ValueHandle >::ConversionType value; + TypeTraits<::cobalt::script::ValueHandle >::ConversionType value; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0(
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.cc new file mode 100644 index 0000000..3fce4bc --- /dev/null +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.cc
@@ -0,0 +1,642 @@ +// Copyright 2017 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. + +// clang-format off + +// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY! +// Auto-generated from template: bindings/mozjs/templates/interface.cc.template + +#include "cobalt/bindings/testing/mozjs_interface_with_any_dictionary.h" + +#include "base/debug/trace_event.h" +#include "cobalt/base/polymorphic_downcast.h" +#include "cobalt/script/global_environment.h" +#include "cobalt/script/opaque_handle.h" +#include "cobalt/script/script_value.h" + +#include "mozjs_gen_type_conversion.h" + +#include "base/lazy_instance.h" +#include "cobalt/script/exception_state.h" +#include "cobalt/script/mozjs/callback_function_conversion.h" +#include "cobalt/script/mozjs/conversion_helpers.h" +#include "cobalt/script/mozjs/mozjs_callback_function.h" +#include "cobalt/script/mozjs/mozjs_exception_state.h" +#include "cobalt/script/mozjs/mozjs_global_environment.h" +#include "cobalt/script/mozjs/mozjs_object_handle.h" +#include "cobalt/script/mozjs/mozjs_property_enumerator.h" +#include "cobalt/script/mozjs/mozjs_user_object_holder.h" +#include "cobalt/script/mozjs/mozjs_value_handle.h" +#include "cobalt/script/mozjs/native_promise.h" +#include "cobalt/script/mozjs/proxy_handler.h" +#include "cobalt/script/mozjs/type_traits.h" +#include "cobalt/script/mozjs/wrapper_factory.h" +#include "cobalt/script/mozjs/wrapper_private.h" +#include "cobalt/script/property_enumerator.h" +#include "cobalt/script/sequence.h" +#include "third_party/mozjs/js/src/jsapi.h" +#include "third_party/mozjs/js/src/jsfriendapi.h" + +namespace { +using cobalt::bindings::testing::InterfaceWithAnyDictionary; +using cobalt::bindings::testing::MozjsInterfaceWithAnyDictionary; +using cobalt::script::CallbackInterfaceTraits; +using cobalt::script::GlobalEnvironment; +using cobalt::script::OpaqueHandle; +using cobalt::script::OpaqueHandleHolder; +using cobalt::script::ScriptValue; +using cobalt::script::ValueHandle; +using cobalt::script::Wrappable; + +using cobalt::script::CallbackFunction; +using cobalt::script::CallbackInterfaceTraits; +using cobalt::script::ExceptionState; +using cobalt::script::Wrappable; +using cobalt::script::mozjs::FromJSValue; +using cobalt::script::mozjs::InterfaceData; +using cobalt::script::mozjs::MozjsCallbackFunction; +using cobalt::script::mozjs::MozjsExceptionState; +using cobalt::script::mozjs::MozjsGlobalEnvironment; +using cobalt::script::mozjs::MozjsPropertyEnumerator; +using cobalt::script::mozjs::MozjsUserObjectHolder; +using cobalt::script::mozjs::ProxyHandler; +using cobalt::script::mozjs::ToJSValue; +using cobalt::script::mozjs::TypeTraits; +using cobalt::script::mozjs::WrapperFactory; +using cobalt::script::mozjs::WrapperPrivate; +using cobalt::script::mozjs::kConversionFlagClamped; +using cobalt::script::mozjs::kConversionFlagNullable; +using cobalt::script::mozjs::kConversionFlagRestricted; +using cobalt::script::mozjs::kConversionFlagTreatNullAsEmptyString; +using cobalt::script::mozjs::kConversionFlagTreatUndefinedAsEmptyString; +using cobalt::script::mozjs::kNoConversionFlags; +} // namespace + +namespace cobalt { +namespace bindings { +namespace testing { + +namespace { + +class MozjsInterfaceWithAnyDictionaryHandler : public ProxyHandler { + public: + MozjsInterfaceWithAnyDictionaryHandler() + : ProxyHandler(indexed_property_hooks, named_property_hooks) {} + + private: + static NamedPropertyHooks named_property_hooks; + static IndexedPropertyHooks indexed_property_hooks; +}; + +ProxyHandler::NamedPropertyHooks +MozjsInterfaceWithAnyDictionaryHandler::named_property_hooks = { + NULL, + NULL, + NULL, + NULL, + NULL, +}; +ProxyHandler::IndexedPropertyHooks +MozjsInterfaceWithAnyDictionaryHandler::indexed_property_hooks = { + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +static base::LazyInstance<MozjsInterfaceWithAnyDictionaryHandler> + proxy_handler; + +JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp); +JSBool HasInstance(JSContext *context, JS::HandleObject type, + JS::MutableHandleValue vp, JSBool *success) { + JS::RootedObject global_object( + context, JS_GetGlobalForObject(context, type)); + DCHECK(global_object); + + JS::RootedObject prototype( + context, MozjsInterfaceWithAnyDictionary::GetPrototype(context, global_object)); + + // |IsDelegate| walks the prototype chain of an object returning true if + // .prototype is found. + bool is_delegate; + if (!IsDelegate(context, prototype, vp, &is_delegate)) { + *success = false; + return false; + } + + *success = is_delegate; + return true; +} + +InterfaceData* CreateCachedInterfaceData() { + InterfaceData* interface_data = new InterfaceData(); + memset(&interface_data->instance_class_definition, 0, + sizeof(interface_data->instance_class_definition)); + memset(&interface_data->prototype_class_definition, 0, + sizeof(interface_data->prototype_class_definition)); + memset(&interface_data->interface_object_class_definition, 0, + sizeof(interface_data->interface_object_class_definition)); + + JSClass* instance_class = &interface_data->instance_class_definition; + const int kGlobalFlags = 0; + instance_class->name = "InterfaceWithAnyDictionary"; + instance_class->flags = kGlobalFlags | JSCLASS_HAS_PRIVATE; + instance_class->addProperty = JS_PropertyStub; + instance_class->delProperty = JS_DeletePropertyStub; + instance_class->getProperty = JS_PropertyStub; + instance_class->setProperty = JS_StrictPropertyStub; + instance_class->enumerate = JS_EnumerateStub; + instance_class->resolve = JS_ResolveStub; + instance_class->convert = JS_ConvertStub; + // Function to be called before on object of this class is garbage collected. + instance_class->finalize = &WrapperPrivate::Finalizer; + // Called to trace objects that can be referenced from this object. + instance_class->trace = &WrapperPrivate::Trace; + + JSClass* prototype_class = &interface_data->prototype_class_definition; + prototype_class->name = "InterfaceWithAnyDictionaryPrototype"; + prototype_class->flags = 0; + prototype_class->addProperty = JS_PropertyStub; + prototype_class->delProperty = JS_DeletePropertyStub; + prototype_class->getProperty = JS_PropertyStub; + prototype_class->setProperty = JS_StrictPropertyStub; + prototype_class->enumerate = JS_EnumerateStub; + prototype_class->resolve = JS_ResolveStub; + prototype_class->convert = JS_ConvertStub; + + JSClass* interface_object_class = + &interface_data->interface_object_class_definition; + interface_object_class->name = "InterfaceWithAnyDictionaryConstructor"; + interface_object_class->flags = 0; + interface_object_class->addProperty = JS_PropertyStub; + interface_object_class->delProperty = JS_DeletePropertyStub; + interface_object_class->getProperty = JS_PropertyStub; + interface_object_class->setProperty = JS_StrictPropertyStub; + interface_object_class->enumerate = JS_EnumerateStub; + interface_object_class->resolve = JS_ResolveStub; + interface_object_class->convert = JS_ConvertStub; + interface_object_class->hasInstance = &HasInstance; + interface_object_class->construct = Constructor; + return interface_data; +} + +JSBool fcn_getAny( + JSContext* context, uint32_t argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + // Compute the 'this' value. + JS::RootedValue this_value(context, JS_ComputeThis(context, vp)); + // 'this' should be an object. + JS::RootedObject object(context); + if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) { + return false; + } + if (!JS_ValueToObject(context, this_value, object.address())) { + NOTREACHED(); + return false; + } + const JSClass* proto_class = + MozjsInterfaceWithAnyDictionary::PrototypeClass(context); + if (proto_class == JS_GetClass(object)) { + // Simply returns true if the object is this class's prototype object. + // There is no need to return any value due to the object is not a platform + // object. The execution reaches here when Object.getOwnPropertyDescriptor + // gets called on native object prototypes. + return true; + } + + MozjsGlobalEnvironment* global_environment = + static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); + WrapperFactory* wrapper_factory = global_environment->wrapper_factory(); + if (!wrapper_factory->DoesObjectImplementInterface( + object, base::GetTypeId<InterfaceWithAnyDictionary>())) { + MozjsExceptionState exception(context); + exception.SetSimpleException(script::kDoesNotImplementInterface); + return false; + } + MozjsExceptionState exception_state(context); + JS::RootedValue result_value(context); + + WrapperPrivate* wrapper_private = + WrapperPrivate::GetFromObject(context, object); + InterfaceWithAnyDictionary* impl = + wrapper_private->wrappable<InterfaceWithAnyDictionary>().get(); + + if (!exception_state.is_exception_set()) { + ToJSValue(context, + impl->GetAny(), + &result_value); + } + if (!exception_state.is_exception_set()) { + args.rval().set(result_value); + } + return !exception_state.is_exception_set(); +} + +JSBool fcn_hasAny( + JSContext* context, uint32_t argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + // Compute the 'this' value. + JS::RootedValue this_value(context, JS_ComputeThis(context, vp)); + // 'this' should be an object. + JS::RootedObject object(context); + if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) { + return false; + } + if (!JS_ValueToObject(context, this_value, object.address())) { + NOTREACHED(); + return false; + } + const JSClass* proto_class = + MozjsInterfaceWithAnyDictionary::PrototypeClass(context); + if (proto_class == JS_GetClass(object)) { + // Simply returns true if the object is this class's prototype object. + // There is no need to return any value due to the object is not a platform + // object. The execution reaches here when Object.getOwnPropertyDescriptor + // gets called on native object prototypes. + return true; + } + + MozjsGlobalEnvironment* global_environment = + static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); + WrapperFactory* wrapper_factory = global_environment->wrapper_factory(); + if (!wrapper_factory->DoesObjectImplementInterface( + object, base::GetTypeId<InterfaceWithAnyDictionary>())) { + MozjsExceptionState exception(context); + exception.SetSimpleException(script::kDoesNotImplementInterface); + return false; + } + MozjsExceptionState exception_state(context); + JS::RootedValue result_value(context); + + WrapperPrivate* wrapper_private = + WrapperPrivate::GetFromObject(context, object); + InterfaceWithAnyDictionary* impl = + wrapper_private->wrappable<InterfaceWithAnyDictionary>().get(); + + if (!exception_state.is_exception_set()) { + ToJSValue(context, + impl->HasAny(), + &result_value); + } + if (!exception_state.is_exception_set()) { + args.rval().set(result_value); + } + return !exception_state.is_exception_set(); +} + +JSBool fcn_hasAnyDefault( + JSContext* context, uint32_t argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + // Compute the 'this' value. + JS::RootedValue this_value(context, JS_ComputeThis(context, vp)); + // 'this' should be an object. + JS::RootedObject object(context); + if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) { + return false; + } + if (!JS_ValueToObject(context, this_value, object.address())) { + NOTREACHED(); + return false; + } + const JSClass* proto_class = + MozjsInterfaceWithAnyDictionary::PrototypeClass(context); + if (proto_class == JS_GetClass(object)) { + // Simply returns true if the object is this class's prototype object. + // There is no need to return any value due to the object is not a platform + // object. The execution reaches here when Object.getOwnPropertyDescriptor + // gets called on native object prototypes. + return true; + } + + MozjsGlobalEnvironment* global_environment = + static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); + WrapperFactory* wrapper_factory = global_environment->wrapper_factory(); + if (!wrapper_factory->DoesObjectImplementInterface( + object, base::GetTypeId<InterfaceWithAnyDictionary>())) { + MozjsExceptionState exception(context); + exception.SetSimpleException(script::kDoesNotImplementInterface); + return false; + } + MozjsExceptionState exception_state(context); + JS::RootedValue result_value(context); + + WrapperPrivate* wrapper_private = + WrapperPrivate::GetFromObject(context, object); + InterfaceWithAnyDictionary* impl = + wrapper_private->wrappable<InterfaceWithAnyDictionary>().get(); + + if (!exception_state.is_exception_set()) { + ToJSValue(context, + impl->HasAnyDefault(), + &result_value); + } + if (!exception_state.is_exception_set()) { + args.rval().set(result_value); + } + return !exception_state.is_exception_set(); +} + +JSBool fcn_setAny( + JSContext* context, uint32_t argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + // Compute the 'this' value. + JS::RootedValue this_value(context, JS_ComputeThis(context, vp)); + // 'this' should be an object. + JS::RootedObject object(context); + if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) { + return false; + } + if (!JS_ValueToObject(context, this_value, object.address())) { + NOTREACHED(); + return false; + } + const JSClass* proto_class = + MozjsInterfaceWithAnyDictionary::PrototypeClass(context); + if (proto_class == JS_GetClass(object)) { + // Simply returns true if the object is this class's prototype object. + // There is no need to return any value due to the object is not a platform + // object. The execution reaches here when Object.getOwnPropertyDescriptor + // gets called on native object prototypes. + return true; + } + + MozjsGlobalEnvironment* global_environment = + static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); + WrapperFactory* wrapper_factory = global_environment->wrapper_factory(); + if (!wrapper_factory->DoesObjectImplementInterface( + object, base::GetTypeId<InterfaceWithAnyDictionary>())) { + MozjsExceptionState exception(context); + exception.SetSimpleException(script::kDoesNotImplementInterface); + return false; + } + MozjsExceptionState exception_state(context); + JS::RootedValue result_value(context); + + WrapperPrivate* wrapper_private = + WrapperPrivate::GetFromObject(context, object); + InterfaceWithAnyDictionary* impl = + wrapper_private->wrappable<InterfaceWithAnyDictionary>().get(); + const size_t kMinArguments = 1; + if (args.length() < kMinArguments) { + exception_state.SetSimpleException(script::kInvalidNumberOfArguments); + return false; + } + // Non-optional arguments + TypeTraits<::cobalt::script::ValueHandle >::ConversionType value; + + DCHECK_LT(0, args.length()); + JS::RootedValue non_optional_value0( + context, args[0]); + FromJSValue(context, + non_optional_value0, + kNoConversionFlags, + &exception_state, &value); + if (exception_state.is_exception_set()) { + return false; + } + + impl->SetAny(value); + result_value.set(JS::UndefinedHandleValue); + return !exception_state.is_exception_set(); +} + + +const JSPropertySpec prototype_properties[] = { + JS_PS_END +}; + +const JSFunctionSpec prototype_functions[] = { + { + "getAny", + JSOP_WRAPPER(&fcn_getAny), + 0, + JSPROP_ENUMERATE, + NULL, + }, + { + "hasAny", + JSOP_WRAPPER(&fcn_hasAny), + 0, + JSPROP_ENUMERATE, + NULL, + }, + { + "hasAnyDefault", + JSOP_WRAPPER(&fcn_hasAnyDefault), + 0, + JSPROP_ENUMERATE, + NULL, + }, + { + "setAny", + JSOP_WRAPPER(&fcn_setAny), + 1, + JSPROP_ENUMERATE, + NULL, + }, + JS_FS_END +}; + +const JSPropertySpec interface_object_properties[] = { + JS_PS_END +}; + +const JSFunctionSpec interface_object_functions[] = { + JS_FS_END +}; + +const JSPropertySpec own_properties[] = { + JS_PS_END +}; + +void InitializePrototypeAndInterfaceObject( + InterfaceData* interface_data, JSContext* context, + JS::HandleObject global_object) { + DCHECK(!interface_data->prototype); + DCHECK(!interface_data->interface_object); + DCHECK(JS_IsGlobalObject(global_object)); + + JS::RootedObject parent_prototype( + context, JS_GetObjectPrototype(context, global_object)); + DCHECK(parent_prototype); + + // Create the Prototype object. + interface_data->prototype = JS_NewObjectWithGivenProto( + context, &interface_data->prototype_class_definition, parent_prototype, + NULL); + bool success = JS_DefineProperties( + context, interface_data->prototype, prototype_properties); + DCHECK(success); + success = JS_DefineFunctions( + context, interface_data->prototype, prototype_functions); + DCHECK(success); + + JS::RootedObject function_prototype( + context, JS_GetFunctionPrototype(context, global_object)); + DCHECK(function_prototype); + // Create the Interface object. + interface_data->interface_object = JS_NewObjectWithGivenProto( + context, &interface_data->interface_object_class_definition, + function_prototype, NULL); + + // Add the InterfaceObject.name property. + JS::RootedObject rooted_interface_object( + context, interface_data->interface_object); + JS::RootedValue name_value(context); + const char name[] = + "InterfaceWithAnyDictionary"; + name_value.setString(JS_NewStringCopyZ(context, name)); + success = + JS_DefineProperty(context, rooted_interface_object, "name", name_value, + JS_PropertyStub, JS_StrictPropertyStub, + JSPROP_READONLY); + DCHECK(success); + + // Add the InterfaceObject.length property. It is set to the length of the + // shortest argument list of all overload constructors. + JS::RootedValue length_value(context); + length_value.setInt32(0); + success = + JS_DefineProperty(context, rooted_interface_object, "length", + length_value, JS_PropertyStub, JS_StrictPropertyStub, + JSPROP_READONLY); + DCHECK(success); + + // Define interface object properties (including constants). + success = JS_DefineProperties(context, rooted_interface_object, + interface_object_properties); + DCHECK(success); + // Define interface object functions (static). + success = JS_DefineFunctions(context, rooted_interface_object, + interface_object_functions); + DCHECK(success); + + + // Set the Prototype.constructor and Constructor.prototype properties. + DCHECK(interface_data->interface_object); + DCHECK(interface_data->prototype); + JS::RootedObject rooted_prototype(context, interface_data->prototype); + success = JS_LinkConstructorAndPrototype( + context, + rooted_interface_object, + rooted_prototype); + DCHECK(success); +} + +InterfaceData* GetInterfaceData(JSContext* context) { + MozjsGlobalEnvironment* global_environment = + static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); + // Use the address of the properties definition for this interface as a + // unique key for looking up the InterfaceData for this interface. + intptr_t key = reinterpret_cast<intptr_t>(&own_properties); + InterfaceData* interface_data = global_environment->GetInterfaceData(key); + if (!interface_data) { + interface_data = CreateCachedInterfaceData(); + DCHECK(interface_data); + global_environment->CacheInterfaceData(key, interface_data); + DCHECK_EQ(interface_data, global_environment->GetInterfaceData(key)); + } + return interface_data; +} + +} // namespace + +// static +JSObject* MozjsInterfaceWithAnyDictionary::CreateProxy( + JSContext* context, const scoped_refptr<Wrappable>& wrappable) { + DCHECK(MozjsGlobalEnvironment::GetFromContext(context)); + JS::RootedObject global_object( + context, + MozjsGlobalEnvironment::GetFromContext(context)->global_object()); + DCHECK(global_object); + + InterfaceData* interface_data = GetInterfaceData(context); + JS::RootedObject prototype(context, GetPrototype(context, global_object)); + DCHECK(prototype); + JS::RootedObject new_object(context, JS_NewObjectWithGivenProto( + context, &interface_data->instance_class_definition, prototype, NULL)); + DCHECK(new_object); + JS::RootedObject proxy(context, + ProxyHandler::NewProxy(context, new_object, prototype, NULL, + proxy_handler.Pointer())); + WrapperPrivate::AddPrivateData(context, proxy, wrappable); + return proxy; +} + +//static +const JSClass* MozjsInterfaceWithAnyDictionary::PrototypeClass( + JSContext* context) { + DCHECK(MozjsGlobalEnvironment::GetFromContext(context)); + JS::RootedObject global_object( + context, + MozjsGlobalEnvironment::GetFromContext(context)->global_object()); + DCHECK(global_object); + + JS::RootedObject prototype(context, GetPrototype(context, global_object)); + JSClass* proto_class = JS_GetClass(*prototype.address()); + return proto_class; +} + +// static +JSObject* MozjsInterfaceWithAnyDictionary::GetPrototype( + JSContext* context, JS::HandleObject global_object) { + DCHECK(JS_IsGlobalObject(global_object)); + + InterfaceData* interface_data = GetInterfaceData(context); + if (!interface_data->prototype) { + // Create new prototype that has all the props and methods + InitializePrototypeAndInterfaceObject( + interface_data, context, global_object); + } + DCHECK(interface_data->prototype); + return interface_data->prototype; +} + +// static +JSObject* MozjsInterfaceWithAnyDictionary::GetInterfaceObject( + JSContext* context, JS::HandleObject global_object) { + DCHECK(JS_IsGlobalObject(global_object)); + + InterfaceData* interface_data = GetInterfaceData(context); + if (!interface_data->interface_object) { + InitializePrototypeAndInterfaceObject( + interface_data, context, global_object); + } + DCHECK(interface_data->interface_object); + return interface_data->interface_object; +} + + +namespace { +JSBool Constructor(JSContext* context, unsigned int argc, JS::Value* vp) { + MozjsExceptionState exception_state(context); + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + + scoped_refptr<InterfaceWithAnyDictionary> new_object = + new InterfaceWithAnyDictionary(); + JS::RootedValue result_value(context); + ToJSValue(context, new_object, &result_value); + DCHECK(result_value.isObject()); + JS::RootedObject result_object(context, JSVAL_TO_OBJECT(result_value)); + args.rval().setObject(*result_object); + return true; +} +} // namespace + + +} // namespace testing +} // namespace bindings +} // namespace cobalt
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.h b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.h new file mode 100644 index 0000000..185dcbc --- /dev/null +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.h
@@ -0,0 +1,52 @@ +// Copyright 2017 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. + +// clang-format off + +// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY! +// Auto-generated from template: bindings/mozjs/templates/interface.h.template + +#ifndef MozjsInterfaceWithAnyDictionary_h +#define MozjsInterfaceWithAnyDictionary_h + +#include "base/hash_tables.h" +#include "base/lazy_instance.h" +#include "base/memory/ref_counted.h" +#include "base/threading/thread_checker.h" +#include "cobalt/base/polymorphic_downcast.h" +#include "cobalt/script/wrappable.h" +#include "cobalt/bindings/testing/interface_with_any_dictionary.h" + +#include "third_party/mozjs/js/src/jsapi.h" + +namespace cobalt { +namespace bindings { +namespace testing { + +class MozjsInterfaceWithAnyDictionary { + public: + static JSObject* CreateProxy(JSContext* context, + const scoped_refptr<script::Wrappable>& wrappable); + static const JSClass* PrototypeClass(JSContext* context); + static JSObject* GetPrototype(JSContext* context, + JS::HandleObject global_object); + static JSObject* GetInterfaceObject(JSContext* context, + JS::HandleObject global_object); +}; + +} // namespace testing +} // namespace bindings +} // namespace cobalt + +#endif // MozjsInterfaceWithAnyDictionary_h
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc index 8e2d83d..7541b5b 100644 --- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc
@@ -478,7 +478,7 @@ WrapperPrivate::GetFromObject(context, object); ObjectTypeBindingsInterface* impl = wrapper_private->wrappable<ObjectTypeBindingsInterface>().get(); - TypeTraits<OpaqueHandle >::ConversionType value; + TypeTraits<::cobalt::script::OpaqueHandle >::ConversionType value; FromJSValue(context, vp, (kConversionFlagNullable), &exception_state, &value); if (exception_state.is_exception_set()) {
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_sequence_user.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_sequence_user.cc index e05d81c..0ddaaeb 100644 --- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_sequence_user.cc +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_sequence_user.cc
@@ -607,7 +607,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< scoped_refptr<ArbitraryInterface> > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< scoped_refptr<ArbitraryInterface> > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -671,7 +671,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< script::Sequence< script::Sequence< scoped_refptr<ArbitraryInterface> > > > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< ::cobalt::script::Sequence< ::cobalt::script::Sequence< scoped_refptr<ArbitraryInterface> > > > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -735,7 +735,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< int32_t > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< int32_t > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -799,7 +799,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< std::string > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< std::string > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -863,7 +863,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< script::Sequence< std::string > > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< ::cobalt::script::Sequence< std::string > > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -927,7 +927,7 @@ return false; } // Non-optional arguments - TypeTraits<script::UnionType2<std::string, script::Sequence< std::string > > >::ConversionType elements; + TypeTraits<::cobalt::script::UnionType2<std::string, ::cobalt::script::Sequence< std::string > > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -991,7 +991,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< script::UnionType2<std::string, scoped_refptr<ArbitraryInterface> > > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< ::cobalt::script::UnionType2<std::string, scoped_refptr<ArbitraryInterface> > > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0(
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_test_dictionary.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_test_dictionary.cc index 50bd3c2..8c8f3c4 100644 --- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_test_dictionary.cc +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_test_dictionary.cc
@@ -132,6 +132,28 @@ return; } } + if (in_dictionary.has_any_member_with_default()) { + JS::RootedValue member_value(context); + ToJSValue(context, in_dictionary.any_member_with_default(), &member_value); + if (!JS_DefineProperty(context, dictionary_object, + "anyMemberWithDefault", + member_value, NULL, NULL, kPropertyAttributes)) { + // Some internal error occurred. + NOTREACHED(); + return; + } + } + if (in_dictionary.has_any_member()) { + JS::RootedValue member_value(context); + ToJSValue(context, in_dictionary.any_member(), &member_value); + if (!JS_DefineProperty(context, dictionary_object, + "anyMember", + member_value, NULL, NULL, kPropertyAttributes)) { + // Some internal error occurred. + NOTREACHED(); + return; + } + } out_value.set(OBJECT_TO_JSVAL(dictionary_object)); } @@ -305,6 +327,20 @@ } out_dictionary->set_non_default_member(converted_value); } + JS::RootedValue any_member_with_default(context); + if (!JS_GetProperty(context, dictionary_object, + "anyMemberWithDefault", + any_member_with_default.address())) { + exception_state->SetSimpleException(kSimpleError); + return; + } + JS::RootedValue any_member(context); + if (!JS_GetProperty(context, dictionary_object, + "anyMember", + any_member.address())) { + exception_state->SetSimpleException(kSimpleError); + return; + } } } // namespace mozjs
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc index 2eb8e32..4529e86 100644 --- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc
@@ -269,7 +269,7 @@ WrapperPrivate::GetFromObject(context, object); UnionTypesInterface* impl = wrapper_private->wrappable<UnionTypesInterface>().get(); - TypeTraits<script::UnionType4<std::string, bool, scoped_refptr<ArbitraryInterface>, int32_t > >::ConversionType value; + TypeTraits<::cobalt::script::UnionType4<std::string, bool, scoped_refptr<ArbitraryInterface>, int32_t > >::ConversionType value; FromJSValue(context, vp, kNoConversionFlags, &exception_state, &value); if (exception_state.is_exception_set()) { @@ -351,7 +351,7 @@ WrapperPrivate::GetFromObject(context, object); UnionTypesInterface* impl = wrapper_private->wrappable<UnionTypesInterface>().get(); - TypeTraits<base::optional<script::UnionType2<double, std::string > > >::ConversionType value; + TypeTraits<base::optional<::cobalt::script::UnionType2<double, std::string > > >::ConversionType value; FromJSValue(context, vp, kNoConversionFlags, &exception_state, &value); if (exception_state.is_exception_set()) { @@ -433,7 +433,7 @@ WrapperPrivate::GetFromObject(context, object); UnionTypesInterface* impl = wrapper_private->wrappable<UnionTypesInterface>().get(); - TypeTraits<base::optional<script::UnionType2<double, std::string > > >::ConversionType value; + TypeTraits<base::optional<::cobalt::script::UnionType2<double, std::string > > >::ConversionType value; FromJSValue(context, vp, (kConversionFlagNullable), &exception_state, &value); if (exception_state.is_exception_set()) { @@ -515,7 +515,7 @@ WrapperPrivate::GetFromObject(context, object); UnionTypesInterface* impl = wrapper_private->wrappable<UnionTypesInterface>().get(); - TypeTraits<script::UnionType2<scoped_refptr<BaseInterface>, std::string > >::ConversionType value; + TypeTraits<::cobalt::script::UnionType2<scoped_refptr<BaseInterface>, std::string > >::ConversionType value; FromJSValue(context, vp, kNoConversionFlags, &exception_state, &value); if (exception_state.is_exception_set()) {
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_window.cc b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_window.cc index ea34cc4..b28b493 100644 --- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_window.cc +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/mozjs_window.cc
@@ -50,6 +50,7 @@ #include "cobalt/bindings/testing/implemented_interface.h" #include "cobalt/bindings/testing/indexed_getter_interface.h" #include "cobalt/bindings/testing/interface_with_any.h" +#include "cobalt/bindings/testing/interface_with_any_dictionary.h" #include "cobalt/bindings/testing/interface_with_unsupported_properties.h" #include "cobalt/bindings/testing/mozjs_anonymous_indexed_getter_interface.h" #include "cobalt/bindings/testing/mozjs_anonymous_named_getter_interface.h" @@ -77,6 +78,7 @@ #include "cobalt/bindings/testing/mozjs_implemented_interface.h" #include "cobalt/bindings/testing/mozjs_indexed_getter_interface.h" #include "cobalt/bindings/testing/mozjs_interface_with_any.h" +#include "cobalt/bindings/testing/mozjs_interface_with_any_dictionary.h" #include "cobalt/bindings/testing/mozjs_interface_with_unsupported_properties.h" #include "cobalt/bindings/testing/mozjs_named_constructor_interface.h" #include "cobalt/bindings/testing/mozjs_named_getter_interface.h" @@ -177,6 +179,7 @@ using cobalt::bindings::testing::ImplementedInterface; using cobalt::bindings::testing::IndexedGetterInterface; using cobalt::bindings::testing::InterfaceWithAny; +using cobalt::bindings::testing::InterfaceWithAnyDictionary; using cobalt::bindings::testing::InterfaceWithUnsupportedProperties; using cobalt::bindings::testing::MozjsAnonymousIndexedGetterInterface; using cobalt::bindings::testing::MozjsAnonymousNamedGetterInterface; @@ -208,6 +211,7 @@ using cobalt::bindings::testing::MozjsImplementedInterface; using cobalt::bindings::testing::MozjsIndexedGetterInterface; using cobalt::bindings::testing::MozjsInterfaceWithAny; +using cobalt::bindings::testing::MozjsInterfaceWithAnyDictionary; using cobalt::bindings::testing::MozjsInterfaceWithUnsupportedProperties; using cobalt::bindings::testing::MozjsNamedConstructorInterface; using cobalt::bindings::testing::MozjsNamedGetterInterface; @@ -589,7 +593,7 @@ WrapperPrivate::GetFromObject(context, object); Window* impl = wrapper_private->wrappable<Window>().get(); - TypeTraits<CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType value; + TypeTraits<::cobalt::script::CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType value; FromJSValue(context, vp, (kConversionFlagNullable), &exception_state, &value); if (exception_state.is_exception_set()) { @@ -1165,6 +1169,10 @@ base::Bind(MozjsInterfaceWithAny::CreateProxy), base::Bind(MozjsInterfaceWithAny::PrototypeClass)); wrapper_factory->RegisterWrappableType( + InterfaceWithAnyDictionary::InterfaceWithAnyDictionaryWrappableType(), + base::Bind(MozjsInterfaceWithAnyDictionary::CreateProxy), + base::Bind(MozjsInterfaceWithAnyDictionary::PrototypeClass)); + wrapper_factory->RegisterWrappableType( InterfaceWithUnsupportedProperties::InterfaceWithUnsupportedPropertiesWrappableType(), base::Bind(MozjsInterfaceWithUnsupportedProperties::CreateProxy), base::Bind(MozjsInterfaceWithUnsupportedProperties::PrototypeClass));
diff --git a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/test_dictionary.h b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/test_dictionary.h index 97ffad7..4ec2228 100644 --- a/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/test_dictionary.h +++ b/src/cobalt/bindings/generated/mozjs/testing/cobalt/bindings/testing/test_dictionary.h
@@ -25,7 +25,9 @@ #include <string> #include "base/optional.h" +#include "cobalt/script/script_value.h" #include "cobalt/script/sequence.h" +#include "cobalt/script/value_handle.h" #include "cobalt/bindings/testing/arbitrary_interface.h" using cobalt::bindings::testing::ArbitraryInterface; @@ -49,10 +51,73 @@ string_member_ = std::string(); has_interface_member_ = false; interface_member_ = scoped_refptr<ArbitraryInterface>(); - has_member_with_default_ = true; member_with_default_ = 5; has_non_default_member_ = false; non_default_member_ = int32_t(); + has_any_member_ = false; + } + + TestDictionary(const TestDictionary& other) { + has_boolean_member_ = other.has_boolean_member_; + boolean_member_ = other.boolean_member_; + has_short_clamp_member_ = other.has_short_clamp_member_; + short_clamp_member_ = other.short_clamp_member_; + has_long_member_ = other.has_long_member_; + long_member_ = other.long_member_; + has_double_member_ = other.has_double_member_; + double_member_ = other.double_member_; + has_string_member_ = other.has_string_member_; + string_member_ = other.string_member_; + has_interface_member_ = other.has_interface_member_; + interface_member_ = other.interface_member_; + member_with_default_ = other.member_with_default_; + has_non_default_member_ = other.has_non_default_member_; + non_default_member_ = other.non_default_member_; + if (other.any_member_with_default_) { + any_member_with_default_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference( + other.any_member_with_default_->referenced_value())); + } + has_any_member_ = other.has_any_member_; + if (other.any_member_) { + any_member_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference( + other.any_member_->referenced_value())); + } + } + + TestDictionary& operator=(const TestDictionary& other) { + has_boolean_member_ = other.has_boolean_member_; + boolean_member_ = other.boolean_member_; + has_short_clamp_member_ = other.has_short_clamp_member_; + short_clamp_member_ = other.short_clamp_member_; + has_long_member_ = other.has_long_member_; + long_member_ = other.long_member_; + has_double_member_ = other.has_double_member_; + double_member_ = other.double_member_; + has_string_member_ = other.has_string_member_; + string_member_ = other.string_member_; + has_interface_member_ = other.has_interface_member_; + interface_member_ = other.interface_member_; + member_with_default_ = other.member_with_default_; + has_non_default_member_ = other.has_non_default_member_; + non_default_member_ = other.non_default_member_; + if (other.any_member_with_default_) { + any_member_with_default_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference( + other.any_member_with_default_->referenced_value())); + } else { + any_member_with_default_.reset(); + } + has_any_member_ = other.has_any_member_; + if (other.any_member_) { + any_member_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference( + other.any_member_->referenced_value())); + } else { + any_member_.reset(); + } + return *this; } bool has_boolean_member() const { @@ -106,7 +171,7 @@ bool has_string_member() const { return has_string_member_; } - std::string string_member() const { + const std::string& string_member() const { DCHECK(has_string_member_); return string_member_; } @@ -118,7 +183,7 @@ bool has_interface_member() const { return has_interface_member_; } - scoped_refptr<ArbitraryInterface> interface_member() const { + const scoped_refptr<ArbitraryInterface>& interface_member() const { DCHECK(has_interface_member_); return interface_member_; } @@ -128,14 +193,12 @@ } bool has_member_with_default() const { - return has_member_with_default_; + return true; } int32_t member_with_default() const { - DCHECK(has_member_with_default_); return member_with_default_; } void set_member_with_default(int32_t value) { - has_member_with_default_ = true; member_with_default_ = value; } @@ -151,6 +214,44 @@ non_default_member_ = value; } + bool has_any_member_with_default() const { + return true; + } + const ::cobalt::script::ScriptValue<::cobalt::script::ValueHandle>* any_member_with_default() const { + if (!any_member_with_default_) { + return NULL; + } + return &(any_member_with_default_->referenced_value()); + } + void set_any_member_with_default(const ::cobalt::script::ScriptValue<::cobalt::script::ValueHandle>* value) { + if (value) { + any_member_with_default_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference(*value)); + } else { + any_member_with_default_.reset(); + } + } + + bool has_any_member() const { + return has_any_member_; + } + const ::cobalt::script::ScriptValue<::cobalt::script::ValueHandle>* any_member() const { + DCHECK(has_any_member_); + if (!any_member_) { + return NULL; + } + return &(any_member_->referenced_value()); + } + void set_any_member(const ::cobalt::script::ScriptValue<::cobalt::script::ValueHandle>* value) { + has_any_member_ = true; + if (value) { + any_member_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference(*value)); + } else { + any_member_.reset(); + } + } + private: bool has_boolean_member_; bool boolean_member_; @@ -164,10 +265,12 @@ std::string string_member_; bool has_interface_member_; scoped_refptr<ArbitraryInterface> interface_member_; - bool has_member_with_default_; int32_t member_with_default_; bool has_non_default_member_; int32_t non_default_member_; + scoped_ptr<script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference> any_member_with_default_; + bool has_any_member_; + scoped_ptr<script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference> any_member_; }; // This ostream override is necessary for MOCK_METHODs commonly used
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/dictionary_with_dictionary_member.h b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/dictionary_with_dictionary_member.h index eee757a..02dbce6 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/dictionary_with_dictionary_member.h +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/dictionary_with_dictionary_member.h
@@ -25,7 +25,9 @@ #include <string> #include "base/optional.h" +#include "cobalt/script/script_value.h" #include "cobalt/script/sequence.h" +#include "cobalt/script/value_handle.h" #include "cobalt/bindings/testing/test_dictionary.h" using cobalt::bindings::testing::TestDictionary; @@ -41,6 +43,17 @@ nested_dictionary_ = TestDictionary(); } + DictionaryWithDictionaryMember(const DictionaryWithDictionaryMember& other) { + has_nested_dictionary_ = other.has_nested_dictionary_; + nested_dictionary_ = other.nested_dictionary_; + } + + DictionaryWithDictionaryMember& operator=(const DictionaryWithDictionaryMember& other) { + has_nested_dictionary_ = other.has_nested_dictionary_; + nested_dictionary_ = other.nested_dictionary_; + return *this; + } + bool has_nested_dictionary() const { return has_nested_dictionary_; }
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc index c5622f7..657efc9 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_callback_interface_interface.cc
@@ -265,7 +265,7 @@ WrapperPrivate::GetFromObject(context, object); CallbackInterfaceInterface* impl = wrapper_private->wrappable<CallbackInterfaceInterface>().get(); - TypeTraits<CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType value; + TypeTraits<::cobalt::script::CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType value; if (args.length() != 1) { NOTREACHED(); return false; @@ -327,7 +327,7 @@ return false; } // Non-optional arguments - TypeTraits<CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType callback_interface; + TypeTraits<::cobalt::script::CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType callback_interface; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0(
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc index 1b865a6..15d0eed 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_dictionary_interface.cc
@@ -265,7 +265,7 @@ WrapperPrivate::GetFromObject(context, object); DictionaryInterface* impl = wrapper_private->wrappable<DictionaryInterface>().get(); - TypeTraits<script::Sequence< TestDictionary > >::ConversionType value; + TypeTraits<::cobalt::script::Sequence< TestDictionary > >::ConversionType value; if (args.length() != 1) { NOTREACHED(); return false;
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_any.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_any.cc index 5943475..f59f815 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_any.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_any.cc
@@ -276,7 +276,7 @@ return false; } // Non-optional arguments - TypeTraits<ValueHandle >::ConversionType value; + TypeTraits<::cobalt::script::ValueHandle >::ConversionType value; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0(
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.cc new file mode 100644 index 0000000..34cf85c --- /dev/null +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.cc
@@ -0,0 +1,608 @@ +// Copyright 2017 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. + +// clang-format off + +// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY! +// Auto-generated from template: bindings/mozjs45/templates/interface.cc.template + +#include "cobalt/bindings/testing/mozjs_interface_with_any_dictionary.h" + +#include "base/debug/trace_event.h" +#include "cobalt/base/polymorphic_downcast.h" +#include "cobalt/script/global_environment.h" +#include "cobalt/script/opaque_handle.h" +#include "cobalt/script/script_value.h" + +#include "mozjs_gen_type_conversion.h" + +#include "base/lazy_instance.h" +#include "cobalt/script/exception_state.h" +#include "cobalt/script/mozjs-45/callback_function_conversion.h" +#include "cobalt/script/mozjs-45/conversion_helpers.h" +#include "cobalt/script/mozjs-45/mozjs_callback_function.h" +#include "cobalt/script/mozjs-45/mozjs_exception_state.h" +#include "cobalt/script/mozjs-45/mozjs_global_environment.h" +#include "cobalt/script/mozjs-45/mozjs_object_handle.h" +#include "cobalt/script/mozjs-45/mozjs_property_enumerator.h" +#include "cobalt/script/mozjs-45/mozjs_user_object_holder.h" +#include "cobalt/script/mozjs-45/mozjs_value_handle.h" +#include "cobalt/script/mozjs-45/native_promise.h" +#include "cobalt/script/mozjs-45/proxy_handler.h" +#include "cobalt/script/mozjs-45/type_traits.h" +#include "cobalt/script/mozjs-45/wrapper_factory.h" +#include "cobalt/script/mozjs-45/wrapper_private.h" +#include "cobalt/script/property_enumerator.h" +#include "cobalt/script/sequence.h" +#include "third_party/mozjs-45/js/src/jsapi.h" +#include "third_party/mozjs-45/js/src/jsfriendapi.h" + +namespace { +using cobalt::bindings::testing::InterfaceWithAnyDictionary; +using cobalt::bindings::testing::MozjsInterfaceWithAnyDictionary; +using cobalt::script::CallbackInterfaceTraits; +using cobalt::script::GlobalEnvironment; +using cobalt::script::OpaqueHandle; +using cobalt::script::OpaqueHandleHolder; +using cobalt::script::ScriptValue; +using cobalt::script::ValueHandle; +using cobalt::script::Wrappable; + +using cobalt::script::CallbackFunction; +using cobalt::script::CallbackInterfaceTraits; +using cobalt::script::ExceptionState; +using cobalt::script::Wrappable; +using cobalt::script::mozjs::FromJSValue; +using cobalt::script::mozjs::InterfaceData; +using cobalt::script::mozjs::MozjsCallbackFunction; +using cobalt::script::mozjs::MozjsExceptionState; +using cobalt::script::mozjs::MozjsGlobalEnvironment; +using cobalt::script::mozjs::MozjsPropertyEnumerator; +using cobalt::script::mozjs::MozjsUserObjectHolder; +using cobalt::script::mozjs::ProxyHandler; +using cobalt::script::mozjs::ToJSValue; +using cobalt::script::mozjs::TypeTraits; +using cobalt::script::mozjs::WrapperFactory; +using cobalt::script::mozjs::WrapperPrivate; +using cobalt::script::mozjs::kConversionFlagClamped; +using cobalt::script::mozjs::kConversionFlagNullable; +using cobalt::script::mozjs::kConversionFlagRestricted; +using cobalt::script::mozjs::kConversionFlagTreatNullAsEmptyString; +using cobalt::script::mozjs::kConversionFlagTreatUndefinedAsEmptyString; +using cobalt::script::mozjs::kNoConversionFlags; +} // namespace + +namespace cobalt { +namespace bindings { +namespace testing { + +namespace { + +class MozjsInterfaceWithAnyDictionaryHandler : public ProxyHandler { + public: + MozjsInterfaceWithAnyDictionaryHandler() + : ProxyHandler(indexed_property_hooks, named_property_hooks) {} + + private: + static NamedPropertyHooks named_property_hooks; + static IndexedPropertyHooks indexed_property_hooks; +}; + +ProxyHandler::NamedPropertyHooks +MozjsInterfaceWithAnyDictionaryHandler::named_property_hooks = { + NULL, + NULL, + NULL, + NULL, + NULL, +}; +ProxyHandler::IndexedPropertyHooks +MozjsInterfaceWithAnyDictionaryHandler::indexed_property_hooks = { + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +static base::LazyInstance<MozjsInterfaceWithAnyDictionaryHandler> + proxy_handler; + +bool Constructor(JSContext* context, unsigned int argc, JS::Value* vp); +bool HasInstance(JSContext *context, JS::HandleObject type, + JS::MutableHandleValue vp, bool *success) { + JS::RootedObject global_object( + context, JS_GetGlobalForObject(context, type)); + DCHECK(global_object); + + JS::RootedObject prototype( + context, MozjsInterfaceWithAnyDictionary::GetPrototype(context, global_object)); + + // |IsDelegate| walks the prototype chain of an object returning true if + // .prototype is found. + bool is_delegate; + if (!IsDelegate(context, prototype, vp, &is_delegate)) { + *success = false; + return false; + } + + *success = is_delegate; + return true; +} + +const JSClass instance_class_definition = { + "InterfaceWithAnyDictionary", + 0 | JSCLASS_HAS_PRIVATE, + NULL, // addProperty + NULL, // delProperty + NULL, // getProperty + NULL, // setProperty + NULL, // enumerate + NULL, // resolve + NULL, // mayResolve + &WrapperPrivate::Finalizer, // finalize + NULL, // call + NULL, // hasInstance + NULL, // construct + &WrapperPrivate::Trace, // trace +}; + +const JSClass prototype_class_definition = { + "InterfaceWithAnyDictionaryPrototype", +}; + +const JSClass interface_object_class_definition = { + "InterfaceWithAnyDictionaryConstructor", + 0, + NULL, // addProperty + NULL, // delProperty + NULL, // getProperty + NULL, // setProperty + NULL, // enumerate + NULL, // resolve + NULL, // mayResolve + NULL, // finalize + NULL, // call + &HasInstance, + Constructor, +}; + +bool fcn_getAny( + JSContext* context, uint32_t argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + // Compute the 'this' value. + JS::RootedValue this_value(context, JS_ComputeThis(context, vp)); + // 'this' should be an object. + JS::RootedObject object(context); + if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) { + return false; + } + if (!JS_ValueToObject(context, this_value, &object)) { + NOTREACHED(); + return false; + } + const JSClass* proto_class = + MozjsInterfaceWithAnyDictionary::PrototypeClass(context); + if (proto_class == JS_GetClass(object)) { + // Simply returns true if the object is this class's prototype object. + // There is no need to return any value due to the object is not a platform + // object. The execution reaches here when Object.getOwnPropertyDescriptor + // gets called on native object prototypes. + return true; + } + + MozjsGlobalEnvironment* global_environment = + static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); + WrapperFactory* wrapper_factory = global_environment->wrapper_factory(); + if (!wrapper_factory->DoesObjectImplementInterface( + object, base::GetTypeId<InterfaceWithAnyDictionary>())) { + MozjsExceptionState exception(context); + exception.SetSimpleException(script::kDoesNotImplementInterface); + return false; + } + MozjsExceptionState exception_state(context); + JS::RootedValue result_value(context); + + WrapperPrivate* wrapper_private = + WrapperPrivate::GetFromObject(context, object); + InterfaceWithAnyDictionary* impl = + wrapper_private->wrappable<InterfaceWithAnyDictionary>().get(); + + if (!exception_state.is_exception_set()) { + ToJSValue(context, + impl->GetAny(), + &result_value); + } + if (!exception_state.is_exception_set()) { + args.rval().set(result_value); + } + return !exception_state.is_exception_set(); +} + +bool fcn_hasAny( + JSContext* context, uint32_t argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + // Compute the 'this' value. + JS::RootedValue this_value(context, JS_ComputeThis(context, vp)); + // 'this' should be an object. + JS::RootedObject object(context); + if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) { + return false; + } + if (!JS_ValueToObject(context, this_value, &object)) { + NOTREACHED(); + return false; + } + const JSClass* proto_class = + MozjsInterfaceWithAnyDictionary::PrototypeClass(context); + if (proto_class == JS_GetClass(object)) { + // Simply returns true if the object is this class's prototype object. + // There is no need to return any value due to the object is not a platform + // object. The execution reaches here when Object.getOwnPropertyDescriptor + // gets called on native object prototypes. + return true; + } + + MozjsGlobalEnvironment* global_environment = + static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); + WrapperFactory* wrapper_factory = global_environment->wrapper_factory(); + if (!wrapper_factory->DoesObjectImplementInterface( + object, base::GetTypeId<InterfaceWithAnyDictionary>())) { + MozjsExceptionState exception(context); + exception.SetSimpleException(script::kDoesNotImplementInterface); + return false; + } + MozjsExceptionState exception_state(context); + JS::RootedValue result_value(context); + + WrapperPrivate* wrapper_private = + WrapperPrivate::GetFromObject(context, object); + InterfaceWithAnyDictionary* impl = + wrapper_private->wrappable<InterfaceWithAnyDictionary>().get(); + + if (!exception_state.is_exception_set()) { + ToJSValue(context, + impl->HasAny(), + &result_value); + } + if (!exception_state.is_exception_set()) { + args.rval().set(result_value); + } + return !exception_state.is_exception_set(); +} + +bool fcn_hasAnyDefault( + JSContext* context, uint32_t argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + // Compute the 'this' value. + JS::RootedValue this_value(context, JS_ComputeThis(context, vp)); + // 'this' should be an object. + JS::RootedObject object(context); + if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) { + return false; + } + if (!JS_ValueToObject(context, this_value, &object)) { + NOTREACHED(); + return false; + } + const JSClass* proto_class = + MozjsInterfaceWithAnyDictionary::PrototypeClass(context); + if (proto_class == JS_GetClass(object)) { + // Simply returns true if the object is this class's prototype object. + // There is no need to return any value due to the object is not a platform + // object. The execution reaches here when Object.getOwnPropertyDescriptor + // gets called on native object prototypes. + return true; + } + + MozjsGlobalEnvironment* global_environment = + static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); + WrapperFactory* wrapper_factory = global_environment->wrapper_factory(); + if (!wrapper_factory->DoesObjectImplementInterface( + object, base::GetTypeId<InterfaceWithAnyDictionary>())) { + MozjsExceptionState exception(context); + exception.SetSimpleException(script::kDoesNotImplementInterface); + return false; + } + MozjsExceptionState exception_state(context); + JS::RootedValue result_value(context); + + WrapperPrivate* wrapper_private = + WrapperPrivate::GetFromObject(context, object); + InterfaceWithAnyDictionary* impl = + wrapper_private->wrappable<InterfaceWithAnyDictionary>().get(); + + if (!exception_state.is_exception_set()) { + ToJSValue(context, + impl->HasAnyDefault(), + &result_value); + } + if (!exception_state.is_exception_set()) { + args.rval().set(result_value); + } + return !exception_state.is_exception_set(); +} + +bool fcn_setAny( + JSContext* context, uint32_t argc, JS::Value *vp) { + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + // Compute the 'this' value. + JS::RootedValue this_value(context, JS_ComputeThis(context, vp)); + // 'this' should be an object. + JS::RootedObject object(context); + if (JS_TypeOfValue(context, this_value) != JSTYPE_OBJECT) { + return false; + } + if (!JS_ValueToObject(context, this_value, &object)) { + NOTREACHED(); + return false; + } + const JSClass* proto_class = + MozjsInterfaceWithAnyDictionary::PrototypeClass(context); + if (proto_class == JS_GetClass(object)) { + // Simply returns true if the object is this class's prototype object. + // There is no need to return any value due to the object is not a platform + // object. The execution reaches here when Object.getOwnPropertyDescriptor + // gets called on native object prototypes. + return true; + } + + MozjsGlobalEnvironment* global_environment = + static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); + WrapperFactory* wrapper_factory = global_environment->wrapper_factory(); + if (!wrapper_factory->DoesObjectImplementInterface( + object, base::GetTypeId<InterfaceWithAnyDictionary>())) { + MozjsExceptionState exception(context); + exception.SetSimpleException(script::kDoesNotImplementInterface); + return false; + } + MozjsExceptionState exception_state(context); + JS::RootedValue result_value(context); + + WrapperPrivate* wrapper_private = + WrapperPrivate::GetFromObject(context, object); + InterfaceWithAnyDictionary* impl = + wrapper_private->wrappable<InterfaceWithAnyDictionary>().get(); + const size_t kMinArguments = 1; + if (args.length() < kMinArguments) { + exception_state.SetSimpleException(script::kInvalidNumberOfArguments); + return false; + } + // Non-optional arguments + TypeTraits<::cobalt::script::ValueHandle >::ConversionType value; + + DCHECK_LT(0, args.length()); + JS::RootedValue non_optional_value0( + context, args[0]); + FromJSValue(context, + non_optional_value0, + kNoConversionFlags, + &exception_state, &value); + if (exception_state.is_exception_set()) { + return false; + } + + impl->SetAny(value); + result_value.set(JS::UndefinedHandleValue); + return !exception_state.is_exception_set(); +} + + + +const JSPropertySpec prototype_properties[] = { + JS_PS_END +}; + +const JSFunctionSpec prototype_functions[] = { + JS_FNSPEC( + "getAny", fcn_getAny, NULL, + 0, JSPROP_ENUMERATE, NULL), + JS_FNSPEC( + "hasAny", fcn_hasAny, NULL, + 0, JSPROP_ENUMERATE, NULL), + JS_FNSPEC( + "hasAnyDefault", fcn_hasAnyDefault, NULL, + 0, JSPROP_ENUMERATE, NULL), + JS_FNSPEC( + "setAny", fcn_setAny, NULL, + 1, JSPROP_ENUMERATE, NULL), + JS_FS_END +}; + +const JSPropertySpec interface_object_properties[] = { + JS_PS_END +}; + +const JSFunctionSpec interface_object_functions[] = { + JS_FS_END +}; + +const JSPropertySpec own_properties[] = { + JS_PS_END +}; + +void InitializePrototypeAndInterfaceObject( + InterfaceData* interface_data, JSContext* context, + JS::HandleObject global_object) { + DCHECK(!interface_data->prototype); + DCHECK(!interface_data->interface_object); + DCHECK(JS_IsGlobalObject(global_object)); + + JS::RootedObject parent_prototype( + context, JS_GetObjectPrototype(context, global_object)); + DCHECK(parent_prototype); + + interface_data->prototype = JS_NewObjectWithGivenProto( + context, &prototype_class_definition, parent_prototype + ); + + JS::RootedObject rooted_prototype(context, interface_data->prototype); + bool success = JS_DefineProperties( + context, + rooted_prototype, + prototype_properties); + + DCHECK(success); + success = JS_DefineFunctions( + context, rooted_prototype, prototype_functions); + DCHECK(success); + + JS::RootedObject function_prototype( + context, JS_GetFunctionPrototype(context, global_object)); + DCHECK(function_prototype); + // Create the Interface object. + interface_data->interface_object = JS_NewObjectWithGivenProto( + context, &interface_object_class_definition, + function_prototype); + + // Add the InterfaceObject.name property. + JS::RootedObject rooted_interface_object( + context, interface_data->interface_object); + JS::RootedValue name_value(context); + const char name[] = + "InterfaceWithAnyDictionary"; + name_value.setString(JS_NewStringCopyZ(context, name)); + success = JS_DefineProperty( + context, rooted_interface_object, "name", name_value, JSPROP_READONLY, + NULL, NULL); + DCHECK(success); + + // Add the InterfaceObject.length property. It is set to the length of the + // shortest argument list of all overload constructors. + JS::RootedValue length_value(context); + length_value.setInt32(0); + success = JS_DefineProperty( + context, rooted_interface_object, "length", length_value, + JSPROP_READONLY, NULL, NULL); + DCHECK(success); + + // Define interface object properties (including constants). + success = JS_DefineProperties(context, rooted_interface_object, + interface_object_properties); + DCHECK(success); + // Define interface object functions (static). + success = JS_DefineFunctions(context, rooted_interface_object, + interface_object_functions); + DCHECK(success); + + // Set the Prototype.constructor and Constructor.prototype properties. + DCHECK(interface_data->interface_object); + DCHECK(interface_data->prototype); + success = JS_LinkConstructorAndPrototype( + context, + rooted_interface_object, + rooted_prototype); + DCHECK(success); +} + +inline InterfaceData* GetInterfaceData(JSContext* context) { + const int kInterfaceUniqueId = 27; + MozjsGlobalEnvironment* global_environment = + static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); + // By convention, the |MozjsGlobalEnvironment| that we are associated with + // will hold our |InterfaceData| at index |kInterfaceUniqueId|, as we asked + // for it to be there in the first place, and could not have conflicted with + // any other interface. + return global_environment->GetInterfaceData(kInterfaceUniqueId); +} + +} // namespace + +// static +JSObject* MozjsInterfaceWithAnyDictionary::CreateProxy( + JSContext* context, const scoped_refptr<Wrappable>& wrappable) { + DCHECK(MozjsGlobalEnvironment::GetFromContext(context)); + JS::RootedObject global_object( + context, + MozjsGlobalEnvironment::GetFromContext(context)->global_object()); + DCHECK(global_object); + + InterfaceData* interface_data = GetInterfaceData(context); + JS::RootedObject prototype(context, GetPrototype(context, global_object)); + DCHECK(prototype); + JS::RootedObject new_object( + context, + JS_NewObjectWithGivenProto( + context, &instance_class_definition, prototype)); + DCHECK(new_object); + JS::RootedObject proxy(context, + ProxyHandler::NewProxy( + context, proxy_handler.Pointer(), new_object, prototype)); + WrapperPrivate::AddPrivateData(context, proxy, wrappable); + return proxy; +} + +// static +const JSClass* MozjsInterfaceWithAnyDictionary::PrototypeClass( + JSContext* context) { + DCHECK(MozjsGlobalEnvironment::GetFromContext(context)); + JS::RootedObject global_object( + context, + MozjsGlobalEnvironment::GetFromContext(context)->global_object()); + DCHECK(global_object); + + JS::RootedObject prototype(context, GetPrototype(context, global_object)); + const JSClass* proto_class = JS_GetClass(prototype); + return proto_class; +} + +// static +JSObject* MozjsInterfaceWithAnyDictionary::GetPrototype( + JSContext* context, JS::HandleObject global_object) { + DCHECK(JS_IsGlobalObject(global_object)); + + InterfaceData* interface_data = GetInterfaceData(context); + if (!interface_data->prototype) { + // Create new prototype that has all the props and methods + InitializePrototypeAndInterfaceObject( + interface_data, context, global_object); + } + DCHECK(interface_data->prototype); + return interface_data->prototype; +} + +// static +JSObject* MozjsInterfaceWithAnyDictionary::GetInterfaceObject( + JSContext* context, JS::HandleObject global_object) { + DCHECK(JS_IsGlobalObject(global_object)); + + InterfaceData* interface_data = GetInterfaceData(context); + if (!interface_data->interface_object) { + InitializePrototypeAndInterfaceObject( + interface_data, context, global_object); + } + DCHECK(interface_data->interface_object); + return interface_data->interface_object; +} + + +namespace { +bool Constructor(JSContext* context, unsigned int argc, JS::Value* vp) { + MozjsExceptionState exception_state(context); + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + + scoped_refptr<InterfaceWithAnyDictionary> new_object = + new InterfaceWithAnyDictionary(); + JS::RootedValue result_value(context); + ToJSValue(context, new_object, &result_value); + DCHECK(result_value.isObject()); + args.rval().setObject(result_value.toObject()); + return true; +} +} // namespace + + +} // namespace testing +} // namespace bindings +} // namespace cobalt
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.h b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.h new file mode 100644 index 0000000..8efc06e --- /dev/null +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_any_dictionary.h
@@ -0,0 +1,52 @@ +// Copyright 2017 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. + +// clang-format off + +// This file has been auto-generated by bindings/code_generator_cobalt.py. DO NOT MODIFY! +// Auto-generated from template: bindings/mozjs45/templates/interface.h.template + +#ifndef MozjsInterfaceWithAnyDictionary_h +#define MozjsInterfaceWithAnyDictionary_h + +#include "base/hash_tables.h" +#include "base/lazy_instance.h" +#include "base/memory/ref_counted.h" +#include "base/threading/thread_checker.h" +#include "cobalt/base/polymorphic_downcast.h" +#include "cobalt/script/wrappable.h" +#include "cobalt/bindings/testing/interface_with_any_dictionary.h" + +#include "third_party/mozjs-45/js/src/jsapi.h" + +namespace cobalt { +namespace bindings { +namespace testing { + +class MozjsInterfaceWithAnyDictionary { + public: + static JSObject* CreateProxy(JSContext* context, + const scoped_refptr<script::Wrappable>& wrappable); + static const JSClass* PrototypeClass(JSContext* context); + static JSObject* GetPrototype(JSContext* context, + JS::HandleObject global_object); + static JSObject* GetInterfaceObject(JSContext* context, + JS::HandleObject global_object); +}; + +} // namespace testing +} // namespace bindings +} // namespace cobalt + +#endif // MozjsInterfaceWithAnyDictionary_h
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_unsupported_properties.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_unsupported_properties.cc index c9d71d7..fd76bd8 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_unsupported_properties.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_interface_with_unsupported_properties.cc
@@ -319,7 +319,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 27; + const int kInterfaceUniqueId = 28; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_constructor_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_constructor_interface.cc index a013300..b9f0a33 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_constructor_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_constructor_interface.cc
@@ -275,7 +275,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 28; + const int kInterfaceUniqueId = 29; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_getter_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_getter_interface.cc index e183554..a5fe033 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_getter_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_getter_interface.cc
@@ -596,7 +596,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 29; + const int kInterfaceUniqueId = 30; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_indexed_getter_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_indexed_getter_interface.cc index 3874d45..3abd0a1 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_indexed_getter_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_named_indexed_getter_interface.cc
@@ -970,7 +970,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 30; + const int kInterfaceUniqueId = 31; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nested_put_forwards_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nested_put_forwards_interface.cc index f73f3c5..148e851 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nested_put_forwards_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nested_put_forwards_interface.cc
@@ -397,7 +397,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 31; + const int kInterfaceUniqueId = 32; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_no_constructor_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_no_constructor_interface.cc index 5940907..4990467 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_no_constructor_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_no_constructor_interface.cc
@@ -265,7 +265,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 32; + const int kInterfaceUniqueId = 33; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_no_interface_object_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_no_interface_object_interface.cc index bafa068..d9cf90e 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_no_interface_object_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_no_interface_object_interface.cc
@@ -228,7 +228,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 33; + const int kInterfaceUniqueId = 34; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nullable_types_test_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nullable_types_test_interface.cc index 9fc4e54..3ad3e5d 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nullable_types_test_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_nullable_types_test_interface.cc
@@ -1181,7 +1181,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 34; + const int kInterfaceUniqueId = 35; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_numeric_types_test_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_numeric_types_test_interface.cc index c335147..9dfd580 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_numeric_types_test_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_numeric_types_test_interface.cc
@@ -3393,7 +3393,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 35; + const int kInterfaceUniqueId = 36; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc index af0e29b..a04bd09 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_object_type_bindings_interface.cc
@@ -521,7 +521,7 @@ WrapperPrivate::GetFromObject(context, object); ObjectTypeBindingsInterface* impl = wrapper_private->wrappable<ObjectTypeBindingsInterface>().get(); - TypeTraits<OpaqueHandle >::ConversionType value; + TypeTraits<::cobalt::script::OpaqueHandle >::ConversionType value; if (args.length() != 1) { NOTREACHED(); return false; @@ -649,7 +649,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 36; + const int kInterfaceUniqueId = 37; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_operations_test_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_operations_test_interface.cc index 213d6bf..5232239 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_operations_test_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_operations_test_interface.cc
@@ -1817,7 +1817,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 37; + const int kInterfaceUniqueId = 38; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_promise_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_promise_interface.cc index 62a9828..e4ef6d9 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_promise_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_promise_interface.cc
@@ -534,7 +534,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 38; + const int kInterfaceUniqueId = 39; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_put_forwards_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_put_forwards_interface.cc index f25d3fb..a537335 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_put_forwards_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_put_forwards_interface.cc
@@ -456,7 +456,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 39; + const int kInterfaceUniqueId = 40; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_sequence_user.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_sequence_user.cc index fa79d52..c499278 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_sequence_user.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_sequence_user.cc
@@ -592,7 +592,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< scoped_refptr<ArbitraryInterface> > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< scoped_refptr<ArbitraryInterface> > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -656,7 +656,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< script::Sequence< script::Sequence< scoped_refptr<ArbitraryInterface> > > > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< ::cobalt::script::Sequence< ::cobalt::script::Sequence< scoped_refptr<ArbitraryInterface> > > > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -720,7 +720,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< int32_t > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< int32_t > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -784,7 +784,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< std::string > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< std::string > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -848,7 +848,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< script::Sequence< std::string > > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< ::cobalt::script::Sequence< std::string > > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -912,7 +912,7 @@ return false; } // Non-optional arguments - TypeTraits<script::UnionType2<std::string, script::Sequence< std::string > > >::ConversionType elements; + TypeTraits<::cobalt::script::UnionType2<std::string, ::cobalt::script::Sequence< std::string > > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -976,7 +976,7 @@ return false; } // Non-optional arguments - TypeTraits<script::Sequence< script::UnionType2<std::string, scoped_refptr<ArbitraryInterface> > > >::ConversionType elements; + TypeTraits<::cobalt::script::Sequence< ::cobalt::script::UnionType2<std::string, scoped_refptr<ArbitraryInterface> > > >::ConversionType elements; DCHECK_LT(0, args.length()); JS::RootedValue non_optional_value0( @@ -1133,7 +1133,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 40; + const int kInterfaceUniqueId = 41; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_static_properties_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_static_properties_interface.cc index 8526725..dc0f2a4 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_static_properties_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_static_properties_interface.cc
@@ -581,7 +581,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 42; + const int kInterfaceUniqueId = 43; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_anonymous_operation_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_anonymous_operation_interface.cc index dfb6793..e1171ba 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_anonymous_operation_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_anonymous_operation_interface.cc
@@ -326,7 +326,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 43; + const int kInterfaceUniqueId = 44; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_attribute_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_attribute_interface.cc index 480fab8..a12de2b 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_attribute_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_attribute_interface.cc
@@ -432,7 +432,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 44; + const int kInterfaceUniqueId = 45; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_operation_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_operation_interface.cc index d0f28bd..0a1bc87 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_operation_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_stringifier_operation_interface.cc
@@ -381,7 +381,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 45; + const int kInterfaceUniqueId = 46; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_target_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_target_interface.cc index 92e30b5..8ac1392 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_target_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_target_interface.cc
@@ -363,7 +363,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 46; + const int kInterfaceUniqueId = 47; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_test_dictionary.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_test_dictionary.cc index 98fc778..78401b1 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_test_dictionary.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_test_dictionary.cc
@@ -132,6 +132,28 @@ return; } } + if (in_dictionary.has_any_member_with_default()) { + JS::RootedValue member_value(context); + ToJSValue(context, in_dictionary.any_member_with_default(), &member_value); + if (!JS_DefineProperty(context, dictionary_object, + "anyMemberWithDefault", + member_value, kPropertyAttributes, nullptr, nullptr)) { + // Some internal error occurred. + NOTREACHED(); + return; + } + } + if (in_dictionary.has_any_member()) { + JS::RootedValue member_value(context); + ToJSValue(context, in_dictionary.any_member(), &member_value); + if (!JS_DefineProperty(context, dictionary_object, + "anyMember", + member_value, kPropertyAttributes, nullptr, nullptr)) { + // Some internal error occurred. + NOTREACHED(); + return; + } + } out_value.setObject(*dictionary_object); } @@ -305,6 +327,20 @@ } out_dictionary->set_non_default_member(converted_value); } + JS::RootedValue any_member_with_default(context); + if (!JS_GetProperty(context, dictionary_object, + "anyMemberWithDefault", + &any_member_with_default)) { + exception_state->SetSimpleException(kSimpleError); + return; + } + JS::RootedValue any_member(context); + if (!JS_GetProperty(context, dictionary_object, + "anyMember", + &any_member)) { + exception_state->SetSimpleException(kSimpleError); + return; + } } } // namespace mozjs
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc index 7908828..5269ebc 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_union_types_interface.cc
@@ -269,7 +269,7 @@ WrapperPrivate::GetFromObject(context, object); UnionTypesInterface* impl = wrapper_private->wrappable<UnionTypesInterface>().get(); - TypeTraits<script::UnionType4<std::string, bool, scoped_refptr<ArbitraryInterface>, int32_t > >::ConversionType value; + TypeTraits<::cobalt::script::UnionType4<std::string, bool, scoped_refptr<ArbitraryInterface>, int32_t > >::ConversionType value; if (args.length() != 1) { NOTREACHED(); return false; @@ -369,7 +369,7 @@ WrapperPrivate::GetFromObject(context, object); UnionTypesInterface* impl = wrapper_private->wrappable<UnionTypesInterface>().get(); - TypeTraits<base::optional<script::UnionType2<double, std::string > > >::ConversionType value; + TypeTraits<base::optional<::cobalt::script::UnionType2<double, std::string > > >::ConversionType value; if (args.length() != 1) { NOTREACHED(); return false; @@ -469,7 +469,7 @@ WrapperPrivate::GetFromObject(context, object); UnionTypesInterface* impl = wrapper_private->wrappable<UnionTypesInterface>().get(); - TypeTraits<base::optional<script::UnionType2<double, std::string > > >::ConversionType value; + TypeTraits<base::optional<::cobalt::script::UnionType2<double, std::string > > >::ConversionType value; if (args.length() != 1) { NOTREACHED(); return false; @@ -569,7 +569,7 @@ WrapperPrivate::GetFromObject(context, object); UnionTypesInterface* impl = wrapper_private->wrappable<UnionTypesInterface>().get(); - TypeTraits<script::UnionType2<scoped_refptr<BaseInterface>, std::string > >::ConversionType value; + TypeTraits<::cobalt::script::UnionType2<scoped_refptr<BaseInterface>, std::string > >::ConversionType value; if (args.length() != 1) { NOTREACHED(); return false; @@ -697,7 +697,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 48; + const int kInterfaceUniqueId = 49; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc index 949d54e..b9cb145 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/mozjs_window.cc
@@ -50,6 +50,7 @@ #include "cobalt/bindings/testing/implemented_interface.h" #include "cobalt/bindings/testing/indexed_getter_interface.h" #include "cobalt/bindings/testing/interface_with_any.h" +#include "cobalt/bindings/testing/interface_with_any_dictionary.h" #include "cobalt/bindings/testing/interface_with_unsupported_properties.h" #include "cobalt/bindings/testing/mozjs_anonymous_indexed_getter_interface.h" #include "cobalt/bindings/testing/mozjs_anonymous_named_getter_interface.h" @@ -77,6 +78,7 @@ #include "cobalt/bindings/testing/mozjs_implemented_interface.h" #include "cobalt/bindings/testing/mozjs_indexed_getter_interface.h" #include "cobalt/bindings/testing/mozjs_interface_with_any.h" +#include "cobalt/bindings/testing/mozjs_interface_with_any_dictionary.h" #include "cobalt/bindings/testing/mozjs_interface_with_unsupported_properties.h" #include "cobalt/bindings/testing/mozjs_named_constructor_interface.h" #include "cobalt/bindings/testing/mozjs_named_getter_interface.h" @@ -177,6 +179,7 @@ using cobalt::bindings::testing::ImplementedInterface; using cobalt::bindings::testing::IndexedGetterInterface; using cobalt::bindings::testing::InterfaceWithAny; +using cobalt::bindings::testing::InterfaceWithAnyDictionary; using cobalt::bindings::testing::InterfaceWithUnsupportedProperties; using cobalt::bindings::testing::MozjsAnonymousIndexedGetterInterface; using cobalt::bindings::testing::MozjsAnonymousNamedGetterInterface; @@ -208,6 +211,7 @@ using cobalt::bindings::testing::MozjsImplementedInterface; using cobalt::bindings::testing::MozjsIndexedGetterInterface; using cobalt::bindings::testing::MozjsInterfaceWithAny; +using cobalt::bindings::testing::MozjsInterfaceWithAnyDictionary; using cobalt::bindings::testing::MozjsInterfaceWithUnsupportedProperties; using cobalt::bindings::testing::MozjsNamedConstructorInterface; using cobalt::bindings::testing::MozjsNamedGetterInterface; @@ -614,7 +618,7 @@ WrapperPrivate::GetFromObject(context, object); Window* impl = wrapper_private->wrappable<Window>().get(); - TypeTraits<CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType value; + TypeTraits<::cobalt::script::CallbackInterfaceTraits<SingleOperationInterface > >::ConversionType value; if (args.length() != 1) { NOTREACHED(); return false; @@ -952,7 +956,7 @@ } inline InterfaceData* GetInterfaceData(JSContext* context) { - const int kInterfaceUniqueId = 50; + const int kInterfaceUniqueId = 51; MozjsGlobalEnvironment* global_environment = static_cast<MozjsGlobalEnvironment*>(JS_GetContextPrivate(context)); // By convention, the |MozjsGlobalEnvironment| that we are associated with @@ -1186,6 +1190,10 @@ base::Bind(MozjsInterfaceWithAny::CreateProxy), base::Bind(MozjsInterfaceWithAny::PrototypeClass)); wrapper_factory->RegisterWrappableType( + InterfaceWithAnyDictionary::InterfaceWithAnyDictionaryWrappableType(), + base::Bind(MozjsInterfaceWithAnyDictionary::CreateProxy), + base::Bind(MozjsInterfaceWithAnyDictionary::PrototypeClass)); + wrapper_factory->RegisterWrappableType( InterfaceWithUnsupportedProperties::InterfaceWithUnsupportedPropertiesWrappableType(), base::Bind(MozjsInterfaceWithUnsupportedProperties::CreateProxy), base::Bind(MozjsInterfaceWithUnsupportedProperties::PrototypeClass));
diff --git a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/test_dictionary.h b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/test_dictionary.h index 97ffad7..4ec2228 100644 --- a/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/test_dictionary.h +++ b/src/cobalt/bindings/generated/mozjs45/testing/cobalt/bindings/testing/test_dictionary.h
@@ -25,7 +25,9 @@ #include <string> #include "base/optional.h" +#include "cobalt/script/script_value.h" #include "cobalt/script/sequence.h" +#include "cobalt/script/value_handle.h" #include "cobalt/bindings/testing/arbitrary_interface.h" using cobalt::bindings::testing::ArbitraryInterface; @@ -49,10 +51,73 @@ string_member_ = std::string(); has_interface_member_ = false; interface_member_ = scoped_refptr<ArbitraryInterface>(); - has_member_with_default_ = true; member_with_default_ = 5; has_non_default_member_ = false; non_default_member_ = int32_t(); + has_any_member_ = false; + } + + TestDictionary(const TestDictionary& other) { + has_boolean_member_ = other.has_boolean_member_; + boolean_member_ = other.boolean_member_; + has_short_clamp_member_ = other.has_short_clamp_member_; + short_clamp_member_ = other.short_clamp_member_; + has_long_member_ = other.has_long_member_; + long_member_ = other.long_member_; + has_double_member_ = other.has_double_member_; + double_member_ = other.double_member_; + has_string_member_ = other.has_string_member_; + string_member_ = other.string_member_; + has_interface_member_ = other.has_interface_member_; + interface_member_ = other.interface_member_; + member_with_default_ = other.member_with_default_; + has_non_default_member_ = other.has_non_default_member_; + non_default_member_ = other.non_default_member_; + if (other.any_member_with_default_) { + any_member_with_default_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference( + other.any_member_with_default_->referenced_value())); + } + has_any_member_ = other.has_any_member_; + if (other.any_member_) { + any_member_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference( + other.any_member_->referenced_value())); + } + } + + TestDictionary& operator=(const TestDictionary& other) { + has_boolean_member_ = other.has_boolean_member_; + boolean_member_ = other.boolean_member_; + has_short_clamp_member_ = other.has_short_clamp_member_; + short_clamp_member_ = other.short_clamp_member_; + has_long_member_ = other.has_long_member_; + long_member_ = other.long_member_; + has_double_member_ = other.has_double_member_; + double_member_ = other.double_member_; + has_string_member_ = other.has_string_member_; + string_member_ = other.string_member_; + has_interface_member_ = other.has_interface_member_; + interface_member_ = other.interface_member_; + member_with_default_ = other.member_with_default_; + has_non_default_member_ = other.has_non_default_member_; + non_default_member_ = other.non_default_member_; + if (other.any_member_with_default_) { + any_member_with_default_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference( + other.any_member_with_default_->referenced_value())); + } else { + any_member_with_default_.reset(); + } + has_any_member_ = other.has_any_member_; + if (other.any_member_) { + any_member_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference( + other.any_member_->referenced_value())); + } else { + any_member_.reset(); + } + return *this; } bool has_boolean_member() const { @@ -106,7 +171,7 @@ bool has_string_member() const { return has_string_member_; } - std::string string_member() const { + const std::string& string_member() const { DCHECK(has_string_member_); return string_member_; } @@ -118,7 +183,7 @@ bool has_interface_member() const { return has_interface_member_; } - scoped_refptr<ArbitraryInterface> interface_member() const { + const scoped_refptr<ArbitraryInterface>& interface_member() const { DCHECK(has_interface_member_); return interface_member_; } @@ -128,14 +193,12 @@ } bool has_member_with_default() const { - return has_member_with_default_; + return true; } int32_t member_with_default() const { - DCHECK(has_member_with_default_); return member_with_default_; } void set_member_with_default(int32_t value) { - has_member_with_default_ = true; member_with_default_ = value; } @@ -151,6 +214,44 @@ non_default_member_ = value; } + bool has_any_member_with_default() const { + return true; + } + const ::cobalt::script::ScriptValue<::cobalt::script::ValueHandle>* any_member_with_default() const { + if (!any_member_with_default_) { + return NULL; + } + return &(any_member_with_default_->referenced_value()); + } + void set_any_member_with_default(const ::cobalt::script::ScriptValue<::cobalt::script::ValueHandle>* value) { + if (value) { + any_member_with_default_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference(*value)); + } else { + any_member_with_default_.reset(); + } + } + + bool has_any_member() const { + return has_any_member_; + } + const ::cobalt::script::ScriptValue<::cobalt::script::ValueHandle>* any_member() const { + DCHECK(has_any_member_); + if (!any_member_) { + return NULL; + } + return &(any_member_->referenced_value()); + } + void set_any_member(const ::cobalt::script::ScriptValue<::cobalt::script::ValueHandle>* value) { + has_any_member_ = true; + if (value) { + any_member_.reset( + new script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference(*value)); + } else { + any_member_.reset(); + } + } + private: bool has_boolean_member_; bool boolean_member_; @@ -164,10 +265,12 @@ std::string string_member_; bool has_interface_member_; scoped_refptr<ArbitraryInterface> interface_member_; - bool has_member_with_default_; int32_t member_with_default_; bool has_non_default_member_; int32_t non_default_member_; + scoped_ptr<script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference> any_member_with_default_; + bool has_any_member_; + scoped_ptr<script::ScriptValue<::cobalt::script::ValueHandle>::StrongReference> any_member_; }; // This ostream override is necessary for MOCK_METHODs commonly used
diff --git a/src/cobalt/bindings/mozjs/templates/dictionary-conversion.cc.template b/src/cobalt/bindings/mozjs/templates/dictionary-conversion.cc.template index cc878eb..3fb2623 100644 --- a/src/cobalt/bindings/mozjs/templates/dictionary-conversion.cc.template +++ b/src/cobalt/bindings/mozjs/templates/dictionary-conversion.cc.template
@@ -115,6 +115,7 @@ exception_state->SetSimpleException(kSimpleError); return; } +{% if not member.is_script_value %} if (!{{member.name}}.isUndefined()) { {{member.type}} converted_value; FromJSValue(context, @@ -127,6 +128,7 @@ } out_dictionary->set_{{member.name}}(converted_value); } +{% endif %} {% endfor %} }
diff --git a/src/cobalt/bindings/mozjs45/templates/dictionary-conversion.cc.template b/src/cobalt/bindings/mozjs45/templates/dictionary-conversion.cc.template index f276cbc..eefd158 100644 --- a/src/cobalt/bindings/mozjs45/templates/dictionary-conversion.cc.template +++ b/src/cobalt/bindings/mozjs45/templates/dictionary-conversion.cc.template
@@ -115,6 +115,7 @@ exception_state->SetSimpleException(kSimpleError); return; } +{% if not member.is_script_value %} if (!{{member.name}}.isUndefined()) { {{member.type}} converted_value; FromJSValue(context, @@ -127,6 +128,7 @@ } out_dictionary->set_{{member.name}}(converted_value); } +{% endif %} {% endfor %} }
diff --git a/src/cobalt/bindings/path_generator.py b/src/cobalt/bindings/path_generator.py index 46206cb..362f4c1 100644 --- a/src/cobalt/bindings/path_generator.py +++ b/src/cobalt/bindings/path_generator.py
@@ -48,6 +48,7 @@ def NamespaceComponents(self, interface_name): """Get the interface's namespace as a list of namespace components.""" + # Get the IDL filename relative to the cobalt directory, and split the # directory to get the list of namespace components. if interface_name in self.interfaces_info: @@ -59,9 +60,23 @@ else: raise KeyError('Unknown interface name %s', interface_name) - idl_path = os.path.relpath(idl_path, self.interfaces_root) - components = os.path.dirname(idl_path).split(os.sep) - return [os.path.basename(self.interfaces_root)] + components + rel_idl_path = os.path.relpath(idl_path, self.interfaces_root) + components = os.path.dirname(rel_idl_path).split(os.sep) + + # Check if this IDL's path lies in our interfaces root. If it does not, + # we treat it as an extension IDL. + real_interfaces_root = os.path.realpath(self.interfaces_root) + real_idl_path = os.path.realpath(os.path.dirname(idl_path)) + interfaces_root_is_in_components_path = (os.path.commonprefix( + [real_interfaces_root, real_idl_path]) == real_interfaces_root) + + if interfaces_root_is_in_components_path: + return [os.path.basename(self.interfaces_root)] + components + else: + # If our IDL path lies outside of the cobalt/ directory, assume it is + # an externally defined web extension and assign it the 'webapi_extension' + # namespace. + return [os.path.basename(self.interfaces_root), 'webapi_extension'] def Namespace(self, interface_name): """Get the interface's namespace."""
diff --git a/src/cobalt/bindings/templates/dictionary.h.template b/src/cobalt/bindings/templates/dictionary.h.template index 20c58ff..3a8bc12 100644 --- a/src/cobalt/bindings/templates/dictionary.h.template +++ b/src/cobalt/bindings/templates/dictionary.h.template
@@ -44,7 +44,9 @@ #include <string> #include "base/optional.h" +#include "cobalt/script/script_value.h" #include "cobalt/script/sequence.h" +#include "cobalt/script/value_handle.h" {% for include in includes %} #include "{{include}}" {% endfor %} @@ -71,34 +73,112 @@ public: {{class_name}}() { {% for member in members %} +{% if not member.default_value %} + has_{{member.name}}_ = false; +{% endif %} +{% if not member.is_script_value %} {% if member.default_value %} - has_{{member.name}}_ = true; {{member.name}}_ = {{member.default_value}}; {% else %} - has_{{member.name}}_ = false; {{member.name}}_ = {{member.type}}(); {% endif %} +{% endif %} {% endfor %} } +{% if parent %} + {{class_name}}(const {{class_name}}& other) + : {{parent}}(other) { +{% else %} + {{class_name}}(const {{class_name}}& other) { +{% endif %} +{% for member in members %} +{% if not member.default_value %} + has_{{member.name}}_ = other.has_{{member.name}}_; +{% endif %} +{% if not member.is_script_value %} + {{member.name}}_ = other.{{member.name}}_; +{% else %} + if (other.{{member.name}}_) { + {{member.name}}_.reset( + new script::ScriptValue<{{member.type}}>::StrongReference( + other.{{member.name}}_->referenced_value())); + } +{% endif %} +{% endfor %} + } + + {{class_name}}& operator=(const {{class_name}}& other) { +{% if parent %} + {{parent}}::operator=(other); +{% endif %} +{% for member in members %} +{% if not member.default_value %} + has_{{member.name}}_ = other.has_{{member.name}}_; +{% endif %} +{% if not member.is_script_value %} + {{member.name}}_ = other.{{member.name}}_; +{% else %} + if (other.{{member.name}}_) { + {{member.name}}_.reset( + new script::ScriptValue<{{member.type}}>::StrongReference( + other.{{member.name}}_->referenced_value())); + } else { + {{member.name}}_.reset(); + } +{% endif %} +{% endfor %} + return *this; + } + {% for member in members %} bool has_{{member.name}}() const { +{% if member.default_value %} + return true; +{% else %} return has_{{member.name}}_; +{% endif %} } - {{member.type}} {{member.name}}() const { + {{member.arg_type}} {{member.name}}() const { +{% if not member.default_value %} DCHECK(has_{{member.name}}_); +{% endif %} +{% if member.is_script_value %} + if (!{{member.name}}_) { + return NULL; + } + return &({{member.name}}_->referenced_value()); +{% else %} return {{member.name}}_; +{% endif %} } void set_{{member.name}}({{member.arg_type}} value) { +{% if not member.default_value %} has_{{member.name}}_ = true; +{% endif %} +{% if member.is_script_value %} + if (value) { + {{member.name}}_.reset( + new script::ScriptValue<{{member.type}}>::StrongReference(*value)); + } else { + {{member.name}}_.reset(); + } +{% else %} {{member.name}}_ = value; +{% endif %} } {% endfor %} private: {% for member in members %} +{% if not member.default_value %} bool has_{{member.name}}_; +{% endif %} +{% if member.is_script_value %} + scoped_ptr<script::ScriptValue<{{member.type}}>::StrongReference> {{member.name}}_; +{% else %} {{member.type}} {{member.name}}_; +{% endif %} {% endfor %} };
diff --git a/src/cobalt/bindings/testing/any_dictionary_bindings_test.cc b/src/cobalt/bindings/testing/any_dictionary_bindings_test.cc new file mode 100644 index 0000000..1892843 --- /dev/null +++ b/src/cobalt/bindings/testing/any_dictionary_bindings_test.cc
@@ -0,0 +1,75 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "base/logging.h" + +#include "cobalt/bindings/testing/bindings_test_base.h" +#include "cobalt/bindings/testing/interface_with_any_dictionary.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::ContainsRegex; + +namespace cobalt { +namespace bindings { +namespace testing { +namespace { + +class AnyDictionaryBindingsTest + : public InterfaceBindingsTest<InterfaceWithAnyDictionary> {}; + +TEST_F(AnyDictionaryBindingsTest, All) { + std::string result; + + EXPECT_TRUE(EvaluateScript("test.hasAnyDefault()", &result)) << result; + EXPECT_STREQ("true", result.c_str()); + + EXPECT_TRUE(EvaluateScript("test.hasAny()", &result)) << result; + EXPECT_STREQ("false", result.c_str()); + + // We should be able to clear it out this way. + EXPECT_TRUE(EvaluateScript("test.setAny(undefined)", &result)) << result; + EXPECT_TRUE(EvaluateScript("test.getAny()", &result)) << result; + EXPECT_STREQ("undefined", result.c_str()); + + EXPECT_TRUE(EvaluateScript("test.setAny(2001)", &result)) << result; + EXPECT_TRUE(EvaluateScript("test.getAny()", &result)) << result; + EXPECT_STREQ("2001", result.c_str()); + + EXPECT_TRUE(EvaluateScript("test.setAny(1.21)", &result)) << result; + EXPECT_TRUE(EvaluateScript("test.getAny()", &result)) << result; + EXPECT_STREQ("1.21", result.c_str()); + + EXPECT_TRUE(EvaluateScript("test.setAny('test')", &result)) << result; + EXPECT_TRUE(EvaluateScript("test.getAny()", &result)) << result; + EXPECT_STREQ("test", result.c_str()); + + EXPECT_TRUE(EvaluateScript("test.setAny(new Object())", &result)) << result; + EXPECT_TRUE(EvaluateScript("test.getAny()", &result)) << result; + EXPECT_STREQ("[object Object]", result.c_str()); + + EXPECT_TRUE(EvaluateScript("test.setAny(new ArbitraryInterface())", &result)) + << result; + EXPECT_TRUE(EvaluateScript("test.getAny()", &result)) << result; + EXPECT_STREQ("[object ArbitraryInterface]", result.c_str()); + + EXPECT_TRUE(EvaluateScript("test.setAny(null)", &result)) << result; + EXPECT_TRUE(EvaluateScript("test.getAny()", &result)) << result; + EXPECT_STREQ("null", result.c_str()); +} + +} // namespace +} // namespace testing +} // namespace bindings +} // namespace cobalt
diff --git a/src/cobalt/bindings/testing/interface_with_any_dictionary.h b/src/cobalt/bindings/testing/interface_with_any_dictionary.h new file mode 100644 index 0000000..9b6608d --- /dev/null +++ b/src/cobalt/bindings/testing/interface_with_any_dictionary.h
@@ -0,0 +1,57 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef COBALT_BINDINGS_TESTING_INTERFACE_WITH_ANY_DICTIONARY_H_ +#define COBALT_BINDINGS_TESTING_INTERFACE_WITH_ANY_DICTIONARY_H_ + +#include "base/compiler_specific.h" + +#include "cobalt/bindings/testing/test_dictionary.h" +#include "cobalt/script/script_value.h" +#include "cobalt/script/value_handle.h" +#include "cobalt/script/wrappable.h" + +namespace cobalt { +namespace bindings { +namespace testing { + +class InterfaceWithAnyDictionary : public script::Wrappable { + public: + InterfaceWithAnyDictionary() {} + + bool HasAnyDefault() const { + return dictionary_.has_any_member_with_default(); + } + + bool HasAny() const { return dictionary_.has_any_member(); } + + const script::ValueHandleHolder* GetAny() const { + return dictionary_.any_member(); + } + + void SetAny(const script::ValueHandleHolder& value) { + dictionary_.set_any_member(&value); + } + + DEFINE_WRAPPABLE_TYPE(InterfaceWithAnyDictionary); + + private: + TestDictionary dictionary_; +}; + +} // namespace testing +} // namespace bindings +} // namespace cobalt + +#endif // COBALT_BINDINGS_TESTING_INTERFACE_WITH_ANY_DICTIONARY_H_
diff --git a/src/starboard/win/lib/atomic_public.h b/src/cobalt/bindings/testing/interface_with_any_dictionary.idl similarity index 76% copy from src/starboard/win/lib/atomic_public.h copy to src/cobalt/bindings/testing/interface_with_any_dictionary.idl index be4e805..4c909d5 100644 --- a/src/starboard/win/lib/atomic_public.h +++ b/src/cobalt/bindings/testing/interface_with_any_dictionary.idl
@@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ -#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ - -#include "starboard/shared/win32/atomic_public.h" - -#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +[ Constructor ] +interface InterfaceWithAnyDictionary { + boolean hasAnyDefault(); + boolean hasAny(); + any getAny(); + void setAny(any value); +};
diff --git a/src/cobalt/bindings/testing/test_dictionary.idl b/src/cobalt/bindings/testing/test_dictionary.idl index c05dc58..5a0078c 100644 --- a/src/cobalt/bindings/testing/test_dictionary.idl +++ b/src/cobalt/bindings/testing/test_dictionary.idl
@@ -24,4 +24,7 @@ long memberWithDefault = 5; long nonDefaultMember; + + any anyMemberWithDefault = null; + any anyMember; };
diff --git a/src/cobalt/bindings/testing/testing.gyp b/src/cobalt/bindings/testing/testing.gyp index bc92e7c..2ef0d01 100644 --- a/src/cobalt/bindings/testing/testing.gyp +++ b/src/cobalt/bindings/testing/testing.gyp
@@ -50,6 +50,7 @@ 'global_interface_parent.idl', 'indexed_getter_interface.idl', 'interface_with_any.idl', + 'interface_with_any_dictionary.idl', 'interface_with_unsupported_properties.idl', 'named_constructor_interface.idl', 'named_getter_interface.idl', @@ -142,6 +143,7 @@ 'type': '<(gtest_target_type)', 'sources': [ 'any_bindings_test.cc', + 'any_dictionary_bindings_test.cc', 'boolean_type_bindings_test.cc', 'callback_function_test.cc', 'callback_interface_test.cc',
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc index d97bbbb..9f855ca 100644 --- a/src/cobalt/browser/application.cc +++ b/src/cobalt/browser/application.cc
@@ -33,6 +33,7 @@ #include "cobalt/base/application_event.h" #include "cobalt/base/cobalt_paths.h" #include "cobalt/base/deep_link_event.h" +#include "cobalt/base/get_application_key.h" #include "cobalt/base/init_cobalt.h" #include "cobalt/base/language.h" #include "cobalt/base/localized_strings.h" @@ -365,6 +366,8 @@ "h5vcc-location-src " "https://www.youtube.com/tv " "https://www.youtube.com/tv/ " + "https://web-green-qa.youtube.com/tv " + "https://web-green-qa.youtube.com/tv/ " "https://web-release-qa.youtube.com/tv " "https://web-release-qa.youtube.com/tv/ " #if defined(ENABLE_ABOUT_SCHEME) @@ -497,6 +500,17 @@ } #endif + base::optional<std::string> initial_key = + base::GetApplicationKey(initial_url); + options.storage_manager_options.savegame_options.id = initial_key; + + base::optional<std::string> default_key = + base::GetApplicationKey(GURL(kDefaultURL)); + if (initial_key == default_key) { + options.storage_manager_options.savegame_options.fallback_to_default_id = + true; + } + // User can specify an extra search path entry for files loaded via file://. options.web_module_options.extra_web_file_dir = GetExtraWebFileDir(); options.web_module_options.location_policy = kYouTubeTvLocationPolicy;
diff --git a/src/cobalt/browser/browser.gyp b/src/cobalt/browser/browser.gyp index 0ea1fe2..97fff2f 100644 --- a/src/cobalt/browser/browser.gyp +++ b/src/cobalt/browser/browser.gyp
@@ -66,6 +66,8 @@ 'memory_tracker/tool/log_writer_tool.h', 'memory_tracker/tool/malloc_stats_tool.cc', 'memory_tracker/tool/malloc_stats_tool.h', + 'memory_tracker/tool/malloc_logger_tool.cc', + 'memory_tracker/tool/malloc_logger_tool.h', 'memory_tracker/tool/memory_size_binner_tool.cc', 'memory_tracker/tool/memory_size_binner_tool.h', 'memory_tracker/tool/params.cc', @@ -150,6 +152,7 @@ '<(DEPTH)/nb/nb.gyp:nb', 'browser_bindings.gyp:bindings', 'screen_shot_writer', + '<(cobalt_webapi_extension_gyp_target)', ], # This target doesn't generate any headers, but it exposes generated # header files (for idl dictionaries) through this module's public header
diff --git a/src/cobalt/browser/browser_bindings_gen.gyp b/src/cobalt/browser/browser_bindings_gen.gyp index 392a6f5..92f4157 100644 --- a/src/cobalt/browser/browser_bindings_gen.gyp +++ b/src/cobalt/browser/browser_bindings_gen.gyp
@@ -209,6 +209,8 @@ '../xhr/xml_http_request.idl', '../xhr/xml_http_request_event_target.idl', '../xhr/xml_http_request_upload.idl', + + '<@(cobalt_webapi_extension_source_idl_files)', ], # IDL files that will end up generating a .h that will be #included in @@ -243,6 +245,7 @@ '../web_animations/animation_fill_mode.idl', '../web_animations/animation_playback_direction.idl', '../websocket/close_event_init.idl', + '<@(cobalt_webapi_extension_generated_header_idl_files)', ], # Partial interfaces and the right-side of "implements". Also includes @@ -291,6 +294,7 @@ '../dom/eme/media_encrypted_event.idl', '../dom/eme/media_key_message_event.idl', '../dom/eme/media_key_session.idl', + '../dom/eme/media_key_status_map.idl', '../dom/eme/media_key_system_access.idl', '../dom/eme/media_keys.idl', ], @@ -299,6 +303,7 @@ '../dom/eme/media_key_message_event_init.idl', '../dom/eme/media_key_message_type.idl', '../dom/eme/media_key_session_type.idl', + '../dom/eme/media_key_status.idl', '../dom/eme/media_key_system_configuration.idl', '../dom/eme/media_key_system_media_capability.idl', '../dom/eme/media_keys_requirement.idl',
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc index 905991b..a9eb520 100644 --- a/src/cobalt/browser/browser_module.cc +++ b/src/cobalt/browser/browser_module.cc
@@ -35,6 +35,7 @@ #include "cobalt/browser/screen_shot_writer.h" #include "cobalt/browser/storage_upgrade_handler.h" #include "cobalt/browser/switches.h" +#include "cobalt/browser/webapi_extension.h" #include "cobalt/dom/csp_delegate_factory.h" #include "cobalt/dom/keycode.h" #include "cobalt/dom/mutation_observer_task_manager.h" @@ -171,11 +172,21 @@ scoped_refptr<script::Wrappable> CreateH5VCC( const h5vcc::H5vcc::Settings& settings, const scoped_refptr<dom::Window>& window, - dom::MutationObserverTaskManager* mutation_observer_task_manager) { + dom::MutationObserverTaskManager* mutation_observer_task_manager, + script::GlobalEnvironment* global_environment) { + UNREFERENCED_PARAMETER(global_environment); return scoped_refptr<script::Wrappable>( new h5vcc::H5vcc(settings, window, mutation_observer_task_manager)); } +scoped_refptr<script::Wrappable> CreateExtensionInterface( + const scoped_refptr<dom::Window>& window, + dom::MutationObserverTaskManager* mutation_observer_task_manager, + script::GlobalEnvironment* global_environment) { + UNREFERENCED_PARAMETER(mutation_observer_task_manager); + return CreateWebAPIExtensionObject(window, global_environment); +} + renderer::RendererModule::Options RendererModuleWithCameraOptions( renderer::RendererModule::Options options, scoped_refptr<input::Camera3D> camera_3d) { @@ -197,10 +208,9 @@ options_(options), self_message_loop_(MessageLoop::current()), event_dispatcher_(event_dispatcher), - storage_manager_( - scoped_ptr<StorageUpgradeHandler>(new StorageUpgradeHandler(url)) - .PassAs<storage::StorageManager::UpgradeHandler>(), - options_.storage_manager_options), + storage_manager_(make_scoped_ptr(new StorageUpgradeHandler(url)) + .PassAs<storage::StorageManager::UpgradeHandler>(), + options_.storage_manager_options), #if defined(OS_STARBOARD) is_rendered_(false), #endif // OS_STARBOARD @@ -272,6 +282,14 @@ options_.web_module_options.injected_window_attributes["h5vcc"] = base::Bind(&CreateH5VCC, h5vcc_settings); + base::optional<std::string> extension_object_name = + GetWebAPIExtensionObjectPropertyName(); + if (extension_object_name) { + options_.web_module_options + .injected_window_attributes[*extension_object_name] = + base::Bind(&CreateExtensionInterface); + } + #if defined(ENABLE_DEBUG_CONSOLE) && defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES) CommandLine* command_line = CommandLine::ForCurrentProcess(); if (command_line->HasSwitch(switches::kInputFuzzer)) {
diff --git a/src/cobalt/browser/cobalt.gyp b/src/cobalt/browser/cobalt.gyp index 473f353..9c1f00b 100644 --- a/src/cobalt/browser/cobalt.gyp +++ b/src/cobalt/browser/cobalt.gyp
@@ -25,18 +25,14 @@ ], 'conditions': [ ['cobalt_enable_lib == 1', { - 'sources': ['lib/main.cc',], - 'all_dependent_settings': { - 'target_conditions': [ - ['_type=="executable" and _toolset=="target"', { - 'sources': [ - 'lib/imported/main_stub.cc', - ], - }], - ], - }, + 'sources': [ + 'lib/cobalt.def', + 'lib/main.cc', + ], }, { - 'sources': ['main.cc',], + 'sources': [ + 'main.cc', + ], }], ['cobalt_copy_test_data == 1', { 'dependencies': [
diff --git a/src/cobalt/browser/debug_console.cc b/src/cobalt/browser/debug_console.cc index 0813095..79a6cd5 100644 --- a/src/cobalt/browser/debug_console.cc +++ b/src/cobalt/browser/debug_console.cc
@@ -150,9 +150,11 @@ const debug::DebugHub::GetHudModeCallback& get_hud_mode_function, const debug::Debugger::GetDebugServerCallback& get_debug_server_callback, const scoped_refptr<dom::Window>& window, - dom::MutationObserverTaskManager* mutation_observer_task_manager) { + dom::MutationObserverTaskManager* mutation_observer_task_manager, + script::GlobalEnvironment* global_environment) { UNREFERENCED_PARAMETER(window); UNREFERENCED_PARAMETER(mutation_observer_task_manager); + UNREFERENCED_PARAMETER(global_environment); return new debug::DebugHub(get_hud_mode_function, get_debug_server_callback); }
diff --git a/src/cobalt/browser/lib/cobalt.def b/src/cobalt/browser/lib/cobalt.def new file mode 100644 index 0000000..966eca6 --- /dev/null +++ b/src/cobalt/browser/lib/cobalt.def
@@ -0,0 +1,652 @@ +; This file defines functions which are explicitly exported by cobalt.dll. +; More info can be found here: +; https://msdn.microsoft.com/en-us/library/d91k01sh.aspx +; And broader context is explained here: +; https://blogs.msdn.microsoft.com/oldnewthing/20140321-00/?p=1433/ + +EXPORTS + ; From starboard/shared/lib/exported/starboard_main.h: + StarboardMain + + ; From cobalt/browser/lib/exported/main.h: + CbLibMainSetCallbackRegistrationReadyCallback + CbLibMainSetOnCobaltInitializedCallback + CbLibMainSetHandleEventCallback + + ; From cobalt/render/rasterizer/lib/exported/graphics.h: + CbLibGraphicsSetContextCreatedCallback + CbLibGraphicsSetBeginRenderFrameCallback + CbLibGraphicsSetEndRenderFrameCallback + + ; From cobalt/render/rasterizer/lib/exported/video.h: + CbLibVideoSetOnUpdateProjectionType + CbLibVideoSetOnUpdateMeshes + CbLibVideoSetOnUpdateStereoMode + CbLibVideoSetOnUpdateRgbTextureId + + ; Following GL functions are copied from libGLESv2.def and EGL from + ; libEGL.def. We export these so that host-applications may use the same + ; GLES & EGL implementation that Cobalt is using for rendering. + glActiveTexture + glAttachShader + glBindAttribLocation + glBindBuffer + glBindFramebuffer + glBindRenderbuffer + glBindTexture + glBlendColor + glBlendEquation + glBlendEquationSeparate + glBlendFunc + glBlendFuncSeparate + glBufferData + glBufferSubData + glCheckFramebufferStatus + glClear + glClearColor + glClearDepthf + glClearStencil + glColorMask + glCompileShader + glCompressedTexImage2D + glCompressedTexSubImage2D + glCopyTexImage2D + glCopyTexSubImage2D + glCreateProgram + glCreateShader + glCullFace + glDeleteBuffers + glDeleteFramebuffers + glDeleteProgram + glDeleteRenderbuffers + glDeleteShader + glDeleteTextures + glDepthFunc + glDepthMask + glDepthRangef + glDetachShader + glDisable + glDisableVertexAttribArray + glDrawArrays + glDrawElements + glEnable + glEnableVertexAttribArray + glFinish + glFlush + glFramebufferRenderbuffer + glFramebufferTexture2D + glFrontFace + glGenBuffers + glGenFramebuffers + glGenRenderbuffers + glGenTextures + glGenerateMipmap + glGetActiveAttrib + glGetActiveUniform + glGetAttachedShaders + glGetAttribLocation + glGetBooleanv + glGetBufferParameteriv + glGetError + glGetFloatv + glGetFramebufferAttachmentParameteriv + glGetIntegerv + glGetProgramInfoLog + glGetProgramiv + glGetRenderbufferParameteriv + glGetShaderInfoLog + glGetShaderPrecisionFormat + glGetShaderSource + glGetShaderiv + glGetString + glGetTexParameterfv + glGetTexParameteriv + glGetUniformLocation + glGetUniformfv + glGetUniformiv + glGetVertexAttribPointerv + glGetVertexAttribfv + glGetVertexAttribiv + glHint + glIsBuffer + glIsEnabled + glIsFramebuffer + glIsProgram + glIsRenderbuffer + glIsShader + glIsTexture + glLineWidth + glLinkProgram + glPixelStorei + glPolygonOffset + glReadPixels + glReleaseShaderCompiler + glRenderbufferStorage + glSampleCoverage + glScissor + glShaderBinary + glShaderSource + glStencilFunc + glStencilFuncSeparate + glStencilMask + glStencilMaskSeparate + glStencilOp + glStencilOpSeparate + glTexImage2D + glTexParameterf + glTexParameterfv + glTexParameteri + glTexParameteriv + glTexSubImage2D + glUniform1f + glUniform1fv + glUniform1i + glUniform1iv + glUniform2f + glUniform2fv + glUniform2i + glUniform2iv + glUniform3f + glUniform3fv + glUniform3i + glUniform3iv + glUniform4f + glUniform4fv + glUniform4i + glUniform4iv + glUniformMatrix2fv + glUniformMatrix3fv + glUniformMatrix4fv + glUseProgram + glValidateProgram + glVertexAttrib1f + glVertexAttrib1fv + glVertexAttrib2f + glVertexAttrib2fv + glVertexAttrib3f + glVertexAttrib3fv + glVertexAttrib4f + glVertexAttrib4fv + glVertexAttribPointer + glViewport + + ; Extensions + glBlitFramebufferANGLE + glRenderbufferStorageMultisampleANGLE + glDeleteFencesNV + glFinishFenceNV + glGenFencesNV + glGetFenceivNV + glIsFenceNV + glSetFenceNV + glTestFenceNV + glGetTranslatedShaderSourceANGLE + glTexStorage2DEXT + glGetGraphicsResetStatusEXT + glReadnPixelsEXT + glGetnUniformfvEXT + glGetnUniformivEXT + glGenQueriesEXT + glDeleteQueriesEXT + glIsQueryEXT + glBeginQueryEXT + glEndQueryEXT + glGetQueryivEXT + glGetQueryObjectuivEXT + glVertexAttribDivisorANGLE + glDrawArraysInstancedANGLE + glDrawElementsInstancedANGLE + glProgramBinaryOES + glGetProgramBinaryOES + glDrawBuffersEXT + glMapBufferOES + glUnmapBufferOES + glGetBufferPointervOES + glMapBufferRangeEXT + glFlushMappedBufferRangeEXT + glDiscardFramebufferEXT + glInsertEventMarkerEXT + glPushGroupMarkerEXT + glPopGroupMarkerEXT + glEGLImageTargetTexture2DOES + glEGLImageTargetRenderbufferStorageOES + glBindVertexArrayOES + glDeleteVertexArraysOES + glGenVertexArraysOES + glIsVertexArrayOES + glDebugMessageControlKHR + glDebugMessageInsertKHR + glDebugMessageCallbackKHR + glGetDebugMessageLogKHR + glPushDebugGroupKHR + glPopDebugGroupKHR + glObjectLabelKHR + glGetObjectLabelKHR + glObjectPtrLabelKHR + glGetObjectPtrLabelKHR + glGetPointervKHR + glQueryCounterEXT + glGetQueryObjectivEXT + glGetQueryObjecti64vEXT + glGetQueryObjectui64vEXT + glBindUniformLocationCHROMIUM + glCoverageModulationCHROMIUM + + glMatrixLoadfCHROMIUM + glMatrixLoadIdentityCHROMIUM + glGenPathsCHROMIUM + glDeletePathsCHROMIUM + glIsPathCHROMIUM + glPathCommandsCHROMIUM + glPathParameterfCHROMIUM + glPathParameteriCHROMIUM + glGetPathParameterfvCHROMIUM + glGetPathParameterivCHROMIUM + glPathStencilFuncCHROMIUM + glStencilFillPathCHROMIUM + glStencilStrokePathCHROMIUM + glCoverFillPathCHROMIUM + glCoverStrokePathCHROMIUM + glStencilThenCoverFillPathCHROMIUM + glStencilThenCoverStrokePathCHROMIUM + glCoverFillPathInstancedCHROMIUM + glCoverStrokePathInstancedCHROMIUM + glStencilStrokePathInstancedCHROMIUM + glStencilFillPathInstancedCHROMIUM + glStencilThenCoverFillPathInstancedCHROMIUM + glStencilThenCoverStrokePathInstancedCHROMIUM + glBindFragmentInputLocationCHROMIUM + glProgramPathFragmentInputGenCHROMIUM + + ; GLES 3.0 Functions + glReadBuffer + glDrawRangeElements + glTexImage3D + glTexSubImage3D + glCopyTexSubImage3D + glCompressedTexImage3D + glCompressedTexSubImage3D + glGenQueries + glDeleteQueries + glIsQuery + glBeginQuery + glEndQuery + glGetQueryiv + glGetQueryObjectuiv + glUnmapBuffer + glGetBufferPointerv + glDrawBuffers + glUniformMatrix2x3fv + glUniformMatrix3x2fv + glUniformMatrix2x4fv + glUniformMatrix4x2fv + glUniformMatrix3x4fv + glUniformMatrix4x3fv + glBlitFramebuffer + glRenderbufferStorageMultisample + glFramebufferTextureLayer + glMapBufferRange + glFlushMappedBufferRange + glBindVertexArray + glDeleteVertexArrays + glGenVertexArrays + glIsVertexArray + glGetIntegeri_v + glBeginTransformFeedback + glEndTransformFeedback + glBindBufferRange + glBindBufferBase + glTransformFeedbackVaryings + glGetTransformFeedbackVarying + glVertexAttribIPointer + glGetVertexAttribIiv + glGetVertexAttribIuiv + glVertexAttribI4i + glVertexAttribI4ui + glVertexAttribI4iv + glVertexAttribI4uiv + glGetUniformuiv + glGetFragDataLocation + glUniform1ui + glUniform2ui + glUniform3ui + glUniform4ui + glUniform1uiv + glUniform2uiv + glUniform3uiv + glUniform4uiv + glClearBufferiv + glClearBufferuiv + glClearBufferfv + glClearBufferfi + glGetStringi + glCopyBufferSubData + glGetUniformIndices + glGetActiveUniformsiv + glGetUniformBlockIndex + glGetActiveUniformBlockiv + glGetActiveUniformBlockName + glUniformBlockBinding + glDrawArraysInstanced + glDrawElementsInstanced + glFenceSync + glIsSync + glDeleteSync + glClientWaitSync + glWaitSync + glGetInteger64v + glGetSynciv + glGetInteger64i_v + glGetBufferParameteri64v + glGenSamplers + glDeleteSamplers + glIsSampler + glBindSampler + glSamplerParameteri + glSamplerParameteriv + glSamplerParameterf + glSamplerParameterfv + glGetSamplerParameteriv + glGetSamplerParameterfv + glVertexAttribDivisor + glBindTransformFeedback + glDeleteTransformFeedbacks + glGenTransformFeedbacks + glIsTransformFeedback + glPauseTransformFeedback + glResumeTransformFeedback + glGetProgramBinary + glProgramBinary + glProgramParameteri + glInvalidateFramebuffer + glInvalidateSubFramebuffer + glTexStorage2D + glTexStorage3D + glGetInternalformativ + + ; GLES 3.1 Functions + glDispatchCompute + glDispatchComputeIndirect + glDrawArraysIndirect + glDrawElementsIndirect + glFramebufferParameteri + glGetFramebufferParameteriv + glGetProgramInterfaceiv + glGetProgramResourceIndex + glGetProgramResourceName + glGetProgramResourceiv + glGetProgramResourceLocation + glUseProgramStages + glActiveShaderProgram + glCreateShaderProgramv + glBindProgramPipeline + glDeleteProgramPipelines + glGenProgramPipelines + glIsProgramPipeline + glGetProgramPipelineiv + glProgramUniform1i + glProgramUniform2i + glProgramUniform3i + glProgramUniform4i + glProgramUniform1ui + glProgramUniform2ui + glProgramUniform3ui + glProgramUniform4ui + glProgramUniform1f + glProgramUniform2f + glProgramUniform3f + glProgramUniform4f + glProgramUniform1iv + glProgramUniform2iv + glProgramUniform3iv + glProgramUniform4iv + glProgramUniform1uiv + glProgramUniform2uiv + glProgramUniform3uiv + glProgramUniform4uiv + glProgramUniform1fv + glProgramUniform2fv + glProgramUniform3fv + glProgramUniform4fv + glProgramUniformMatrix2fv + glProgramUniformMatrix3fv + glProgramUniformMatrix4fv + glProgramUniformMatrix2x3fv + glProgramUniformMatrix3x2fv + glProgramUniformMatrix2x4fv + glProgramUniformMatrix4x2fv + glProgramUniformMatrix3x4fv + glProgramUniformMatrix4x3fv + glValidateProgramPipeline + glGetProgramPipelineInfoLog + glBindImageTexture + glGetBooleani_v + glMemoryBarrier + glMemoryBarrierByRegion + glTexStorage2DMultisample + glGetMultisamplefv + glSampleMaski + glGetTexLevelParameteriv + glGetTexLevelParameterfv + glBindVertexBuffer + glVertexAttribFormat + glVertexAttribIFormat + glVertexAttribBinding + glVertexBindingDivisor + + ; ANGLE Platform Implementation + ANGLEGetDisplayPlatform + ANGLEResetDisplayPlatform + eglBindAPI + eglBindTexImage + eglChooseConfig + eglCopyBuffers + eglCreateContext + eglCreatePbufferFromClientBuffer + eglCreatePbufferSurface + eglCreatePixmapSurface + eglCreateWindowSurface + eglDestroyContext + eglDestroySurface + eglGetConfigAttrib + eglGetConfigs + eglGetCurrentContext + eglGetCurrentDisplay + eglGetCurrentSurface + eglGetDisplay + eglGetError + eglGetProcAddress + eglInitialize + eglMakeCurrent + eglQueryAPI + eglQueryContext + eglQueryString + eglQuerySurface + eglReleaseTexImage + eglReleaseThread + eglSurfaceAttrib + eglSwapBuffers + eglSwapInterval + eglTerminate + eglWaitClient + eglWaitGL + eglWaitNative + + ; Extensions + eglGetPlatformDisplayEXT + eglQuerySurfacePointerANGLE + eglPostSubBufferNV + eglQueryDisplayAttribEXT + eglQueryDeviceAttribEXT + eglQueryDeviceStringEXT + eglCreateImageKHR + eglDestroyImageKHR + eglCreateDeviceANGLE + eglReleaseDeviceANGLE + eglCreateStreamKHR + eglDestroyStreamKHR + eglStreamAttribKHR + eglQueryStreamKHR + eglQueryStreamu64KHR + eglStreamConsumerGLTextureExternalKHR + eglStreamConsumerAcquireKHR + eglStreamConsumerReleaseKHR + eglStreamConsumerGLTextureExternalAttribsNV + eglCreateStreamProducerD3DTextureNV12ANGLE + eglStreamPostD3DTextureNV12ANGLE + eglGetSyncValuesCHROMIUM + eglSwapBuffersWithDamageEXT + + ; 1.5 entry points + eglCreateSync + eglDestroySync + eglClientWaitSync + eglGetSyncAttrib + eglCreateImage + eglDestroyImage + eglGetPlatformDisplay + eglCreatePlatformWindowSurface + eglCreatePlatformPixmapSurface + eglWaitSync + eglBindAPI + eglBindTexImage + eglChooseConfig + eglCopyBuffers + eglCreateContext + eglCreatePbufferFromClientBuffer + eglCreatePbufferSurface + eglCreatePixmapSurface + eglCreateWindowSurface + eglDestroyContext + eglDestroySurface + eglGetConfigAttrib + eglGetConfigs + eglGetCurrentContext + eglGetCurrentDisplay + eglGetCurrentSurface + eglGetDisplay + eglGetError + eglGetProcAddress + eglInitialize + eglMakeCurrent + eglQueryAPI + eglQueryContext + eglQueryString + eglQuerySurface + eglReleaseTexImage + eglReleaseThread + eglSurfaceAttrib + eglSwapBuffers + eglSwapInterval + eglTerminate + eglWaitClient + eglWaitGL + eglWaitNative + + ; Extensions + eglGetPlatformDisplayEXT + eglQuerySurfacePointerANGLE + eglPostSubBufferNV + eglQueryDisplayAttribEXT + eglQueryDeviceAttribEXT + eglQueryDeviceStringEXT + eglCreateImageKHR + eglDestroyImageKHR + eglCreateDeviceANGLE + eglReleaseDeviceANGLE + eglCreateStreamKHR + eglDestroyStreamKHR + eglStreamAttribKHR + eglQueryStreamKHR + eglQueryStreamu64KHR + eglStreamConsumerGLTextureExternalKHR + eglStreamConsumerAcquireKHR + eglStreamConsumerReleaseKHR + eglStreamConsumerGLTextureExternalAttribsNV + eglCreateStreamProducerD3DTextureNV12ANGLE + eglStreamPostD3DTextureNV12ANGLE + eglGetSyncValuesCHROMIUM + eglSwapBuffersWithDamageEXT + + ; 1.5 entry points + eglCreateSync + eglDestroySync + eglClientWaitSync + eglGetSyncAttrib + eglCreateImage + eglDestroyImage + eglGetPlatformDisplay + eglCreatePlatformWindowSurface + eglCreatePlatformPixmapSurface + eglWaitSync + eglBindAPI + eglBindTexImage + eglChooseConfig + eglCopyBuffers + eglCreateContext + eglCreatePbufferFromClientBuffer + eglCreatePbufferSurface + eglCreatePixmapSurface + eglCreateWindowSurface + eglDestroyContext + eglDestroySurface + eglGetConfigAttrib + eglGetConfigs + eglGetCurrentContext + eglGetCurrentDisplay + eglGetCurrentSurface + eglGetDisplay + eglGetError + eglGetProcAddress + eglInitialize + eglMakeCurrent + eglQueryAPI + eglQueryContext + eglQueryString + eglQuerySurface + eglReleaseTexImage + eglReleaseThread + eglSurfaceAttrib + eglSwapBuffers + eglSwapInterval + eglTerminate + eglWaitClient + eglWaitGL + eglWaitNative + + ; Extensions + eglGetPlatformDisplayEXT + eglQuerySurfacePointerANGLE + eglPostSubBufferNV + eglQueryDisplayAttribEXT + eglQueryDeviceAttribEXT + eglQueryDeviceStringEXT + eglCreateImageKHR + eglDestroyImageKHR + eglCreateDeviceANGLE + eglReleaseDeviceANGLE + eglCreateStreamKHR + eglDestroyStreamKHR + eglStreamAttribKHR + eglQueryStreamKHR + eglQueryStreamu64KHR + eglStreamConsumerGLTextureExternalKHR + eglStreamConsumerAcquireKHR + eglStreamConsumerReleaseKHR + eglStreamConsumerGLTextureExternalAttribsNV + eglCreateStreamProducerD3DTextureNV12ANGLE + eglStreamPostD3DTextureNV12ANGLE + eglGetSyncValuesCHROMIUM + eglSwapBuffersWithDamageEXT + + ; 1.5 entry points + eglCreateSync + eglDestroySync + eglClientWaitSync + eglGetSyncAttrib + eglCreateImage + eglDestroyImage + eglGetPlatformDisplay + eglCreatePlatformWindowSurface + eglCreatePlatformPixmapSurface + eglWaitSync
diff --git a/src/cobalt/browser/lib/exported/main.h b/src/cobalt/browser/lib/exported/main.h new file mode 100644 index 0000000..087cb52 --- /dev/null +++ b/src/cobalt/browser/lib/exported/main.h
@@ -0,0 +1,53 @@ +// Copyright 2017 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. + +// All imported functions defined below MUST be implemented by client +// applications. + +#ifndef COBALT_BROWSER_LIB_EXPORTED_MAIN_H_ +#define COBALT_BROWSER_LIB_EXPORTED_MAIN_H_ + +#include "starboard/event.h" +#include "starboard/export.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*CbLibMainCallbackRegistrationReadyCallback)(void* context); +typedef void (*CbLibMainOnCobaltInitializedCallback)(void* context); +typedef bool (*CbLibMainHandleEventCallback)(void* context, + const SbEvent* event); + +// Sets a callback which will be called once Cobalt is ready to accept +// further callbacks. This is the only callback that may be set before +// intializing Cobalt; as soon as this callback is called, all remaining +// callbacks may be set. +SB_EXPORT_PLATFORM void CbLibMainSetCallbackRegistrationReadyCallback( + void* context, CbLibMainCallbackRegistrationReadyCallback callback); + +// Sets a callback which will be called after Cobalt has been initialized. +SB_EXPORT_PLATFORM void CbLibMainSetOnCobaltInitializedCallback( + void* context, CbLibMainOnCobaltInitializedCallback callback); + +// Sets a callback which will be called when Cobalt is receiving an event from +// Starboard. Returns true if the client consumed |event|; false otherwise. +SB_EXPORT_PLATFORM void CbLibMainSetHandleEventCallback( + void* context, CbLibMainHandleEventCallback callback); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // COBALT_BROWSER_LIB_EXPORTED_MAIN_H_
diff --git a/src/cobalt/browser/lib/imported/main.h b/src/cobalt/browser/lib/imported/main.h deleted file mode 100644 index 1cbfd3a..0000000 --- a/src/cobalt/browser/lib/imported/main.h +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright 2017 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. - -// All imported functions defined below MUST be implemented by client -// applications. - -#ifndef COBALT_BROWSER_LIB_IMPORTED_MAIN_H_ -#define COBALT_BROWSER_LIB_IMPORTED_MAIN_H_ - -#include "starboard/event.h" -#include "starboard/export.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Invoked after Cobalt has been initialized. -SB_IMPORT_PLATFORM void CbLibOnCobaltInitialized(); - -// Invoked when Cobalt is receiving an event from Starboard. -// Returns true if the client consumed |event|; false otherwise. -SB_IMPORT_PLATFORM bool CbLibHandleEvent(const SbEvent* event); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // COBALT_BROWSER_LIB_IMPORTED_MAIN_H_
diff --git a/src/cobalt/browser/lib/imported/main_stub.cc b/src/cobalt/browser/lib/imported/main_stub.cc deleted file mode 100644 index ad5c642..0000000 --- a/src/cobalt/browser/lib/imported/main_stub.cc +++ /dev/null
@@ -1,9 +0,0 @@ -#include "cobalt/browser/lib/imported/main.h" - -// Empty implementations so that 'lib' targets can be compiled into executables -// by the builder without missing symbol definitions. -void CbLibOnCobaltInitialized() {} -bool CbLibHandleEvent(const SbEvent* event) { - (void) event; - return false; -}
diff --git a/src/cobalt/browser/lib/main.cc b/src/cobalt/browser/lib/main.cc index 13657ee..fea5e48 100644 --- a/src/cobalt/browser/lib/main.cc +++ b/src/cobalt/browser/lib/main.cc
@@ -12,21 +12,41 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "cobalt/browser/lib/exported/main.h" + +#include "base/bind.h" #include "base/callback.h" +#include "base/lazy_instance.h" #include "base/logging.h" #include "cobalt/base/wrap_main.h" #include "cobalt/browser/application.h" -#include "cobalt/browser/lib/imported/main.h" #include "starboard/event.h" #include "starboard/input.h" namespace { cobalt::browser::Application* g_application = NULL; +typedef base::Callback<void(void)> InitializedCallback; +typedef base::Callback<bool(const SbEvent*)> HandleEventCallback; +static base::LazyInstance<InitializedCallback> + g_on_cobalt_initialized_callback = LAZY_INSTANCE_INITIALIZER; +static base::LazyInstance<HandleEventCallback> g_handle_event_callback = + LAZY_INSTANCE_INITIALIZER; + +// We cannot use LazyInstance here as this can be set before Cobalt has been +// initialized at all - thus there will not yet exist an AtExitManager which +// means the app would crash if we tried to replace the lazy instance too +// early. Instead, for this one callback, we simply do things manually. +CbLibMainCallbackRegistrationReadyCallback g_callback_registration_ready = + nullptr; +void* g_registration_ready_context = nullptr; + void PreloadApplication(int /*argc*/, char** /*argv*/, const char* /*link*/, const base::Closure& quit_closure) { DCHECK(!g_application); + CHECK(g_callback_registration_ready); + g_callback_registration_ready(g_registration_ready_context); g_application = new cobalt::browser::Application(quit_closure, true /*should_preload*/); DCHECK(g_application); @@ -36,6 +56,8 @@ const base::Closure& quit_closure) { LOG(INFO) << "Starting application!"; if (!g_application) { + CHECK(g_callback_registration_ready); + g_callback_registration_ready(g_registration_ready_context); g_application = new cobalt::browser::Application(quit_closure, false /*should_preload*/); DCHECK(g_application); @@ -43,7 +65,8 @@ g_application->Start(); } DCHECK(g_application); - CbLibOnCobaltInitialized(); + if (!g_on_cobalt_initialized_callback.Get().is_null()) + g_on_cobalt_initialized_callback.Get().Run(); } void StopApplication() { @@ -54,9 +77,8 @@ } void HandleStarboardEvent(const SbEvent* starboard_event) { - DCHECK(starboard_event); - if (!CbLibHandleEvent(starboard_event)) { - DCHECK(g_application); + if (g_application && (g_handle_event_callback.Get().is_null() || + !g_handle_event_callback.Get().Run(starboard_event))) { g_application->HandleStarboardEvent(starboard_event); } } @@ -65,3 +87,21 @@ COBALT_WRAP_MAIN(PreloadApplication, StartApplication, HandleStarboardEvent, StopApplication); + +void CbLibMainSetCallbackRegistrationReadyCallback( + void* context, CbLibMainOnCobaltInitializedCallback callback) { + g_registration_ready_context = context; + g_callback_registration_ready = callback; +} + +void CbLibMainSetOnCobaltInitializedCallback( + void* context, CbLibMainOnCobaltInitializedCallback callback) { + g_on_cobalt_initialized_callback.Get() = + callback ? base::Bind(callback, context) : InitializedCallback(); +} + +void CbLibMainSetHandleEventCallback(void* context, + CbLibMainHandleEventCallback callback) { + g_handle_event_callback.Get() = + callback ? base::Bind(callback, context) : HandleEventCallback(); +}
diff --git a/src/cobalt/browser/memory_tracker/tool.cc b/src/cobalt/browser/memory_tracker/tool.cc index 9a95e1b..95b9290 100644 --- a/src/cobalt/browser/memory_tracker/tool.cc +++ b/src/cobalt/browser/memory_tracker/tool.cc
@@ -23,6 +23,7 @@ #include "cobalt/browser/memory_tracker/tool/compressed_time_series_tool.h" #include "cobalt/browser/memory_tracker/tool/leak_finder_tool.h" #include "cobalt/browser/memory_tracker/tool/log_writer_tool.h" +#include "cobalt/browser/memory_tracker/tool/malloc_logger_tool.h" #include "cobalt/browser/memory_tracker/tool/malloc_stats_tool.h" #include "cobalt/browser/memory_tracker/tool/memory_size_binner_tool.h" #include "cobalt/browser/memory_tracker/tool/print_csv_tool.h" @@ -65,6 +66,7 @@ kLeakTracer, kJavascriptLeakTracer, kMallocStats, + kMallocLogger, }; struct SwitchVal { @@ -160,58 +162,67 @@ SwitchVal startup_tool( "startup(num_mins=1)", // Name of tool. - "Records high-frequency memory metrics for the first 60 " - "seconds of program launch and then dumps it out in CSV format " - "to stdout.", + " Records high-frequency memory metrics for the first 60\n" + " seconds of program launch and then dumps it out in CSV format\n" + " to stdout.\n", kStartup); SwitchVal continuous_printer_tool( "continuous_printer", // Name of tool. - "Once every second the memory state is dumped to stdout.", + " Once every second the memory state is dumped to stdout.\n", kContinuousPrinter); SwitchVal compressed_timeseries_tool( "compressed_timeseries", // Name of tool. - "Use this tool to see the growth in memory usage as the app runs. The " - "memory growth is segmented into memory scopes and outputted as CSV. " - "The compressed time-series will depict the full history of the memory " - "using a fixed number of rows. Older history has degraded resolution and " - "while new entries are captured in full detail. This achieved by " - "evicting old entries by an exponential decay scheme.", + " Use this tool to see the growth in memory usage as the app runs.\n" + " The memory growth is segmented into memory scopes and outputted as\n" + " CSV. The compressed time-series will depict the full history of\n" + " the memory using a fixed number of rows. Older history has degraded\n" + " resolution and while new entries are captured in full detail. This\n" + " achieved by evicting old entries by an exponential decay scheme.\n", kCompressedTimeseries); SwitchVal binner_tool( "binner(region=NULL)", - "Dumps memory statistics once a second in CSV format to stdout. " - "The default memory region is all memory regions. Pass the " - "name of the memory region to specify that only that memory region " - "should be tracked. For example: binner(Javascript).", + " Dumps memory statistics once a second in CSV format to stdout.\n" + " The default memory region is all memory regions. Pass the\n" + " name of the memory region to specify that only that memory region\n" + " should be tracked. For example: binner(Javascript).\n", kBinnerAnalytics); SwitchVal allocation_logger_tool( "allocation_logger", - "Continuously writes allocations and deallocations to memory_log.txt. " - "This is a legacy format used by lbshell. The location of this " - "memory_log.txt file is in the platform dependent directory specified " - "by kSbSystemPathDebugOutputDirectory.", + " Continuously writes allocations and deallocations to\n" + " memory_log.txt. This is a legacy format used by lbshell. The\n" + " location of this memory_log.txt file is in the platform dependent\n" + " directory specified by kSbSystemPathDebugOutputDirectory.\n", kAllocationLogger); SwitchVal leak_tracing_tool( "leak_tracer", - "Automatically detects leaks and reports them in CSV format.", + " Automatically detects leaks and reports them in CSV format.\n", kLeakTracer); SwitchVal js_leak_tracing_tool( "js_leak_tracer", - "Automatically detects Javascript leaks and reports them in CSV format.", + " Automatically detects Javascript leaks and reports them in CSV\n" + " format.\n", kJavascriptLeakTracer); SwitchVal malloc_stats_tool( "malloc_stats", - "Queries the allocation system for memory usage. This is the most " - "lightweight tool. Output is CSV format.", + " Queries the allocation system for memory usage. This is the most\n" + " lightweight tool. Output is CSV format.\n", kMallocStats); + SwitchVal malloc_logger_tool( + "malloc_logger", + " Continuously writes allocations, deallocations, allocation location\n" + " and malloc stats to memory_log_<timestamp>.csv, without headers.\n" + " The location of this log file is in the platform dependent\n" + " directory specified by kSbSystemPathDebugOutputDirectory.\n", + kMallocLogger); + SwitchMap switch_map; switch_map[ParseToolName(startup_tool.tool_name)] = startup_tool; switch_map[ParseToolName(continuous_printer_tool.tool_name)] = @@ -224,6 +235,8 @@ switch_map[ParseToolName(leak_tracing_tool.tool_name)] = leak_tracing_tool; switch_map[ParseToolName(js_leak_tracing_tool.tool_name)] = js_leak_tracing_tool; + switch_map[ParseToolName(malloc_logger_tool.tool_name)] = + malloc_logger_tool; switch_map[ParseToolName(malloc_stats_tool.tool_name)] = malloc_stats_tool; @@ -383,6 +396,16 @@ tool_ptr.reset(new MallocStatsTool); break; } + case kMallocLogger: { + scoped_ptr<MallocLoggerTool> malloc_logger( + new MallocLoggerTool()); + + memory_tracker = MemoryTracker::Get(); + memory_tracker->InstallGlobalTrackingHooks(); + memory_tracker->SetMemoryTrackerDebugCallback(malloc_logger.get()); + tool_ptr.reset(malloc_logger.release()); + break; + } default: { SB_NOTREACHED() << "Unhandled case."; break;
diff --git a/src/cobalt/browser/memory_tracker/tool/malloc_logger_tool.cc b/src/cobalt/browser/memory_tracker/tool/malloc_logger_tool.cc new file mode 100644 index 0000000..9243bd6 --- /dev/null +++ b/src/cobalt/browser/memory_tracker/tool/malloc_logger_tool.cc
@@ -0,0 +1,204 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/browser/memory_tracker/tool/malloc_logger_tool.h" + +#include <algorithm> + +#include "base/time.h" +#include "cobalt/base/c_val.h" +#include "cobalt/browser/memory_tracker/tool/buffered_file_writer.h" +#include "cobalt/browser/memory_tracker/tool/params.h" +#include "cobalt/browser/memory_tracker/tool/util.h" +#include "nb/memory_scope.h" +#include "starboard/atomic.h" +#include "starboard/string.h" +#include "starboard/types.h" + +namespace cobalt { +namespace browser { +namespace memory_tracker { + +namespace { +const int kAllocationRecord = 1; +const int kDeallocationRecord = 0; +const size_t kStartIndex = 5; +const size_t kNumAddressPrints = 2; +const size_t kMaxStackSize = 10; +const size_t kRecordLimit = 1024; +const NbMemoryScopeInfo kEmptyCallstackMemoryScopeInfo = {nullptr, + "-", "-", 0, "-", true}; +} // namespace + +MallocLoggerTool::MallocLoggerTool() : start_time_(NowTime()), + atomic_counter_(0), + atomic_used_memory_(SbSystemGetUsedCPUMemory()) { + buffered_file_writer_.reset(new BufferedFileWriter(MemoryLogPath())); +} + +MallocLoggerTool::~MallocLoggerTool() { + // No locks are used for the thread reporter, so when it's set to null + // we allow one second for any suspended threads to run through and finish + // their reporting. + SbMemorySetReporter(NULL); + SbThreadSleep(kSbTimeSecond); + buffered_file_writer_.reset(NULL); +} + +std::string MallocLoggerTool::tool_name() const { + return "MemoryTrackerMallocLogger"; +} + +void MallocLoggerTool::Run(Params* params) { + // Update malloc stats every second + params->logger()->Output("MemoryTrackerMallocLogger running..."); + + // There are some memory allocations which do not get tracked. + // Those allocations show up as fragmentation. + // It has been empirically observed that a majority (98%+) of these + // untracked allocations happen in the first 20 seconds of Cobalt runtime. + // + // Also, there is minimal external fragmentation (< 1 MB) during this initial + // period. + // + // The following piece of code resets atomic_used_memory_ at the 20 second + // mark, to compensate for the deviation due to untracked memory. + base::TimeDelta current_sample_interval = + base::TimeDelta::FromSeconds(20); + if (!params->wait_for_finish_signal(current_sample_interval.ToSbTime())) { + atomic_used_memory_.store(SbSystemGetUsedCPUMemory()); + } + + // Export fragmentation as a CVal on HUD. + base::CVal<base::cval::SizeInBytes> memory_fragmentation( + "Memory.CPU.Fragmentation", base::cval::SizeInBytes(0), + "Memory Fragmentation"); + + // Update CVal every 5 seconds + current_sample_interval = base::TimeDelta::FromSeconds(5); + int64_t allocated_memory = 0; + int64_t used_memory = 0; + while (!params->wait_for_finish_signal(current_sample_interval.ToSbTime())) { + allocated_memory = SbSystemGetUsedCPUMemory(); + used_memory = atomic_used_memory_.load(); + memory_fragmentation = static_cast<uint64>( + std::max(allocated_memory - used_memory, static_cast<int64_t>(0))); + } +} + +void MallocLoggerTool::LogRecord(const void* memory_block, + const nb::analytics::AllocationRecord& record, + const nb::analytics::CallStack& callstack, int type) { + const int log_counter = atomic_counter_.increment(); + const int64_t used_memory = atomic_used_memory_.load(); + const int64_t allocated_memory = SbSystemGetUsedCPUMemory(); + const int time_since_start_ms = GetTimeSinceStartMs(); + char buff[kRecordLimit] = {0}; + size_t buff_pos = 0; + void* addresses[kMaxStackSize]; + + const NbMemoryScopeInfo* memory_scope; + if (callstack.empty()) { + memory_scope = &kEmptyCallstackMemoryScopeInfo; + } else { + memory_scope = callstack.back(); + } + + int bytes_written = SbStringFormatF(buff, sizeof(buff), + "%u,%d,%zd,\"%s\",%d,%s,%d,%" PRId64 ",%" PRId64 ",%" PRIXPTR ",\"", + log_counter, type, record.size, memory_scope->file_name_, + memory_scope->line_number_, memory_scope->function_name_, + time_since_start_ms, allocated_memory, used_memory, + reinterpret_cast<uintptr_t>(memory_block)); + + buff_pos += static_cast<size_t>(bytes_written); + const size_t count = std::max(SbSystemGetStack(addresses, kMaxStackSize), 0); + const size_t end_index = std::min(count, kStartIndex + kNumAddressPrints); + // For each of the stack addresses that we care about, concat them to the + // buffer. This was originally written to do multiple stack addresses but + // this tends to overflow on some lower platforms so it's possible that + // this loop only iterates once. + for (size_t i = kStartIndex; i < end_index; ++i) { + void* p = addresses[i]; + bytes_written = + SbStringFormatF(buff + buff_pos, kRecordLimit - buff_pos, + ",%" PRIXPTR "", reinterpret_cast<uintptr_t>(p)); + DCHECK_GE(bytes_written, 0); + buff_pos += static_cast<size_t>(bytes_written); + } + + // Adds a "\n" at the end. + bytes_written = SbStringConcat(buff + buff_pos, "\"\n", + static_cast<int>(kRecordLimit - buff_pos)); + buff_pos += bytes_written; + buffered_file_writer_->Append(buff, buff_pos); +} + +void MallocLoggerTool::OnMemoryAllocation( + const void* memory_block, const nb::analytics::AllocationRecord& record, + const nb::analytics::CallStack& callstack) { + atomic_used_memory_.fetch_add(record.size); + LogRecord(memory_block, record, callstack, kAllocationRecord); +} + +void MallocLoggerTool::OnMemoryDeallocation( + const void* memory_block, const nb::analytics::AllocationRecord& record, + const nb::analytics::CallStack& callstack) { + atomic_used_memory_.fetch_sub(record.size); + LogRecord(memory_block, record, callstack, kDeallocationRecord); +} + +std::string MallocLoggerTool::MemoryLogPath() { + char file_name_buff[2048] = {}; + SbSystemGetPath(kSbSystemPathDebugOutputDirectory, file_name_buff, + arraysize(file_name_buff)); + std::string path(file_name_buff); + if (!path.empty()) { // Protect against a dangling "/" at end. + const int back_idx_signed = static_cast<int>(path.length()) - 1; + if (back_idx_signed >= 0) { + const size_t idx = back_idx_signed; + if (path[idx] == '/') { + path.erase(idx); + } + } + } + + base::Time time = base::Time::Now(); + base::Time::Exploded exploded; + time.LocalExplode(&exploded); + + std::stringstream ss; + ss << "/memory_log_" << exploded.year << "-" + << exploded.month << "-" << exploded.day_of_month << ":" + << exploded.hour << "-" << exploded.minute << "-" << exploded.second + << ".csv"; + path.append(ss.str()); + return path; +} + +base::TimeTicks MallocLoggerTool::NowTime() { + // NowFromSystemTime() is slower but more accurate. However it might + // be useful to use the faster but less accurate version if there is + // a speedup. + return base::TimeTicks::Now(); +} + +int MallocLoggerTool::GetTimeSinceStartMs() const { + base::TimeDelta dt = NowTime() - start_time_; + return static_cast<int>(dt.InMilliseconds()); +} + +} // namespace memory_tracker +} // namespace browser +} // namespace cobalt
diff --git a/src/cobalt/browser/memory_tracker/tool/malloc_logger_tool.h b/src/cobalt/browser/memory_tracker/tool/malloc_logger_tool.h new file mode 100644 index 0000000..80313f9 --- /dev/null +++ b/src/cobalt/browser/memory_tracker/tool/malloc_logger_tool.h
@@ -0,0 +1,79 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef COBALT_BROWSER_MEMORY_TRACKER_TOOL_MALLOC_LOGGER_TOOL_H_ +#define COBALT_BROWSER_MEMORY_TRACKER_TOOL_MALLOC_LOGGER_TOOL_H_ + +#include <string> + +#include "base/compiler_specific.h" +#include "base/time.h" +#include "cobalt/browser/memory_tracker/tool/params.h" +#include "cobalt/browser/memory_tracker/tool/tool_impl.h" +#include "nb/memory_scope.h" +#include "starboard/atomic.h" +#include "starboard/memory_reporter.h" + +namespace cobalt { +namespace browser { +namespace memory_tracker { + +class BufferedFileWriter; + +// Outputs memory_log_<time_stamp>.csv to the output log location. This log +// contains allocations and deallocations with a non-symbolized stack trace. +class MallocLoggerTool: public AbstractTool, + public nb::analytics::MemoryTrackerDebugCallback { + public: + MallocLoggerTool(); + virtual ~MallocLoggerTool(); + + // Interface AbstractMemoryTrackerTool + virtual std::string tool_name() const OVERRIDE; + virtual void Run(Params* params) OVERRIDE; + + // OnMemoryAllocation() and OnMemoryDeallocation() are part of + // class MemoryTrackerDebugCallback. + void OnMemoryAllocation(const void* memory_block, + const nb::analytics::AllocationRecord& record, + const nb::analytics::CallStack& callstack) OVERRIDE; + + void OnMemoryDeallocation(const void* memory_block, + const nb::analytics::AllocationRecord& record, + const nb::analytics::CallStack& callstack) OVERRIDE; + + // Method to obtain allocation, stack information and generate records + void LogRecord(const void* memory_block, + const nb::analytics::AllocationRecord& record, + const nb::analytics::CallStack& callstack, + const int type); + + private: + static std::string MemoryLogPath(); + static base::TimeTicks NowTime(); + + int GetTimeSinceStartMs() const; + + base::TimeTicks start_time_; + scoped_ptr<SbMemoryReporter> memory_reporter_; + scoped_ptr<BufferedFileWriter> buffered_file_writer_; + starboard::atomic_int32_t atomic_counter_; + starboard::atomic_int64_t atomic_used_memory_; +}; + +} // namespace memory_tracker +} // namespace browser +} // namespace cobalt + +#endif // COBALT_BROWSER_MEMORY_TRACKER_TOOL_MALLOC_LOGGER_TOOL_H_
diff --git a/src/cobalt/browser/null_webapi_extension.cc b/src/cobalt/browser/null_webapi_extension.cc new file mode 100644 index 0000000..6d7e13b --- /dev/null +++ b/src/cobalt/browser/null_webapi_extension.cc
@@ -0,0 +1,41 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/browser/webapi_extension.h" + +#include "base/compiler_specific.h" +#include "cobalt/script/global_environment.h" + +namespace cobalt { +namespace browser { + +base::optional<std::string> GetWebAPIExtensionObjectPropertyName() { + return base::nullopt; +} + +scoped_refptr<script::Wrappable> CreateWebAPIExtensionObject( + const scoped_refptr<dom::Window>& window, + script::GlobalEnvironment* global_environment) { + UNREFERENCED_PARAMETER(window); + UNREFERENCED_PARAMETER(global_environment); + + // We should never get called if GetWindowExtensionObjectName() above returns + // base::nullopt. + NOTREACHED(); + + return scoped_refptr<script::Wrappable>(); +} + +} // namespace browser +} // namespace cobalt
diff --git a/src/cobalt/browser/null_webapi_extension.gyp b/src/cobalt/browser/null_webapi_extension.gyp new file mode 100644 index 0000000..ad078eb --- /dev/null +++ b/src/cobalt/browser/null_webapi_extension.gyp
@@ -0,0 +1,29 @@ +# Copyright 2017 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. +{ + 'targets': [ + { + 'target_name': 'null_webapi_extension', + 'type': 'static_library', + 'sources': [ + 'null_webapi_extension.cc', + ], + 'dependencies': [ + '<(DEPTH)/cobalt/dom/dom.gyp:dom', + '<(DEPTH)/cobalt/script/script.gyp:script', + '<(DEPTH)/base/base.gyp:base', + ], + }, + ], +}
diff --git a/src/cobalt/browser/splash_screen_cache.cc b/src/cobalt/browser/splash_screen_cache.cc index ab674df..29de881 100644 --- a/src/cobalt/browser/splash_screen_cache.cc +++ b/src/cobalt/browser/splash_screen_cache.cc
@@ -16,11 +16,11 @@ #include <string> -#include "base/base64.h" #include "base/memory/scoped_ptr.h" #include "base/optional.h" #include "base/string_util.h" #include "base/synchronization/lock.h" +#include "cobalt/base/get_application_key.h" #include "starboard/directory.h" #include "starboard/file.h" #include "starboard/string.h" @@ -113,15 +113,10 @@ // static base::optional<std::string> SplashScreenCache::GetKeyForStartUrl( const GURL& url) { - std::string encoded_url = ""; - if (!url.is_valid()) { + base::optional<std::string> encoded_url = base::GetApplicationKey(url); + if (!encoded_url) { return base::nullopt; } - base::Base64Encode(base::StringPiece(url.host() + url.path()), &encoded_url); - - // Make web-safe. - ReplaceChars(encoded_url, "/", "_", &encoded_url); - ReplaceChars(encoded_url, "+", "-", &encoded_url); char path[SB_FILE_MAX_PATH] = {0}; bool has_cache_dir = @@ -137,7 +132,7 @@ return base::nullopt; } subpath += "splash_screen"; - subcomponent = SB_FILE_SEP_STRING + encoded_url; + subcomponent = SB_FILE_SEP_STRING + *encoded_url; if (SbStringConcat(path, subcomponent.c_str(), SB_FILE_MAX_PATH) >= SB_FILE_MAX_PATH) { return base::nullopt;
diff --git a/src/cobalt/browser/stack_size_constants.h b/src/cobalt/browser/stack_size_constants.h index d6b33fc..3d7d7d2 100644 --- a/src/cobalt/browser/stack_size_constants.h +++ b/src/cobalt/browser/stack_size_constants.h
@@ -21,12 +21,12 @@ namespace browser { #if defined(COBALT_BUILD_TYPE_DEBUG) // Non-optimized builds require a bigger stack size. - const size_t kBaseStackSize = 2 * 1024 * 1024; + const size_t kBaseStackSize = 3 * 1024 * 1024; #elif defined(COBALT_BUILD_TYPE_DEVEL) // Devel builds require a slightly bigger stack size. - const size_t kBaseStackSize = 448 * 1024; + const size_t kBaseStackSize = 832 * 1024; #else - const size_t kBaseStackSize = 384 * 1024; + const size_t kBaseStackSize = 768 * 1024; #endif const size_t kWebModuleStackSize = kBaseStackSize + base::kAsanAdditionalStackSize;
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc index efd1b83..63abd63 100644 --- a/src/cobalt/browser/web_module.cc +++ b/src/cobalt/browser/web_module.cc
@@ -799,8 +799,8 @@ attributes.begin(); iter != attributes.end(); ++iter) { global_environment_->Bind( - iter->first, - iter->second.Run(window_, &mutation_observer_task_manager_)); + iter->first, iter->second.Run(window_, &mutation_observer_task_manager_, + global_environment_.get())); } }
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h index 07d8975..b296d6f 100644 --- a/src/cobalt/browser/web_module.h +++ b/src/cobalt/browser/web_module.h
@@ -82,7 +82,8 @@ struct Options { typedef base::Callback<scoped_refptr<script::Wrappable>( const scoped_refptr<dom::Window>& window, - dom::MutationObserverTaskManager* mutation_observer_task_manager)> + dom::MutationObserverTaskManager* mutation_observer_task_manager, + script::GlobalEnvironment* global_environment)> CreateObjectFunction; typedef base::hash_map<std::string, CreateObjectFunction> InjectedWindowAttributes;
diff --git a/src/cobalt/browser/webapi_extension.h b/src/cobalt/browser/webapi_extension.h new file mode 100644 index 0000000..30a977e --- /dev/null +++ b/src/cobalt/browser/webapi_extension.h
@@ -0,0 +1,53 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef COBALT_BROWSER_WEBAPI_EXTENSION_H_ +#define COBALT_BROWSER_WEBAPI_EXTENSION_H_ + +#include <string> + +#include "base/memory/ref_counted.h" +#include "base/optional.h" +#include "cobalt/dom/window.h" +#include "cobalt/script/global_environment.h" +#include "cobalt/script/wrappable.h" + +namespace cobalt { +namespace browser { + +// This file declares the interface that Cobalt calls in order to possibly +// inject external functionality into the web app's JavaScript environment. +// See cobalt/doc/webapi_extension.md for more information. + +// The implementation of this function should return the name of the property +// to be injected into to the JavaScript window object. If base::nullopt is +// returned, then CreateWebExtensionObject() will not be subsequently called +// and nothing will be injected. +base::optional<std::string> GetWebAPIExtensionObjectPropertyName(); + +// The actual object that will be assigned to the window property with name +// given by *GetWebExtensionObjectPropertyName(). The returned object should +// be specified by an IDL interface. It is passed a reference to |window| +// so that it can access and introspect any properties of the window object. +// It is passed |global_environment| so that it can access functions of the +// GlobalEnvironment interface, such as using it to execute arbitrary +// JavaScript. +scoped_refptr<script::Wrappable> CreateWebAPIExtensionObject( + const scoped_refptr<dom::Window>& window, + script::GlobalEnvironment* global_environment); + +} // namespace browser +} // namespace cobalt + +#endif // COBALT_BROWSER_WEBAPI_EXTENSION_H_
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id index cf4e0e6..e6c9c94 100644 --- a/src/cobalt/build/build.id +++ b/src/cobalt/build/build.id
@@ -1 +1 @@ -84472 \ No newline at end of file +88774 \ No newline at end of file
diff --git a/src/cobalt/build/build_config.h b/src/cobalt/build/build_config.h index bfe3df5..e743e5f 100644 --- a/src/cobalt/build/build_config.h +++ b/src/cobalt/build/build_config.h
@@ -50,4 +50,12 @@ #endif // COBALT_MEDIA_BUFFER_VIDEO_BUDGET_4K < // COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P +#if COBALT_ENCRYPTED_MEDIA_EXTENSION_ENABLE_KEY_STATUSES_UPDATE +#if SB_API_VERSION < SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION +#error COBALT_ENCRYPTED_MEDIA_EXTENSION_ENABLE_KEY_STATUSES_UPDATE requires \ + that SB_API_VERSION is greater than or equal to \ + SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION +#endif // SB_API_VERSION < SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION +#endif // COBALT_ENCRYPTED_MEDIA_EXTENSION_ENABLE_KEY_STATUSES_UPDATE + #endif // COBALT_BUILD_BUILD_CONFIG_H_
diff --git a/src/cobalt/build/cobalt_build_id.gni b/src/cobalt/build/cobalt_build_id.gni new file mode 100644 index 0000000..f6d248b --- /dev/null +++ b/src/cobalt/build/cobalt_build_id.gni
@@ -0,0 +1,17 @@ +# Copyright 2017 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. + +# Cobalt build id. +# TODO: ensure that this is updated after a new source revision is pulled down +cobalt_build_id = exec_script("get_build_id.py", "value")
diff --git a/src/cobalt/build/config/BUILD.gn b/src/cobalt/build/config/BUILD.gn new file mode 100644 index 0000000..f0af403 --- /dev/null +++ b/src/cobalt/build/config/BUILD.gn
@@ -0,0 +1,181 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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. + +import("//cobalt/build/config/base.gni") + +# TODO: split out into relevant subdirectories +config("compiler_defaults") { + if (cobalt_media_buffer_pool_allocate_on_demand) { + allocate_on_demand = 1 + } else { + allocate_on_demand = 0 + } + + if (cobalt_encrypted_media_extension_enable_key_statuses_update) { + enable_key_statuses_update = 1 + } else { + enable_key_statuses_update = 0 + } + + defines = [ + "COBALT", + "COBALT_MEDIA_BUFFER_POOL_ALLOCATE_ON_DEMAND=$allocate_on_demand", + "COBALT_MEDIA_BUFFER_INITIAL_CAPACITY=$cobalt_media_buffer_initial_capacity", + "COBALT_MEDIA_BUFFER_ALLOCATION_UNIT=$cobalt_media_buffer_allocation_unit", + "COBALT_MEDIA_BUFFER_ALIGNMENT=$cobalt_media_buffer_alignment", + "COBALT_MEDIA_BUFFER_PADDING=$cobalt_media_buffer_padding", + "COBALT_MEDIA_BUFFER_PROGRESSIVE_BUDGET=$cobalt_media_buffer_progressive_budget", + "COBALT_MEDIA_BUFFER_NON_VIDEO_BUDGET=$cobalt_media_buffer_non_video_budget", + "COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P=$cobalt_media_buffer_video_budget_1080p", + "COBALT_MEDIA_BUFFER_VIDEO_BUDGET_4K=$cobalt_media_buffer_video_budget_4k", + "COBALT_ENCRYPTED_MEDIA_EXTENSION_ENABLE_KEY_STATUSES_UPDATE=$enable_key_statuses_update", + + # From common.gypi + "USE_OPENSSL=1", + ] + + include_dirs = [ "//" ] + + if (cobalt_use_media_source_2016) { + defines += [ "COBALT_MEDIA_SOURCE_2016=1" ] + } else { + defines += [ "COBALT_MEDIA_SOURCE_2012=1" ] + } + + if (cobalt_media_buffer_storage_type == "memory") { + defines += [ "COBALT_MEDIA_BUFFER_STORAGE_TYPE_MEMORY=1" ] + } else { + defines += [ "COBALT_MEDIA_BUFFER_STORAGE_TYPE_FILE=1" ] + } + + if (enable_in_app_dial) { + defines += [ "DIAL_SERVER" ] + } + + if (enable_file_scheme) { + defines += [ "COBALT_ENABLE_FILE_SCHEME" ] + } + + if (!enable_spdy) { + defines += [ "COBALT_DISABLE_SPDY" ] + } +} + +config("final_executable_target_config") { + # XXX: ideally this config would only apply when we are compiling targets + # for the target platform. We try to check for that here, however, this check + # is ineffective when default_toolchain happens to be the same as + # host_toolchain. + # Therefore, **targets which should be compiled for the host must remove this + # config from their list of configs.** + if (current_toolchain == default_toolchain && + final_executable_type == "shared_library") { + defines = [ + # Rewrite main() functions into StarboardMain. TODO: This is a + # hack, it would be better to be more surgical, here. + "main=StarboardMain", + ] + + cflags = [ + # To link into a shared library on Linux and similar platforms, + # the compiler must be told to generate Position Independent Code. + # This appears to cause errors when linking the code statically, + # however. + "-fPIC", + ] + } +} + +config("compiler_defaults_debug") { + defines = [ + "ALLOCATOR_STATS_TRACKING", + "COBALT_BOX_DUMP_ENABLED", + "COBALT_BUILD_TYPE_DEBUG", + "COBALT_ENABLE_JAVASCRIPT_ERROR_LOGGING", + "COBALT_SECURITY_SCREEN_CLEAR_TO_UGLY_COLOR", + "_DEBUG", + "ENABLE_DEBUG_COMMAND_LINE_SWITCHES", + "ENABLE_DEBUG_C_VAL", + "ENABLE_DEBUG_CONSOLE", + "ENABLE_DIR_SOURCE_ROOT_ACCESS", + "ENABLE_IGNORE_CERTIFICATE_ERRORS", + "ENABLE_PARTIAL_LAYOUT_CONTROL", + "ENABLE_TEST_RUNNER", + "__LB_SHELL__ENABLE_SCREENSHOT__", + "__LB_SHELL__FORCE_LOGGING__", # TODO: Rename to COBALT_LOGGING_ENABLED. + "SK_DEVELOPER", + ] +} + +config("compiler_defaults_devel") { + defines = [ + "_DEBUG", + "ALLOCATOR_STATS_TRACKING", + "COBALT_BUILD_TYPE_DEVEL", + "COBALT_ENABLE_JAVASCRIPT_ERROR_LOGGING", + "COBALT_SECURITY_SCREEN_CLEAR_TO_UGLY_COLOR", + "ENABLE_DEBUG_COMMAND_LINE_SWITCHES", + "ENABLE_DEBUG_C_VAL", + "ENABLE_DEBUG_CONSOLE", + "ENABLE_DIR_SOURCE_ROOT_ACCESS", + "ENABLE_IGNORE_CERTIFICATE_ERRORS", + "ENABLE_PARTIAL_LAYOUT_CONTROL", + "ENABLE_TEST_RUNNER", + "__LB_SHELL__ENABLE_SCREENSHOT__", + "__LB_SHELL__FORCE_LOGGING__", + "SK_DEVELOPER", + ] +} + +config("compiler_defaults_qa") { + defines = [ + "ALLOCATOR_STATS_TRACKING", + "COBALT_BUILD_TYPE_QA", + "COBALT_ENABLE_JAVASCRIPT_ERROR_LOGGING", + "COBALT_SECURITY_SCREEN_CLEAR_TO_UGLY_COLOR", + "ENABLE_DEBUG_COMMAND_LINE_SWITCHES", + "ENABLE_DEBUG_C_VAL", + "ENABLE_DEBUG_CONSOLE", + "ENABLE_DIR_SOURCE_ROOT_ACCESS", + "ENABLE_IGNORE_CERTIFICATE_ERRORS", + "ENABLE_PARTIAL_LAYOUT_CONTROL", + "ENABLE_TEST_RUNNER", + "__LB_SHELL__ENABLE_SCREENSHOT__", + "__LB_SHELL__FOR_QA__", + "NDEBUG", + ] +} + +config("compiler_defaults_gold") { + defines = [ + "ALLOCATOR_STATS_TRACKING", + "COBALT_BUILD_TYPE_GOLD", + "COBALT_FORCE_CSP", + "COBALT_FORCE_HTTPS", + "__LB_SHELL__FOR_RELEASE__", + "NDEBUG", + "TRACING_DISABLED", + ] +} + +config("chromium_code") { + defines = [ + "__STDC_CONSTANT_MACROS", + "__STDC_FORMAT_MACROS", + ] +}
diff --git a/src/cobalt/build/config/BUILDCONFIG.gn b/src/cobalt/build/config/BUILDCONFIG.gn new file mode 100644 index 0000000..9b8796e --- /dev/null +++ b/src/cobalt/build/config/BUILDCONFIG.gn
@@ -0,0 +1,203 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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. + +# ============================================================================= +# WHAT IS THIS FILE? +# ============================================================================= +# +# This is the master GN build configuration. This file is loaded after the +# build args (args.gn) for the build directory and after the toplevel ".gn" +# file (which points to this file as the build configuration). +# +# This file will be executed and the resulting context will be used to execute +# every other file in the build. So variables declared here (that don't start +# with an underscore) will be implicitly global. Note that unlike in GYP, in +# GN the practice is to limit the number of global variables and define +# variables in .gni files instead. +# +# YOU SHOULD ALMOST NEVER NEED TO ADD FLAGS TO THIS FILE. GN allows any file in +# the build to declare build flags. +# +# - If you want to add a new per-platform variable (e.g. javascript_engine, +# enable_map_to_mesh, etc.), add that to //cobalt/build/config/base.gni or +# //starboard/build/config/base.gni. +# +# - If you want to add an actual build arg (i.e. something a developer would +# specify at compile time, such as cobalt_use_fastbuild or use_asan): +# +# - If your build arg will only be used in a single target, say //cobalt/foo, +# you can put a declare_args() block in //cobalt/foo/BUILD.gn and use it +# there. Nobody else in the build needs to see the flag. +# +# - Otherwise, you can put the argument in a .gni file. This should be put in +# the lowest level of the build that knows about this feature (which should +# almost always be outside of "build" directories!). +# +# - If your flag toggles a target on and off or toggles between different +# versions of similar things, write a "group" target that forwards to the +# right target (or no target) depending on the value of the build flag. This +# group can be in the same BUILD.gn file as the build flag, and targets can +# depend unconditionally on the group rather than duplicating flag checks +# across many targets. + +# ============================================================================= +# PLATFORM SELECTION +# ============================================================================= +# +# There are two main things to set: "cobalt_config" and "target_platform". +# These are set via `gn args`. The starboard platform path is then calculated +# from target_platform. Finally, we import a file containing platform-specific +# configuration (such as the default toolchain and target OS/architecture) that +# must be set in BUILDCONFIG.gn. + +declare_args() { + # The current build configuration. + cobalt_config = "gold" + + # The platform we are building for. + target_platform = "" +} +assert(target_platform != "", "You must specify a target platform") + +# The relative path from // to the directory containing the +# BUILD.gn file defining the starboard_platform target +starboard_path = rebase_path(exec_script("//cobalt/build/get_starboard_path.py", + [ target_platform ], + "trim string"), + "//") + +# Import platform-specific build config variables +import("//$starboard_path/buildconfig.gni") + +# ============================================================================= +# THE TARGET OS AND ARCHITECTURE +# ============================================================================= +# +# GN has three families of built in variables: +# - host_os, host_cpu, host_toolchain +# - target_os, target_cpu, default_toolchain +# - current_os, current_cpu, current_toolchain. +# +# There are three different types of each of these things: The "host" +# represents the computer doing the compile and never changes. The "target" +# represents the main thing we're trying to build. The "current" represents +# which configuration is currently being defined, which can be either the +# host, the target, or even (in theory) something completely different. GN will +# run the same build file multiple times for the different required +# configuration in the same build. +# +# Note the default_toolchain isn't symmetrical (you would expect +# target_toolchain). This is because the "default" toolchain is a GN built-in +# concept, and "target" is something our build sets up that's symmetrical with +# its GYP counterpart. Potentially the built-in default_toolchain variable +# could be renamed in the future. +# +# When writing build files, to do something only for the host: +# if (current_toolchain == host_toolchain) { ... + +if (defined(target_os_)) { + target_os = target_os_ +} else { + target_os = "unknown" +} +target_cpu = target_cpu_ + +if (current_os == "") { + current_os = target_os +} +if (current_cpu == "") { + current_cpu = target_cpu +} + +# ============================================================================= +# TARGET DEFAULTS +# ============================================================================= +# +# Set up the default configuration for every build target of the given type. +# The values configured here will be automatically set on the scope of the +# corresponding target. Target definitions can add or remove to the settings +# here as needed. + +# All binary targets will get this list of configs by default. +_shared_binary_target_configs = [ + "//cobalt/build/config:compiler_defaults", + "//cobalt/build/config:compiler_defaults_$cobalt_config", + + "//starboard/build/config:compiler_defaults", + "//$starboard_path:compiler_defaults", + "//$starboard_path:compiler_defaults_$cobalt_config", + + "//cobalt/build/config:final_executable_target_config", + + "//starboard/build/config:no_pedantic_warnings", + "//starboard/build/config:default_rtti", + "//starboard/build/config:default_optimizations", +] + +# Apply that default list to the binary target types. +set_defaults("executable") { + configs = _shared_binary_target_configs +} +set_defaults("static_library") { + configs = _shared_binary_target_configs +} +set_defaults("shared_library") { + configs = _shared_binary_target_configs +} +set_defaults("source_set") { + configs = _shared_binary_target_configs +} + +# ============================================================================= +# TARGET TYPE SETUP +# ============================================================================= + +# Define some additional target types. These are useful on platforms where the +# native code may require an additional packaging step (ex. Android). + +if (!defined(test_target_type)) { + test_target_type = "executable" +} +template("test") { + target(test_target_type, target_name) { + # Explicitly forward visibility, implicitly forward everything else. + # Forwarding "*" doesn't recurse into nested scopes (to avoid copying all + # globals into each template invocation), so won't pick up file-scoped + # variables. Normally this isn't too bad, but visibility is commonly + # defined at the file scope. Explicitly forwarding visibility and then + # excluding it from the "*" set works around this problem. + # See http://crbug.com/594610 + forward_variables_from(invoker, [ "visibility" ]) + forward_variables_from(invoker, "*", [ "visibility" ]) + } +} + +if (!defined(final_executable_type)) { + final_executable_type = "executable" +} +template("final_executable") { + target(final_executable_type, target_name) { + # See comment above + forward_variables_from(invoker, [ "visibility" ]) + forward_variables_from(invoker, "*", [ "visibility" ]) + } +} + +# Set the default toolchain and the host toolchain +set_default_toolchain(target_toolchain) +assert(defined(host_toolchain))
diff --git a/src/cobalt/build/config/base.gni b/src/cobalt/build/config/base.gni new file mode 100644 index 0000000..21e6bef --- /dev/null +++ b/src/cobalt/build/config/base.gni
@@ -0,0 +1,581 @@ +# Copyright 2017 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. + +# Import platform-specific defaults +import("//$starboard_path/configuration.gni") +# Import starboard variables +import("//starboard/build/config/base.gni") + +# Cobalt variables. + +# Enable support for the map to mesh filter, which is primarily used to +# implement spherical video playback. +if (!defined(enable_map_to_mesh)) { + enable_map_to_mesh = false +} + +# This variable defines what Cobalt's preferred strategy should be for +# handling internally triggered application exit requests (e.g. the user +# chooses to back out of the application). +# "stop" -- The application should call SbSystemRequestStop() on exit, +# resulting in a complete shutdown of the application. +# "suspend" -- The application should call SbSystemRequestSuspend() on +# exit, resulting in the application being "minimized". +# "noexit" -- The application should never allow the user to trigger an +# exit, this will be managed by the system. +if (!defined(cobalt_user_on_exit_strategy)) { + cobalt_user_on_exit_strategy = "stop" +} + +# Contains the current font package selection. This can be used to trade +# font quality, coverage, and latency for different font package sizes. +# The font package can be one of the following options: +# "expanded" -- The largest package. It includes everything in the +# 'standard' package, along with 'bold' weight CJK. It is +# recommended that 'local_font_cache_size_in_bytes' be +# increased to 24MB when using this package to account for +# the extra memory required by bold CJK. This package is +# ~48.7MB. +# "standard" -- The default package. It includes all sans-serif, serif, +# and FCC fonts, non-CJK fallback fonts in both 'normal' and +# 'bold' weights, and 'normal' weight CJK ('bold' weight CJK +# is synthesized from it). This package is ~29.4MB. +# "limited_with_jp" -- A significantly smaller package than 'standard'. +# This package removes all but 'normal' and 'bold' weighted +# sans-serif and serif, removes the FCC fonts (which must be +# provided by the system or downloaded from the web), +# removes the 'bold' weighted non-CJK fallback fonts (the +# 'normal' weight is still included and is used to +# synthesize bold), and replaces standard CJK with low +# quality CJK. However, higher quality Japanese is still +# included. Because low quality CJK cannot synthesize bold, +# bold glyphs are unavailable in Chinese and Korean. This +# package is ~10.9MB. +# "limited" -- A smaller package than 'limited_with_jp'. The two packages +# are identical with the exception that 'limited' does not +# include the higher quality Japanese font; instead it +# relies on low quality CJK for all CJK characters. Because +# low quality CJK cannot synthesize bold, bold glyphs are +# unavailable in Chinese, Japanese, and Korean. This package +# is ~7.7MB. +# "minimal" -- The smallest possible font package. It only includes +# Roboto's Basic Latin characters. Everything else must be +# provided by the system or downloaded from the web. This +# package is ~16.4KB. +# NOTE: When bold is needed, but unavailable, it is typically synthesized, +# resulting in lower quality glyphs than those generated directly from +# a bold font. However, this does not occur with low quality CJK, +# which is not high enough quality to synthesize. Its glyphs always +# have a 'normal' weight. +if (!defined(cobalt_font_package)) { + cobalt_font_package = "standard" +} + +# Font package overrides can be used to modify the files included within the +# selected package. The following values are available: +# -1 -- The package value for the specified category is not overridden. +# 0 -- The package value is overridden and no fonts for the specified +# category are included. +# 1 -- The package value is overridden and fonts from the specified +# category with a weight of 'normal' and a style of 'normal' are +# included. +# 2 -- The package value is overridden and fonts from the specified +# category with a weight of either 'normal' or bold' and a style of +# 'normal' are included. +# 3 -- The package value is overridden and fonts from the specified +# category with a weight of either 'normal' or 'bold' and a style of +# either 'normal' or 'italic' are included. +# 4 -- The package value is overridden and all available fonts from the +# specified category are included. This may include additional +# weights beyond 'normal' and 'bold'. +# See content/fonts/README.md for details on the specific values used by +# each of the packages use for the various font categories. +if (!defined(cobalt_font_package_override_named_sans_serif)) { + cobalt_font_package_override_named_sans_serif = -1 +} +if (!defined(cobalt_font_package_override_named_serif)) { + cobalt_font_package_override_named_serif = -1 +} +if (!defined(cobalt_font_package_override_named_fcc_fonts)) { + cobalt_font_package_override_named_fcc_fonts = -1 +} +if (!defined(cobalt_font_package_override_fallback_lang_non_cjk)) { + cobalt_font_package_override_fallback_lang_non_cjk = -1 +} +if (!defined(cobalt_font_package_override_fallback_lang_cjk)) { + cobalt_font_package_override_fallback_lang_cjk = -1 +} +if (!defined(cobalt_font_package_override_fallback_lang_cjk_low_quality)) { + cobalt_font_package_override_fallback_lang_cjk_low_quality = -1 +} +if (!defined(cobalt_font_package_override_fallback_lang_jp)) { + cobalt_font_package_override_fallback_lang_jp = -1 +} +if (!defined(cobalt_font_package_override_fallback_emoji)) { + cobalt_font_package_override_fallback_emoji = -1 +} +if (!defined(cobalt_font_package_override_fallback_symbols)) { + cobalt_font_package_override_fallback_symbols = -1 +} + +# The target platform id as a string, like "ps4", etc.. +# TODO: eliminate when all platforms are fully starboard. +if (!defined(sb_target_platform)) { + sb_target_platform = "" +} + +# Defines what kind of rasterizer will be used. This can be adjusted to +# force a stub graphics implementation or software graphics implementation. +# It can be one of the following options: +# 'direct-gles' -- Uses a light wrapper over OpenGL ES to handle most +# draw elements. This will fall back to the skia hardware +# rasterizer for some render tree node types, but is +# generally faster on the CPU and GPU. This can handle +# 360 rendering. +# 'hardware' -- As much hardware acceleration of graphics commands as +# possible. This uses skia to wrap OpenGL ES commands. +# Required for 360 rendering. +# 'software' -- Perform most rasterization using the CPU and only +# interact with the GPU to send the final image to the +# output window. +# 'stub' -- Stub graphics rasterization. A rasterizer object will +# still be available and valid, but it will do nothing. +if (!defined(rasterizer_type)) { + rasterizer_type = "hardware" +} + +# If set to true, will enable support for rendering only the regions of the +# display that are modified due to animations, instead of re-rendering the +# entire scene each frame. This feature can reduce startup time where +# usually there is a small loading spinner animating on the screen. On GLES +# renderers, Cobalt will attempt to implement this support by using +# eglSurfaceAttrib(..., EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED), otherwise +# the dirty region will be silently disabled. On Blitter API platforms, +# if this is enabled, we explicitly create an extra offscreen full-size +# intermediate surface to render into. Note that some GLES driver +# implementations may internally allocate an extra full screen surface to +# support this feature, and many have been noticed to not properly support +# this functionality (but they report that they do), and for these reasons +# this value is defaulted to false. +if (!defined(render_dirty_region_only)) { + render_dirty_region_only = false +} + +# Modify this value to adjust the default rasterizer setting for your +# platform. +if (!defined(default_renderer_options_dependency)) { + default_renderer_options_dependency = "//cobalt/renderer:default_options" +} + +# Allow throttling of the frame rate. This is expressed in terms of +# milliseconds and can be a floating point number. Keep in mind that +# swapping frames may take some additional processing time, so it may be +# better to specify a lower delay. For example, "33" instead of "33.33" +# for 30 Hz refresh. +if (!defined(cobalt_minimum_frame_time_in_milliseconds)) { + cobalt_minimum_frame_time_in_milliseconds = "16.4" +} + +# Cobalt will call eglSwapInterval() and specify this value before calling +# eglSwapBuffers() each frame. +if (!defined(cobalt_egl_swap_interval)) { + cobalt_egl_swap_interval = 1 +} + +# Set to true to build with DIAL support. +if (!defined(enable_in_app_dial)) { + enable_in_app_dial = false +} + +# Set to true to enable a custom MediaSessionClient. +if (!defined(enable_custom_media_session_client)) { + enable_custom_media_session_client = false +} + +# Set to true to enable H5vccAccountManager. +if (!defined(enable_account_manager)) { + enable_account_manager = false +} + +# Set to true to enable H5vccCrashLog. +if (!defined(enable_crash_log)) { + enable_crash_log = false +} + +# Set to true to enable H5vccSSO (Single Sign On). +if (!defined(enable_sso)) { + enable_sso = false +} + +# Set to true to compile with SPDY support. +if (!defined(enable_spdy)) { + enable_spdy = false +} + +# Set to true to enable filtering of HTTP headers before sending. +if (!defined(enable_xhr_header_filtering)) { + enable_xhr_header_filtering = false +} + +# Used by //cobalt/media to pick a proper media platform. +if (!defined(sb_media_platform)) { + sb_media_platform = "starboard" +} + +# List of platform-specific targets that get compiled into cobalt. +if (!defined(cobalt_platform_dependencies)) { + cobalt_platform_dependencies = [] +} + +# The URL of default build time splash screen - see +# cobalt/doc/splash_screen.md for information about this. +if (!defined(fallback_splash_screen_url)) { + fallback_splash_screen_url = "h5vcc-embedded://youtube_splash_screen.html" +} + +# Cache parameters + +# The following set of parameters define how much memory is reserved for +# different Cobalt caches. These caches affect CPU *and* GPU memory usage. +# +# The sum of the following caches effectively describes the maximum GPU +# texture memory usage (though it doesn't consider video textures and +# display color buffers): +# - skia_cache_size_in_bytes (GLES2 rasterizer only) +# - scratch_surface_cache_size_in_bytes +# - surface_cache_size_in_bytes +# - image_cache_size_in_bytes +# - skia_glyph_atlas_width * skia_glyph_atlas_height +# +# The other caches affect CPU memory usage. + +# Determines the capacity of the skia cache. The Skia cache is maintained +# within Skia and is used to cache the results of complicated effects such +# as shadows, so that Skia draw calls that are used repeatedly across +# frames can be cached into surfaces. This setting is only relevant when +# using the hardware-accelerated Skia rasterizer (e.g. as opposed to the +# Blitter API). +if (!defined(skia_cache_size_in_bytes)) { + skia_cache_size_in_bytes = "(4 * 1024 * 1024)" +} + +# Determines the capacity of the scratch surface cache. The scratch +# surface cache facilitates the reuse of temporary offscreen surfaces +# within a single frame. This setting is only relevant when using the +# hardware-accelerated Skia rasterizer. +if (!defined(scratch_surface_cache_size_in_bytes)) { + scratch_surface_cache_size_in_bytes = 0 +} + +# Determines the capacity of the surface cache. The surface cache tracks +# which render tree nodes are being re-used across frames and stores the +# nodes that are most CPU-expensive to render into surfaces. +if (!defined(surface_cache_size_in_bytes)) { + surface_cache_size_in_bytes = 0 +} + +# Determines the amount of GPU memory the offscreen target atlases will +# use. This is specific to the direct-GLES rasterizer and serves a similar +# purpose as the surface_cache_size_in_bytes, but caches any render tree +# nodes which require skia for rendering. Two atlases will be allocated +# from this memory or multiple atlases of the frame size if the limit +# allows. It is recommended that enough memory be reserved for two RGBA +# atlases about a quarter of the frame size. +if (!defined(offscreen_target_cache_size_in_bytes)) { + offscreen_target_cache_size_in_bytes = -1 +} + +# Determines the capacity of the image cache, which manages image surfaces +# downloaded from a web page. While it depends on the platform, often (and +# ideally) these images are cached within GPU memory. +# Set to -1 to automatically calculate the value at runtime, based on +# features like windows dimensions and the value of +# SbSystemGetTotalGPUMemory(). +if (!defined(image_cache_size_in_bytes)) { + image_cache_size_in_bytes = -1 +} + +# Determines the capacity of the local font cache, which manages all fonts +# loaded from local files. Newly encountered sections of font files are +# lazily loaded into the cache, enabling subsequent requests to the same +# file sections to be handled via direct memory access. Once the limit is +# reached, further requests are handled via file stream. +# Setting the value to 0 disables memory caching and causes all font file +# accesses to be done using file streams. +if (!defined(local_font_cache_size_in_bytes)) { + local_font_cache_size_in_bytes = "(16 * 1024 * 1024)" +} + +# Determines the capacity of the remote font cache, which manages all +# fonts downloaded from a web page. +if (!defined(remote_font_cache_size_in_bytes)) { + remote_font_cache_size_in_bytes = "(4 * 1024 * 1024)" +} + +# Determines the capacity of the mesh cache. Each mesh is held compressed +# in main memory, to be inflated into a GPU buffer when needed for +# projection. When set to "auto", will be adjusted according to whether +# the enable_map_to_mesh is true or not. If enable_map_to_mesh is false, +# then the mesh cache size will be set to 0. +if (!defined(mesh_cache_size_in_bytes)) { + mesh_cache_size_in_bytes = "auto" +} + +# Only relevant if you are using the Blitter API. +# Determines the capacity of the software surface cache, which is used to +# cache all surfaces that are rendered via a software rasterizer to avoid +# re-rendering them. +if (!defined(software_surface_cache_size_in_bytes)) { + software_surface_cache_size_in_bytes = "(8 * 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. +if (!defined(image_cache_capacity_multiplier_when_playing_video)) { + image_cache_capacity_multiplier_when_playing_video = "1.0f" +} + +# Determines the size in pixels of the glyph atlas where rendered glyphs are +# cached. The resulting memory usage is 2 bytes of GPU memory per pixel. +# When a value is used that is too small, thrashing may occur that will +# result in visible stutter. Such thrashing is more likely to occur when CJK +# language glyphs are rendered and when the size of the glyphs in pixels is +# larger, such as for higher resolution displays. +# The negative default values indicates to the engine that these settings +# should be automatically set. +if (!defined(skia_glyph_atlas_width)) { + skia_glyph_atlas_width = "-1" +} +if (!defined(skia_glyph_atlas_height)) { + skia_glyph_atlas_height = "-1" +} + +# Determines the size of garbage collection threshold. After this many bytes +# have been allocated, the mozjs garbage collector will run. Lowering this +# has been found to reduce performance and decrease JavaScript memory usage. +# For example, we have measured on at least one platform that performance +# becomes 7% worse on average in certain cases when adjusting this number +# from 8MB to 1MB. +if (!defined(mozjs_garbage_collection_threshold_in_bytes)) { + mozjs_garbage_collection_threshold_in_bytes = "(8 * 1024 * 1024)" +} + +# Max Cobalt CPU usage specifies that the cobalt program should +# keep it's size below the specified size. A value of -1 causes this +# value to be assumed from the starboard API function: +# SbSystemGetTotalCPUMemory(). +if (!defined(max_cobalt_cpu_usage)) { + max_cobalt_cpu_usage = -1 +} + +if (!defined(max_cobalt_gpu_usage)) { + # Max Cobalt GPU usage specifies that the cobalt program should + # keep it's size below the specified size. A value of -1 causes this + # value to be assumed from the starboard API function: + # SbSystemGetTotalGPUMemory(). + max_cobalt_gpu_usage = -1 +} + +# When specified this value will reduce the cpu memory consumption by +# the specified amount. -1 disables the value. +# When this value is specified then max_cobalt_cpu_usage will not be +# used in memory_constrainer, but will still be used for triggering +# a warning if the engine consumes more memory than this value specifies. +if (!defined(reduce_cpu_memory_by)) { + reduce_cpu_memory_by = -1 +} + +# When specified this value will reduce the gpu memory consumption by +# the specified amount. -1 disables the value. +# When this value is specified then max_cobalt_gpu_usage will not be +# used in memory_constrainer, but will still be used for triggering +# a warning if the engine consumes more memory than this value specifies. +if (!defined(reduce_gpu_memory_by)) { + reduce_gpu_memory_by = -1 +} + +# The only currently-supported Javascript engine is "mozjs-45". (However, +# this may potentially change in the future.) +if (!defined(javascript_engine)) { + javascript_engine = "mozjs-45" +} + +# Enable jit instead of running in interpreter-only mode by default. +# We have found that disabling jit often results in faster JavaScript +# execution and lower memory usage. +# Setting this to true on a platform or engine for which there is no JIT +# implementation has no effect. +if (!defined(cobalt_enable_jit)) { + cobalt_enable_jit = false +} + +# Use media source extension implementation that is conformed to the +# Candidate Recommandation of July 5th 2016. +if (!defined(cobalt_use_media_source_2016)) { + cobalt_use_media_source_2016 = true +} + +# Note that the following media buffer related variables are only used when +# |cobalt_use_media_source_2016| is set to true. + +# This can be set to "memory" or "file". When it is set to "memory", the +# media buffers will be stored in main memory allocated by SbMemory +# functions. When it is set to "file", the media buffers will be stored in +# a temporary file in the system cache folder acquired by calling +# SbSystemGetPath() with "kSbSystemPathCacheDirectory". Note that when its +# value is "file" the media stack will still allocate memory to cache the +# the buffers in use. +if (!defined(cobalt_media_buffer_storage_type)) { + cobalt_media_buffer_storage_type = "memory" +} +# When either |cobalt_media_buffer_initial_capacity| or +# |cobalt_media_buffer_allocation_unit| isn't zero, media buffers will be +# allocated using a memory pool. Set the following variable to true to +# allocate the media buffer pool memory on demand and return all memory to +# the system when there is no media buffer allocated. Setting the following +# value to false results in that Cobalt will allocate +# |cobalt_media_buffer_initial_capacity| bytes for media buffer on startup +# and will not release any media buffer memory back to the system even if +# there is no media buffers allocated. +if (!defined(cobalt_media_buffer_pool_allocate_on_demand)) { + cobalt_media_buffer_pool_allocate_on_demand = true +} +# The amount of memory that will be used to store media buffers allocated +# during system startup. To allocate a large chunk at startup helps with +# reducing fragmentation and can avoid failures to allocate incrementally. +# This can be set to 0. +if (!defined(cobalt_media_buffer_initial_capacity)) { + cobalt_media_buffer_initial_capacity = "(21 * 1024 * 1024)" +} +# When the media stack needs more memory to store media buffers, it will +# allocate extra memory in units of |cobalt_media_buffer_allocation_unit|. +# This can be set to 0, in which case the media stack will allocate extra +# memory on demand. When |cobalt_media_buffer_initial_capacity| and this +# value are both set to 0, the media stack will allocate individual buffers +# directly using SbMemory functions. +if (!defined(cobalt_media_buffer_allocation_unit)) { + cobalt_media_buffer_allocation_unit = "(1 * 1024 * 1024)" +} + +# The media buffer will be allocated using the following alignment. Set +# this to a larger value may increase the memory consumption of media +# buffers. +if (!defined(cobalt_media_buffer_alignment)) { + cobalt_media_buffer_alignment = 0 +} +# Extra bytes allocated at the end of a media buffer to ensure that the +# buffer can be use optimally by specific instructions like SIMD. Set to 0 +# to remove any padding. +if (!defined(cobalt_media_buffer_padding)) { + cobalt_media_buffer_padding = 0 +} + +# The memory used when playing mp4 videos that is not in DASH format. The +# resolution of such videos shouldn't go beyond 1080p. Its value should be +# less than the sum of 'cobalt_media_buffer_non_video_budget' and +# 'cobalt_media_buffer_video_budget_1080p' but not less than 8 MB. +if (!defined(cobalt_media_buffer_progressive_budget)) { + cobalt_media_buffer_progressive_budget = "(12 * 1024 * 1024)" +} + +# Specifies the maximum amount of memory used by audio or text buffers of +# media source before triggering a garbage collection. A large value will +# cause more memory being used by audio buffers but will also make +# JavaScript app less likely to re-download audio data. Note that the +# JavaScript app may experience significant difficulty if this value is too +# low. +if (!defined(cobalt_media_buffer_non_video_budget)) { + cobalt_media_buffer_non_video_budget = "(5 * 1024 * 1024)" +} + +# Specifies the maximum amount of memory used by video buffers of media +# source before triggering a garbage collection when the video resolution is +# lower than 1080p (1920x1080). A large value will cause more memory being +# used by video buffers but will also make JavaScript app less likely to +# re-download video data. Note that the JavaScript app may experience +# significant difficulty if this value is too low. +if (!defined(cobalt_media_buffer_video_budget_1080p)) { + cobalt_media_buffer_video_budget_1080p = "(16 * 1024 * 1024)" +} +# Specifies the maximum amount of memory used by video buffers of media +# source before triggering a garbage collection when the video resolution is +# lower than 4k (3840x2160). A large value will cause more memory being +# used by video buffers but will also make JavaScript app less likely to +# re-download video data. Note that the JavaScript app may experience +# significant difficulty if this value is too low. +if (!defined(cobalt_media_buffer_video_budget_4k)) { + cobalt_media_buffer_video_budget_4k = "(60 * 1024 * 1024)" +} + +# Set to true to enable MediaKeySession::keyStatuses and +# MediaKeySession::onkeystatuseschange support. This requires that +# SB_API_VERSION is greater than or equal to +# SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION. +if (!defined(cobalt_encrypted_media_extension_enable_key_statuses_update)) { + cobalt_encrypted_media_extension_enable_key_statuses_update = true +} + +# Enables embedding Cobalt as a shared library within another app. This +# requires a 'lib' starboard implementation for the corresponding platform. +if (!defined(cobalt_enable_lib)) { + cobalt_enable_lib = sb_enable_lib +} + +# For configurations other than Gold, set the flag that lets test data files be +# copied and carried along with the build. +# Clients must copy over all content; to avoid having to copy over extra data, +# we omit the test data +_copy_test_data = (cobalt_config != "gold" && !cobalt_enable_lib) +if (!defined(cobalt_copy_debug_console)) { + cobalt_copy_debug_console = _copy_test_data +} +if (!defined(cobalt_copy_test_data)) { + cobalt_copy_test_data = _copy_test_data +} +if (!defined(enable_about_scheme)) { + enable_about_scheme = _copy_test_data +} +if (!defined(enable_fake_microphone)) { + enable_fake_microphone = _copy_test_data +} +if (!defined(enable_file_scheme)) { + enable_file_scheme = _copy_test_data +} +if (!defined(enable_network_logging)) { + enable_network_logging = _copy_test_data +} +if (!defined(enable_remote_debugging)) { + enable_remote_debugging = _copy_test_data +} +if (!defined(enable_screenshot)) { + enable_screenshot = _copy_test_data +} +if (!defined(enable_webdriver)) { + enable_webdriver = _copy_test_data +} + + +# Use system libjpeg. +if (!defined(use_system_libjpeg)) { + use_system_libjpeg = false +} + +# TODO: add ARM compilation flags to the starboard platform config + +# TODO: implement remaining flags like clang_type_profiler, build_for_tool, order_profiling, etc.
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi index 0f974b5..a3243c1 100644 --- a/src/cobalt/build/config/base.gypi +++ b/src/cobalt/build/config/base.gypi
@@ -12,12 +12,31 @@ # See the License for the specific language governing permissions and # limitations under the License. +##################################################################### +# If you modify this file, PLEASE REMEMBER TO UPDATE +# //cobalt/build/config/base.gni or //starboard/build/config/base.gni +# AS WELL +##################################################################### + # This file should be included in all .gyp files used by Cobalt. Normally, # this should be done automatically by gyp_cobalt. { 'variables': { # Cobalt variables. + # We need to define some variables inside of an inner 'variables' scope + # so that they can be referenced by other outer variables here. Also, it + # allows for the specification of default values that get referenced by + # a top level scope. + 'variables': { + # 'sb_enable_lib' is initially defined inside this inner 'variables' dict so + # that it can be accessed by 'cobalt_enable_lib' below. + 'sb_enable_lib%': 0, + + 'cobalt_webapi_extension_source_idl_files%': [], + 'cobalt_webapi_extension_generated_header_idl_files%': [], + }, + # Whether Cobalt is being built. 'cobalt': 1, @@ -33,13 +52,8 @@ # implement spherical video playback. 'enable_map_to_mesh%': 0, - # 'sb_enable_lib' is initially defined inside this inner 'variables' dict so - # that it can be accessed by 'cobalt_enable_lib' below here. - 'variables': { - # Enables embedding Cobalt as a shared library within another app. This - # requires a 'lib' starboard implementation for the corresponding platform. - 'sb_enable_lib%': 0, - }, + # Enables embedding Cobalt as a shared library within another app. This + # requires a 'lib' starboard implementation for the corresponding platform. 'sb_enable_lib%': '<(sb_enable_lib)', 'cobalt_enable_lib': '<(sb_enable_lib)', @@ -177,10 +191,31 @@ # this value is defaulted to 0. 'render_dirty_region_only%': 0, - # Modify this value to adjust the default rasterizer setting for your + # Override this value to adjust the default rasterizer setting for your # platform. 'default_renderer_options_dependency%': '<(DEPTH)/cobalt/renderer/default_options_starboard.gyp:default_options', + # Override this to inject a custom interface into Cobalt's JavaScript + # `window` global object. This implies that you will have to provide your + # own IDL files to describe that interface and all interfaces that it + # references. See cobalt/doc/webapi_extension.md for more information. + 'cobalt_webapi_extension_source_idl_files%': [ + '<@(cobalt_webapi_extension_source_idl_files)'\ + ], + # Override this to have Cobalt build IDL files that result in generated + # header files that may need to be included from other C++ source files. + # This includes, for example, IDL enumerations. See + # cobalt/doc/webapi_extension.md for more information. + 'cobalt_webapi_extension_generated_header_idl_files%': [ + '<@(cobalt_webapi_extension_generated_header_idl_files)' + ], + + # This gyp target must implement the functions defined in + # <(DEPTH)/cobalt/browser/idl_extensions.h. See + # cobalt/doc/webapi_extension.md for more information. + 'cobalt_webapi_extension_gyp_target%': + '<(DEPTH)/cobalt/browser/null_webapi_extension.gyp:null_webapi_extension', + # Allow throttling of the frame rate. This is expressed in terms of # milliseconds and can be a floating point number. Keep in mind that # swapping frames may take some additional processing time, so it may be @@ -518,6 +553,12 @@ # re-download video data. Note that the JavaScript app may experience # significant difficulty if this value is too low. 'cobalt_media_buffer_video_budget_4k%': 60 * 1024 * 1024, + + # Set to 1 to enable MediaKeySession::keyStatuses and + # MediaKeySession::onkeystatuseschange support. This requires that + # SB_API_VERSION is greater than or equal to + # SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION. + 'cobalt_encrypted_media_extension_enable_key_statuses_update%': 1, }, 'target_defaults': { @@ -544,6 +585,7 @@ 'COBALT_MEDIA_BUFFER_NON_VIDEO_BUDGET=<(cobalt_media_buffer_non_video_budget)', 'COBALT_MEDIA_BUFFER_VIDEO_BUDGET_1080P=<(cobalt_media_buffer_video_budget_1080p)', 'COBALT_MEDIA_BUFFER_VIDEO_BUDGET_4K=<(cobalt_media_buffer_video_budget_4k)', + 'COBALT_ENCRYPTED_MEDIA_EXTENSION_ENABLE_KEY_STATUSES_UPDATE=<(cobalt_encrypted_media_extension_enable_key_statuses_update)', ], 'cflags': [ '<@(compiler_flags)' ], 'ldflags': [ '<@(linker_flags)' ],
diff --git a/src/cobalt/build/get_build_id.py b/src/cobalt/build/get_build_id.py new file mode 100755 index 0000000..e2e5ad7 --- /dev/null +++ b/src/cobalt/build/get_build_id.py
@@ -0,0 +1,31 @@ +#!/usr/bin/env python +# Copyright 2017 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. + +"""Prints out the Cobalt Build ID.""" + +import os.path +import sys + +sys.path.append( + os.path.abspath( + os.path.join(os.pardir, os.pardir, 'cobalt', 'build'))) +from gyp_utils import GetBuildNumber # pylint: disable=g-import-not-at-top + + +def main(): + print GetBuildNumber() + +if __name__ == '__main__': + main()
diff --git a/src/cobalt/build/get_starboard_path.py b/src/cobalt/build/get_starboard_path.py new file mode 100755 index 0000000..1d32707 --- /dev/null +++ b/src/cobalt/build/get_starboard_path.py
@@ -0,0 +1,30 @@ +#!/usr/bin/env python +# Copyright 2017 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. + +"""Prints the path to the given starboard platform's configuration directory. +""" + +import sys + +import gyp_utils + + +def main(): + platforms = gyp_utils.GetAllPlatforms() + print platforms[sys.argv[1]].path + + +if __name__ == '__main__': + main()
diff --git a/src/cobalt/css_parser/grammar.y b/src/cobalt/css_parser/grammar.y index 6e4d467..36e8e8a 100644 --- a/src/cobalt/css_parser/grammar.y +++ b/src/cobalt/css_parser/grammar.y
@@ -6370,7 +6370,6 @@ std::string property_name = $1.ToString(); DCHECK_GT(property_name.size(), 0U); -#ifdef __LB_SHELL__FORCE_LOGGING__ // Do not warn about non-standard or non-WebKit properties. if (property_name[0] != '-') { base::AutoLock lock(non_trivial_static_fields.Get().lock); @@ -6383,7 +6382,6 @@ parser_impl->LogWarning(@1, "unsupported property " + property_name); } } -#endif // __LB_SHELL__FORCE_LOGGING__ $$ = NULL; }
diff --git a/src/cobalt/css_parser/parser.cc b/src/cobalt/css_parser/parser.cc index b8b9047..98b1521 100644 --- a/src/cobalt/css_parser/parser.cc +++ b/src/cobalt/css_parser/parser.cc
@@ -229,7 +229,6 @@ }; // TODO: Stop deduplicating warnings. -#ifdef __LB_SHELL__FORCE_LOGGING__ namespace { struct NonTrivialStaticFields { @@ -242,7 +241,6 @@ LAZY_INSTANCE_INITIALIZER; } // namespace -#endif // __LB_SHELL__FORCE_LOGGING__ ParserImpl::ParserImpl(const std::string& input, const base::SourceLocation& input_location,
diff --git a/src/cobalt/debug/debug_web_server.cc b/src/cobalt/debug/debug_web_server.cc index 76b371f..6ffd152 100644 --- a/src/cobalt/debug/debug_web_server.cc +++ b/src/cobalt/debug/debug_web_server.cc
@@ -80,21 +80,11 @@ return base::nullopt; } -std::string GetLocalIpAddress() { +base::optional<std::string> GetLocalIpAddress() { net::IPEndPoint ip_addr; -#if defined(__LB_SHELL__) - struct sockaddr_in addr = {0}; - addr.sin_family = AF_INET; - lb_get_local_ip_address(&addr.sin_addr); - bool result = - ip_addr.FromSockAddr(reinterpret_cast<sockaddr*>(&addr), sizeof(addr)); - DCHECK(result); -#elif defined(OS_STARBOARD) - -#if SB_API_VERSION >= 4 SbSocketAddress local_ip; - SbMemorySet(&(local_ip.address), 0, sizeof(local_ip.address)); - + SbMemorySet(&local_ip, 0, sizeof(local_ip)); +#if SB_API_VERSION >= 4 bool result = false; // Prefer IPv4 addresses, as they're easier to type for debugging. @@ -115,17 +105,24 @@ } } - DCHECK(result); + if (!result) { + DLOG(WARNING) << "Unable to get a local interface address."; + return base::nullopt; + } #else - SbSocketAddress sb_address; - bool result = SbSocketGetLocalInterfaceAddress(&sb_address); - DCHECK(result); - result = ip_addr.FromSbSocketAddress(&sb_address); + bool result = SbSocketGetLocalInterfaceAddress(&local_ip); + if (!result) { + DLOG(WARNING) << "Unable to get a local interface address."; + return base::nullopt; + } + + result = ip_addr.FromSbSocketAddress(&local_ip); + if (!result) { + LOG(WARNING) << "Got invalid local interface address."; + return base::nullopt; + } #endif // SB_API_VERSION >= 4 -#else -#error "Not Implemented." -#endif return ip_addr.ToStringWithoutPort(); } @@ -339,8 +336,13 @@ DCHECK(thread_checker_.CalledOnValidThread()); // Create http server - const std::string ip_addr = GetLocalIpAddress(); - factory_.reset(new net::TCPListenSocketFactory(ip_addr, port)); + const base::optional<std::string> ip_addr = GetLocalIpAddress(); + if (!ip_addr) { + DLOG(WARNING) + << "Could not get a local IP address for the debug web server."; + return; + } + factory_.reset(new net::TCPListenSocketFactory(*ip_addr, port)); server_ = new net::HttpServer(*factory_, this); std::string address;
diff --git a/src/cobalt/doc/gn_quick_start.md b/src/cobalt/doc/gn_quick_start.md new file mode 100644 index 0000000..b858afe --- /dev/null +++ b/src/cobalt/doc/gn_quick_start.md
@@ -0,0 +1,349 @@ +# GN Quick Start Guide for Cobalt + +This guide was adapted from +the [GN Quick Start Guide for Chromium][chromium-guide]. + +[chromium-guide]: https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/quick_start.md + +[TOC] + +## Running GN + +You just run `gn` from the command line. There is a script in +`depot_tools`, which is presumably in your PATH, with this name. The +script will find the binary in the source tree containing the current +directory and run it. + +## Setting up a build + +In GYP, the system would generate `<platform>_debug`, `<platform>_devel`, +`<platform>_qa` and `<platform>_gold` build directories for you and configure +them accordingly. GN doesn't do this. Instead, you set up whatever build +directory you want with whatever configuration you want. The Ninja files will be +automatically regenerated if they're out of date when you build in that +directory. + +To make a build directory: + +``` +gn gen out/my_build +``` + +## Passing build arguments + +Set build arguments on your build directory by running: + +``` +gn args out/my_build +``` + +This will bring up an editor. Type build args into that file like this: + +``` +target_platform = "linux-x64x11" +cobalt_config = "gold" +``` + +You can see the list of available arguments and their default values by +typing + +``` +gn args --list out/my_build +``` + +on the command line. Note that you have to specify the build directory +for this command because the available arguments can change according +to what's set. + +## Configuring goma + +Run `gn args out/Default` (substituting your build directory as needed). +Add: + +``` +use_goma = true +goma_dir = "~/foo/bar/goma" +``` + +If your goma is in the default location (`~/goma`) then you can omit the +`goma_dir` line. + +Currently, `use_goma` is enabled by default for stub and linux platforms, and +disabled for others. + +## Step-by-step + +### Adding a build file + +Create a `cobalt/samples/gn_tutorial/BUILD.gn` file and enter the following: + +``` +executable("hello_world") { + sources = [ + "hello_world.cc", + ] +} +``` + +There should already be a `hello_world.cc` file in that directory, +containing what you expect. That's it! Now we just need to tell the +build about this file. Open the `BUILD.gn` file in the root directory +and add the label of this target to the dependencies of one of the root +groups (a "group" target is a meta-target that is just a collection of +other targets): + +``` +group("all") { + deps = [ + ... + "//starboard:all", + "//cobalt/samples/gn_tutorial:hello_world", + ] +} +``` + +You can see the label of your target is "//" (indicating the source +root), followed by the directory name, a colon, and the target name. + +### Testing your addition + +From the command line in the source root directory: + +``` +gn gen out/Default +ninja -C out/Default hello_world +out/Default/hello_world +``` + +(Remember to specify `target_platform` and `cobalt_config` in `gn args` if +you haven't done so already.) + +GN encourages target names for static libraries that aren't globally +unique. To build one of these, you can pass the label with no leading +"//" to ninja: + +``` +ninja -C out/Default cobalt/samples/gn_tutorial:hello_world +``` + +### Declaring dependencies + +Let's make a static library that has a function to say hello to random +people. There is a source file `hello.cc` in that directory which has a +function to do this. Open the `cobalt/samples/gn_tutorial/BUILD.gn` file and add +the static library to the bottom of the existing file: + +``` +static_library("hello") { + sources = [ + "hello.cc", + ] +} +``` + +Now let's add an executable that depends on this library: + +``` +executable("say_hello") { + sources = [ + "say_hello.cc", + ] + deps = [ + ":hello", + ] +} +``` + +This executable includes one source file and depends on the previous +static library. The static library is referenced by its label in the +`deps`. You could have used the full label `//cobalt/samples/gn_tutorial:hello` +but if you're referencing a target in the same build file, you can use +the shortcut `:hello`. + +### Test the static library version + +From the command line in the source root directory: + +``` +ninja -C out/Default say_hello +out/Default/say_hello +``` + +Note that you **didn't** need to re-run GN. GN will automatically rebuild +the ninja files when any build file has changed. You know this happens +when ninja prints `[1/1] Regenerating ninja files` at the beginning of +execution. + +### Compiler settings + +Our hello library has a new feature, the ability to say hello to two +people at once. This feature is controlled by defining `TWO_PEOPLE`. We +can add defines like so: + +``` +static_library("hello") { + sources = [ + "hello.cc", + ] + defines = [ + "TWO_PEOPLE", + ] +} +``` + +### Putting settings in a config + +However, users of the library also need to know about this define, and +putting it in the static library target defines it only for the files +there. If somebody else includes `hello.h`, they won't see the new +definition. To see the new definition, everybody will have to define +`TWO_PEOPLE`. + +GN has a concept called a "config" which encapsulates settings. Let's +create one that defines our preprocessor define: + +``` +config("hello_config") { + defines = [ + "TWO_PEOPLE", + ] +} +``` + +To apply these settings to your target, you only need to add the +config's label to the list of configs in the target: + +``` +static_library("hello") { + ... + configs += [ + ":hello_config", + ] +} +``` + +Note that you need "+=" here instead of "=" since the build +configuration has a default set of configs applied to each target that +set up the default build stuff. You want to add to this list rather than +overwrite it. To see the default configs, you can use the `print` +function in the build file or the `desc` command-line subcommand (see +below for examples of both). + +### Dependent configs + +This nicely encapsulates our settings, but still requires everybody that +uses our library to set the config on themselves. It would be nice if +everybody that depends on our `hello` library can get this +automatically. Change your library definition to: + +``` +static_library("hello") { + sources = [ + "hello.cc", + ] + all_dependent_configs = [ + ":hello_config" + ] +} +``` + +This applies the `hello_config` to the `hello` target itself, plus all +targets that transitively depend on the current one. Now everybody that +depends on us will get our settings. You can also set `public_configs` +which applies only to targets that directly depend on your target (not +transitively). + +Now if you compile and run, you'll see the new version with two people: + +``` +> ninja -C out/Default say_hello +ninja: Entering directory 'out/Default' +[1/1] Regenerating ninja files +[4/4] LINK say_hello +> out/Default/say_hello +Hello, Bill and Joy. +``` + +## Add a new build argument + +You declare which arguments you accept and specify default values via +`declare_args`. + +``` +declare_args() { + enable_teleporter = true + enable_doom_melon = false +} +``` + +See `gn help buildargs` for an overview of how this works. +See `gn help declare_args` for specifics on declaring them. + +It is an error to declare a given argument more than once in a given scope, so +care should be used in scoping and naming arguments. + +## Don't know what's going on? + +You can run GN in verbose mode to see lots of messages about what it's +doing. Use `-v` for this. + +### Print debugging + +There is a `print` command which just writes to stdout: + +``` +static_library("hello") { + ... + print(configs) +} +``` + +This will print all of the configs applying to your target (including +the default ones). + +### The "desc" command + +You can run `gn desc <build_dir> <targetname>` to get information about +a given target: + +``` +gn desc out/Default //cobalt/samples/gn_tutorial:say_hello +``` + +will print out lots of exciting information. You can also print just one +section. Lets say you wanted to know where your `TWO_PEOPLE` define +came from on the `say_hello` target: + +``` +> gn desc out/Default //cobalt/samples/gn_tutorial:say_hello defines --blame +...lots of other stuff omitted... + From //cobalt/samples/gn_tutorial:hello_config + (Added by //cobalt/samples/gn_tutorial/BUILD.gn:12) + TWO_PEOPLE +``` + +You can see that `TWO_PEOPLE` was defined by a config, and you can also +see the which line caused that config to be applied to your target (in +this case, the `all_dependent_configs` line). + +Another particularly interesting variation: + +``` +gn desc out/Default //starboard:all deps --tree +``` + +See `gn help desc` for more. + +### Performance + +You can see what took a long time by running it with the `--time` command +line flag. This will output a summary of timings for various things. + +You can also make a trace of how the build files were executed: + +``` +gn --tracelog=mylog.trace +``` + +and you can load the resulting file in Chrome's `about:tracing` page to +look at everything.
diff --git a/src/cobalt/doc/gyp_gn_files.md b/src/cobalt/doc/gyp_gn_files.md new file mode 100644 index 0000000..452bfa7 --- /dev/null +++ b/src/cobalt/doc/gyp_gn_files.md
@@ -0,0 +1,19 @@ +# GYP files and their corresponding GN files + +Generally, `foo/bar/bar.gyp` corresponds to `foo/bar/BUILD.gn`, while +`foo/bar/baz.gyp` corresponds to either `foo/bar/baz/BUILD.gn` or +`foo/bar/BUILD.gn` (depending on whether it made sense to combine `baz.gyp` with +`bar.gyp`). `foo/bar/quux.gypi` typically corresponds to +`foo/bar/quux.gni`. Here is a table of irregular correspondences: + +GYP File | GN File | Notes +--------------------------------------------------- | ------------------------------------------------------------------------- |------ +build/common.gypi | cobalt/build/config/base.gni, starboard/build/config/base.gni (variables) | A few variables have been omitted, moved to `BUILDCONFIG.gn` instead, or refactored into configs. See the GYP -> GN cookbook for more info. +build/common.gypi | cobalt/build/config/BUILD.gn (target defaults) +cobalt/build/all.gyp | BUILD.gn (in root directory) | GN requires this location to be used +cobalt/build/config/base.gypi | cobalt/build/config/base.gni, starboard/build/config/base.gni (variables) | See comments for `build/common.gypi` +starboard/linux/shared/compiler_flags.gypi | starboard/linux/shared/BUILD.gn | "Compiler Defaults" section +starboard/linux/shared/starboard_base_symbolize.gyp | starboard/linux/shared/BUILD.gn | "starboard_platform Target" section +starboard/linux/shared/starboard_platform.gypi | starboard/linux/shared/BUILD.gn | "starboard_platform Target" section +starboard/linux/x64x11/libraries.gypi | starboard/linux/x64x11/BUILD.gn | `libs` variable of the `compiler_defaults` config +starboard/starboard_base_target.gypi | starboard/build/config/BUILD.gn | "Compiler Defaults" section
diff --git a/src/cobalt/doc/gyp_to_gn.md b/src/cobalt/doc/gyp_to_gn.md new file mode 100644 index 0000000..c7fbc74 --- /dev/null +++ b/src/cobalt/doc/gyp_to_gn.md
@@ -0,0 +1,349 @@ +# GYP → GN Conversion Cookbook (Cobalt Edition) + +[TOC] + +## Foreword + +Read the GN docs to familiarize yourself with the GN build system. I recommend +reading at least our [Quick Start][quick-start] guide, and skimming +the [Language document][language] and [Style Guide][style-guide] too. +The [GN and GYP Patterns][gn-gyp-patterns] document has some useful info too, +although not all of it is applicable to Cobalt. + +Also read [Chromium's GYP → GN conversion cookbook][chromium-cookbook] if you +haven't already. The guidelines in that cookbook generally apply here. This +document consists of Cobalt-specific addenda to that document. + +If you are uncertain how a certain idiom is expressed in GN, I suggest +consulting the Chromium code to see how they did it. Not all of Chromium's GN +idioms are adaptable to Cobalt (primarily because Chromium has no Starboard +concept), but it is a good place to start. + +[quick-start]: https://cobalt.googlesource.com/cobalt/+/master/src/cobalt/doc/gn_quick_start.md +[language]: https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/language.md +[style-guide]: https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/style_guide.md +[gn-gyp-patterns]: https://docs.google.com/document/d/1xuInfaOjQQ00mtzaTPfiLH-Hw1wlxfH-60jHoa921Lc/edit +[chromium-cookbook]: https://chromium.googlesource.com/experimental/chromium/src/+/refs/wip/bajones/webvr/tools/gn/docs/cookbook.md + +## gyp_to_gn.py + +There is a script to partially automate the GYP to GN conversion in +`cobalt/tools/gyp_to_gn.py`. To run it, use: + + cobalt/tools/gyp_to_gn.py path/to/module/module.gyp | gn format --stdin > path/to/module/BUILD.gn + +This script is able to produce reasonably close GN output for many GYP files. +However, it is not perfect, and some manual inspection and revision of the +output is often necessary. As of this writing, known issues in addition to the +ones the script warns about are: + +1. It doesn't translate over comments. This is because the script uses `eval` + to load the GYP file, which naturally cuts out all of the comments. +1. Sometimes the script will output `sources =` when it should have outputted + `sources +=`. This is because the GYP file had `'sources':` in both places, + but one of those places was inside a `conditions` block or similar. This bug + can be fixed, but it will take a little work. + + The same problem can happen with other variables besides `sources`, e.g. + `defines`, `deps`, etc. + +The script relies on two helper files in its directory, `variable_rewrites.dict` +and `deps_substitutions.txt`. `variable_rewrites.dict` is a Python dictionary +containing variables which were renamed or changed into booleans. +`deps_substitutions.txt` is a tab-delimited file containing a (non-exhaustive) +list of targets which were renamed. + +## File Correspondences + +`gyp_gn_files.md` in this directory contains a list of GYP -> GN file +correspondences. If you create a new irregular file correspondence, please add +it to this list before you forget! + +## Variables vs Build Args + +GN distinguishes between variables and build args. Build args are parameters +declared inside a `declare_args` block, that are intended for developers to +specify at the time they run gn. Ordinary variables are specified outside of +`declare_args` blocks, and they are intended to not change from build to build. + +An example of a build arg is `use_goma`; if this build arg is turned on, +compilation is done with Goma instead of locally. (As of this writing, +`use_goma` is by default on for stub and linux platforms, and off on the +others.) An example of a variable is `gl_type`; this is something which depends +on the Starboard platform, and it doesn't make sense for individual developers +to change the value of this variable at compile time. + +Some build behaviors controlled by environment variables in GYP been refactored +into GN build args. Here is a list of correspondences: + +GYP | GN | Defined in +-------------- | ---------------------- | ----------------------------------------- +`LB_FASTBUILD` | `cobalt_use_fastbuild` | `//starboard/build/config/fastbuild.gni` +`USE_ASAN` | `use_asan` | `//starboard/build/config/sanitizers.gni` +`USE_TSAN` | `use_tsan` | `//starboard/build/config/sanitizers.gni` + +## Feature Flags + +Most variables defined in `cobalt/build/config/base.gypi` and +`build/common.gypi` have been moved to `cobalt/build/config/base.gni` or +`starboard/build/config/base.gni`, depending on whether they are Cobalt or +Starboard variables. (A few, like `cobalt_config` and `starboard_path`, have +been moved to `BUILDCONFIG.gn`, and others may have been moved to other places +as well.) + +Some variables have not been copied over. Most commonly this is because the +variable in question has been replaced by a config, group or something in GN +more appropriate. + +Also, since GN has a true boolean type, variables which took on 0/1 values in +GYP have been converted to take on true/false values in GN. + +Variables in Starboard platforms' `gyp_configuration.gypi` file have been moved +to `configuration.gni` under the Starboard platform's directory. +`base.gni` automatically imports the `configuration.gni` file of the +right Starboard platform. + +GN doesn't allow defining a build arg twice with different values or changing +the value of a variable/build arg by importing a file. It also has no analog to +GYP's %-variable. Unfortunately for us, this means the code of `base.gni` +must necessarily check whether every variable/build arg it defines has already +been defined by the Starboard platform in `configuration.gni`. + +Chromium frowns upon files with too many variables or build arg definitions. +They prefer to keep such definitions close to the files which actually use them. +In contrast, we keep a single `base.gni` file, because it would be inconvenient +for porters to have to browse through dozens of files to find out which variables +they should override. + +## Build Args with Platform-Specific Defaults + +There are some build args, like `use_goma`, which have different default values +on different Starboard platforms. Here is the generic declaration of `use_goma`, +located in `//starboard/shared/toolchain/goma.gni`: + + if (!defined(use_goma)) { + # Set to true to enable distributed compilation using Goma. By default + # we use Goma for stub and linux. + use_goma = false + } + +Notice a few things: + +1. As with feature flags, `goma.gni` first checks to see if the Starboard + platform configuration has already defined it (with a different default) + in `configuration.gni`. +2. The comment is located right above the variable, inside the if statement. + This looks weird, but it's intentionally done this way so that the comment + will be printed out in `gn args --list`. +3. Starboard platforms which define alternative defaults are encouraged to + copy the comment when making their own definition of `use_goma`. (See the + stub platform configuration for an example.) It's not strictly necessary, but + if it's not done, then `gn args --list` won't print any documentation for + this build arg. + +## BUILDCONFIG Variables + +Some things which must necessarily be defined in `BUILDCONFIG.gn` may depend on +values from the Starboard platform, like: + + * The `target_os` and `target_cpu` + * The `test_target_type`, and `final_executable_type` (which correspond to the + GYP variables `gtest_target_type` and `final_executable_type`) + * The host and target toolchain + +These values are obtained from the Starboard platform's `buildconfig.gni` +file. + +## Generic Compiler Options + +In GYP, we have variables like `sb_pedantic_warnings` and keys like `rtti`, +which, if set for a target, turn on or off additional compiler flags. In GN, +these variables have been refactored into configs. + +Consult the following examples: + +### Pedantic Warnings + +GYP: + + 'variables': { + 'sb_pedantic_warnings': 1 + } + +GN: + + configs -= [ "//starboard/build/config:no_pedantic_warnings" ] + configs += [ "//starboard/build/config:pedantic_warnings" ] + +### Optimizations + +GYP: + + 'optimizations': 'debuggable' + +GN: + + configs -= [ "//starboard/build/config:default_optimizations" ] + configs += [ "//starboard/build/config:debuggable_optimizations" ] + +Ditto for `none` and `full`. + +### RTTI + +GYP: + + 'rtti': 1 + +GN: + + configs -= [ "//starboard/build/config:default_rtti" ] + configs += [ "//starboard/build/config:rtti" ] + +GYP: + + 'rtti': 0 + +GN: + + configs -= [ "//starboard/build/config:default_rtti" ] + configs += [ "//starboard/build/config:no_rtti" ] + +### -Wexit-time-destructors + +GYP: + + 'enable_wexit_time_destructors': 1 + +GN: + + configs += [ "//starboard/build/config:wexit_time_destructors" ] + +There is no `//starboard/build/config:no_wexit_time_destructors` config. + +### Implementation Details + +Each Starboard generic compiler config is implemented by referencing a +platform-dependent implementation as a subconfig. For instance, here is, in +essence, the code for `//starboard/build/config:pedantic_warnings`: + + config("pedantic_warnings") { + configs = [ "//$starboard_path/config:pedantic_warnings" ] + } + +Each Starboard platform is then expected to define a pedantic warnings config +(and a no-pedantic-warnings config) in its `BUILD.gn` file. For instance, the +stub platform's implementation is: + + config("pedantic_warnings") { + cflags = [ + "-Wall", + "-Wextra", + "-Wunreachable-code", + ] + } + +Similarly, each Starboard platform is expected to define configs for turning on +and off RTTI, or what the default RTTI state should be; configs for turning on +and off optimizations, and the like. In reality, Starboard platforms often in +turn delegate to configs implemented by toolchains (which stub does for e.g. +RTTI). + +## Variables Renamed + +In general, following Chromium's practice, booleans have been renamed to have a +`use_`, `enable_` or `is_` prefix, if they did not already have such a prefix. +These prefixes come after any `cobalt_` or `sb_` prefix. + +Here is a partial table of some renames: + +GYP | GN +--------------------------- | -------------------------- +`cobalt_fastbuild` | `cobalt_use_fastbuild` +`cobalt_version` | `cobalt_build_id` +`sb_allows_memory_tracking` | `sb_allow_memory_tracking` +`target_arch` | `target_cpu` + + +## Table of Variables Refactored into Configs + +Variable | Config +----------------------------------------------------- | -------------------------------------------------------------- +`sb_pedantic_warnings` | `//starboard/build/config:{no_}pedantic_warnings` +`compiler_flags`, `linker_flags` | `//$starboard_path:compiler_defaults` +`compiler_flags_debug`, `compiler_flags_c_debug`, ... | `//$starboard_path:compiler_defaults_debug` +`compiler_flags_devel`, `compiler_flags_c_devel`, ... | `//$starboard_path:compiler_defaults_devel` +`compiler_flags_qa`, `compiler_flags_c_qa`, ... | `//$starboard_path:compiler_defaults_qa` +`compiler_flags_gold`, `compiler_flags_c_gold`, ... | `//$starboard_path:compiler_defaults_gold` +`compiler_flags_host`, `compiler_flags_c_host`, ... | `//$starboard_path:compiler_defaults($host_toolchain)` +`platform_libraries` | `//$starboard_path:compiler_defaults` (in the `libs` variable) + +## gtest_target_type and friends + +The `gtest_target_type` variable has been renamed `test_target_type`. Platforms +wishing to override the default value of this variable (e.g. Android) should +put the override in `buildconfig.gni`. `final_executable_type` is similar. + +To use these types in targets, consult the following conversion table: + +GYP | GN +---------------------------------------------------- | --------------------------- +`'type': '<(gtest_target_type)', 'name': 'foo',` | `test("foo") {` +`'type': '<(final_executable_type)', 'name': 'foo',` | `final_executable("foo") {` + +## Deploy + +Replace + + { + 'target_name': 'target_deploy', + 'type': 'none', + 'dependencies': [ + 'target', + ], + 'variables': { + 'executable_name': 'target', + }, + 'includes': [ '../build/deploy.gypi' ], + }, + +with + + deploy("deploy") { + executable_name = "target" + + deps = [ + ":target", + ] + } + +and import `//starboard/build/deploy.gni` at the top of the file. + +## Runner Script + +The GYP build system has a runner script, `gyp_cobalt`, which does a ton of +preprocessing, then runs GYP four times, once for each Cobalt configuration. + +GN does not use a runner script. The preprocessing that `gyp_cobalt` does is +being moved into the actual GN build itself, making a runner script mostly +unnecessary. Furthermore, a nontrivial runner script would potentially interfere +with Ninja correctly rerunning GN when GN build files have changed. + +## Generic GN Advice for Build Args + +If you're adding a flag inside a `declare_args` block, read these tidbits of +advice: + + * Use boolean values when possible. If you need a default value that expands + to some complex thing in the default case (like the location of the + compiler which would be computed by a script), use a default value of -1 or + the empty string. Outside of the `declare_args` block, conditionally expand + the default value as necessary. + + * Use a name like `use_foo` or `is_foo` (whatever is more appropriate for + your feature) rather than just `foo`. + + * Write good comments directly above the declaration with no blank line. + These comments will appear as documentation in `gn args --list`. + + * Don't call `exec_script` inside `declare_args`. This will execute the script + even if the value is overridden, which is wasteful. See first bullet.
diff --git a/src/cobalt/doc/resources/webapi_extension_example.jpg b/src/cobalt/doc/resources/webapi_extension_example.jpg new file mode 100644 index 0000000..e9b43d1 --- /dev/null +++ b/src/cobalt/doc/resources/webapi_extension_example.jpg Binary files differ
diff --git a/src/cobalt/doc/webapi_extension.md b/src/cobalt/doc/webapi_extension.md new file mode 100644 index 0000000..4173d3a --- /dev/null +++ b/src/cobalt/doc/webapi_extension.md
@@ -0,0 +1,99 @@ +# Cobalt Web Extension Support + +Cobalt provides a facility for extending the JavaScript Web API. This allows +custom web apps running on Cobalt to make calls through a custom API to +C++ Cobalt code defined per Starboard platform. This can allow for closer +integration between the web app hosted by Cobalt and the system on which that +web app is running. + +The Cobalt Web Extension support will allow you to attach an instance of a +custom class to the JavaScript `window` global object so that it can be +referenced from a web app in JavaScript as in the following example: + +``` +window.myInterface.RunMyFunction() +``` + +## Build-level modifications + +In order to extend the interface, one should add the following lines to the +`variables` section of their platform's gyp_configuration.gypi file: + +1. `cobalt_webapi_extension_source_idl_files` + This should be a list of [IDL files](https://en.wikipedia.org/wiki/Web_IDL) + that define the collection of new interfaces introduced by your extensions. + One of these new interfaces can be selected to be injected into the `window` + element (see 3. `cobalt_webapi_extension_gyp_target` for information on how + to do this). Each IDL file listed here simultaneously defines a JavaScript + and a C++ interface. For each IDL file, you will be expected to also provide + a header file in the same directory that re-declares (in C++) the interface + declared in the IDL file, as well as an implementation of all the methods + within it (either inline in the header file or in a corresponding source + file). +2. `cobalt_webapi_extension_generated_header_idl_files` + This is a list of all files that may result in automatic header file + generation that might be referenced from other C++ code. An example of + this is the definition of `enum`s that may then be referenced as types in + a file from 1. `cobalt_webapi_extension_source_idl_files`. +3. `cobalt_webapi_extension_gyp_target` + This is the gyp target that will provide the IDL interface implementations, + as well as any necessary auxiliary code. It will be added as a dependency of + [browser/cobalt.gyp:cobalt](../browser/cobalt.gyp). It is expected that + this target will implement the interface defined in + [browser/webapi_extension.h](../browser/webapi_extension.h), which let you + name the injected window property, and provide a function to instantiate it + (i.e. to let you select which IDL object is the "entry point"). + +The first two lists get included by +[cobalt/browser/browser_bindings_gen.gyp](cobalt/browser/browser_bindings_gen.gyp), +where you can look to see many examples of existing Cobalt IDL files that define +the Web API available through Cobalt. For each of these, you can also +examine their corresponding `.h` files and in most cases their `.cc` files as +well. + +An example configuration for these variables is available at +[starboard/shared/test_webapi_extension/test_webapi_extension.gypi](../../starboard/shared/test_webapi_extension/test_webapi_extension.gypi), which +contains the following variable definitions: + +``` +'cobalt_webapi_extension_source_idl_files': [ + 'my_new_interface.idl' +], +'cobalt_webapi_extension_generated_header_idl_files': [ + 'my_new_enum.idl' +], +'cobalt_webapi_extension_gyp_target': + '<(DEPTH)/starboard/shared/test_webapi_extension/webapi_extension.gyp:cobalt_test_webapi_extension', +``` + +## Implementing the [webapi_extension.h](../browser/webapi_extension.h) interface + +As discussed above in 3. `cobalt_webapi_extension_gyp_target`, you must provide +an implementation of the two functions declared in +[browser/webapi_extension.h](../browser/webapi_extension.h). + +### `GetWebAPIExtensionObjectPropertyName()` +You should implement `GetWebAPIExtensionObjectPropertyName()` to return the name +of the injected `window` property. For example, in the example from the +beginning of this document, `window.myInterface.RunMyFunction()`, we would have +the function return `std::string("myInterface")`. If you return `nullopt` from +this function, it is assumed that you do not wish to extend the web interface. + +Note that you should NOT name your `window` property the same as your class name +as described in the IDL file, it will result in a name collision in the +JavaScript environment. + +### `CreateWebAPIExtensionObject()` +This function should instantiate and return the object to be accessed from +`window`. The object must be defined by an IDL file. + +## Debugging +You may find the Cobalt debug console to be particularly useful for debugging +IDL additions and changes. In it, you can enter arbitrary JavaScript and then +hit enter to execute it. You can toggle it open by hitting either CTRL+O or +F1, and you may have to hit the key twice to skip past the HUD mode. + +Here is an example of an example interface being exercised through the +debug console: + + \ No newline at end of file
diff --git a/src/cobalt/dom/buffer_source.cc b/src/cobalt/dom/buffer_source.cc new file mode 100644 index 0000000..e94d6a1 --- /dev/null +++ b/src/cobalt/dom/buffer_source.cc
@@ -0,0 +1,47 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/dom/buffer_source.h" + +#include "base/logging.h" +#include "cobalt/dom/array_buffer.h" +#include "cobalt/dom/array_buffer_view.h" + +namespace cobalt { +namespace dom { + +void GetBufferAndSize(const BufferSource& buffer_source, const uint8** buffer, + int* buffer_size) { + DCHECK(buffer); + DCHECK(buffer_size); + + if (buffer_source.IsType<scoped_refptr<ArrayBufferView> >()) { + scoped_refptr<ArrayBufferView> array_buffer_view = + buffer_source.AsType<scoped_refptr<ArrayBufferView> >(); + *buffer = static_cast<const uint8*>(array_buffer_view->base_address()); + *buffer_size = array_buffer_view->byte_length(); + } else if (buffer_source.IsType<scoped_refptr<ArrayBuffer> >()) { + scoped_refptr<ArrayBuffer> array_buffer = + buffer_source.AsType<scoped_refptr<ArrayBuffer> >(); + *buffer = array_buffer->data(); + *buffer_size = array_buffer->byte_length(); + } else { + NOTREACHED(); + *buffer = NULL; + *buffer_size = 0; + } +} + +} // namespace dom +} // namespace cobalt
diff --git a/src/cobalt/dom/buffer_source.h b/src/cobalt/dom/buffer_source.h index a796675..cb8e6a5 100644 --- a/src/cobalt/dom/buffer_source.h +++ b/src/cobalt/dom/buffer_source.h
@@ -26,6 +26,9 @@ typedef script::UnionType2<scoped_refptr<ArrayBufferView>, scoped_refptr<ArrayBuffer> > BufferSource; +void GetBufferAndSize(const BufferSource& buffer_source, const uint8** buffer, + int* buffer_size); + } // namespace dom } // namespace cobalt
diff --git a/src/cobalt/dom/dom.gyp b/src/cobalt/dom/dom.gyp index e516263..5711b9b 100644 --- a/src/cobalt/dom/dom.gyp +++ b/src/cobalt/dom/dom.gyp
@@ -37,6 +37,7 @@ 'blob.cc', 'blob.h', 'blob_property_bag.h', + 'buffer_source.cc', 'buffer_source.h', 'camera_3d.cc', 'camera_3d.h', @@ -292,6 +293,8 @@ 'eme/media_key_message_event.h', 'eme/media_key_session.cc', 'eme/media_key_session.h', + 'eme/media_key_status_map.cc', + 'eme/media_key_status_map.h', 'eme/media_key_system_access.cc', 'eme/media_key_system_access.h', 'eme/media_keys.cc',
diff --git a/src/cobalt/dom/eme/media_key_session.cc b/src/cobalt/dom/eme/media_key_session.cc index 5c62383..b2d8205 100644 --- a/src/cobalt/dom/eme/media_key_session.cc +++ b/src/cobalt/dom/eme/media_key_session.cc
@@ -14,6 +14,8 @@ #include "cobalt/dom/eme/media_key_session.h" +#include <type_traits> + #include "cobalt/dom/array_buffer.h" #include "cobalt/dom/array_buffer_view.h" #include "cobalt/dom/dom_exception.h" @@ -32,15 +34,23 @@ const scoped_refptr<media::DrmSystem>& drm_system, script::ScriptValueFactory* script_value_factory, const ClosedCallback& closed_callback) - : drm_system_(drm_system), - drm_system_session_(drm_system->CreateSession()), + : ALLOW_THIS_IN_INITIALIZER_LIST(event_queue_(this)), + drm_system_(drm_system), + drm_system_session_(drm_system->CreateSession( +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + base::Bind(&MediaKeySession::OnSessionUpdateKeyStatuses, + base::AsWeakPtr(this)) +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + )), script_value_factory_(script_value_factory), uninitialized_(true), callable_(false), + key_status_map_(new MediaKeyStatusMap), closed_callback_(closed_callback), ALLOW_THIS_IN_INITIALIZER_LIST(closed_promise_reference_( this, script_value_factory->CreateBasicPromise<void>())), - initiated_by_generate_request_(false) {} + initiated_by_generate_request_(false) { +} // According to the step 3.1 of // https://www.w3.org/TR/encrypted-media/#dom-mediakeys-createsession, @@ -55,6 +65,20 @@ return &closed_promise_reference_.referenced_value(); } +const scoped_refptr<MediaKeyStatusMap>& MediaKeySession::key_statuses() const { + return key_status_map_; +} + +const EventTarget::EventListenerScriptValue* +MediaKeySession::onkeystatuseschange() const { + return GetAttributeEventListener(base::Tokens::keystatuseschange()); +} + +void MediaKeySession::set_onkeystatuseschange( + const EventListenerScriptValue& event_listener) { + SetAttributeEventListener(base::Tokens::keystatuseschange(), event_listener); +} + const EventTarget::EventListenerScriptValue* MediaKeySession::onmessage() const { return GetAttributeEventListener(base::Tokens::message()); @@ -65,27 +89,6 @@ SetAttributeEventListener(base::Tokens::message(), event_listener); } -namespace { - -void GetBufferAndSize(const BufferSource& buffer_source, const uint8** buffer, - int* buffer_size) { - if (buffer_source.IsType<scoped_refptr<ArrayBufferView> >()) { - scoped_refptr<ArrayBufferView> array_buffer_view = - buffer_source.AsType<scoped_refptr<ArrayBufferView> >(); - *buffer = static_cast<const uint8*>(array_buffer_view->base_address()); - *buffer_size = array_buffer_view->byte_length(); - } else if (buffer_source.IsType<scoped_refptr<ArrayBuffer> >()) { - scoped_refptr<ArrayBuffer> array_buffer = - buffer_source.AsType<scoped_refptr<ArrayBuffer> >(); - *buffer = array_buffer->data(); - *buffer_size = array_buffer->byte_length(); - } else { - NOTREACHED(); - } -} - -} // namespace - // See // https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-generaterequest. scoped_ptr<MediaKeySession::VoidPromiseValue> MediaKeySession::GenerateRequest( @@ -252,7 +255,7 @@ // // TODO: Implement Event.isTrusted as per // https://www.w3.org/TR/dom/#dom-event-istrusted and set it to true. - DispatchEvent( + event_queue_.Enqueue( new MediaKeyMessageEvent("message", media_key_message_event_init)); // 10.5. Resolve promise. @@ -306,6 +309,60 @@ promise_reference->value().Reject(new DOMException(DOMException::kNone)); } +// See https://www.w3.org/TR/encrypted-media/#update-key-statuses. +void MediaKeySession::OnSessionUpdateKeyStatuses( + const std::vector<std::string>& key_ids, + const std::vector<SbDrmKeyStatus>& key_statuses) { +#define CHECK_KEY_STATUS_ENUM(starboard_value, dom_value) \ + static_assert(static_cast<MediaKeyStatus>(starboard_value) == dom_value, \ + "key status enum value mismatch"); + + CHECK_KEY_STATUS_ENUM(kSbDrmKeyStatusUsable, kMediaKeyStatusUsable); + CHECK_KEY_STATUS_ENUM(kSbDrmKeyStatusExpired, kMediaKeyStatusExpired); + CHECK_KEY_STATUS_ENUM(kSbDrmKeyStatusReleased, kMediaKeyStatusReleased); + CHECK_KEY_STATUS_ENUM(kSbDrmKeyStatusRestricted, + kMediaKeyStatusOutputRestricted); + CHECK_KEY_STATUS_ENUM(kSbDrmKeyStatusDownscaled, + kMediaKeyStatusOutputDownscaled); + CHECK_KEY_STATUS_ENUM(kSbDrmKeyStatusPending, kMediaKeyStatusStatusPending); + CHECK_KEY_STATUS_ENUM(kSbDrmKeyStatusError, kMediaKeyStatusInternalError); + + DCHECK_EQ(key_ids.size(), key_statuses.size()); + + // 1. Let the session be the associated MediaKeySession object. + // 2. Let the input statuses be the sequence of pairs key ID and associated + // MediaKeyStatus pairs. + // 3. Let the statuses be session's keyStatuses attribute. + // 4. Run the following steps to replace the contents of statuses: + // 4.1. Empty statuses. + key_status_map_->Clear(); + + // 4.2. For each pair in input statuses. + for (size_t i = 0; i < key_ids.size(); ++i) { + // 4.2.1. Let pair be the pair. + // 4.2.2. Insert an entry for pair's key ID into statuses with the value of + // pair's MediaKeyStatus value. + DCHECK_GE(key_statuses[i], kSbDrmKeyStatusUsable); + DCHECK_LE(key_statuses[i], kSbDrmKeyStatusError); + + if (key_statuses[i] < kSbDrmKeyStatusUsable || + key_statuses[i] > kSbDrmKeyStatusError) { + key_status_map_->Add(key_ids[i], kMediaKeyStatusInternalError); + } else { + key_status_map_->Add(key_ids[i], + static_cast<MediaKeyStatus>(key_statuses[i])); + } + } + + // 5. Queue a task to fire a simple event named keystatuseschange at the + // session. + event_queue_.Enqueue(new Event(base::Tokens::keystatuseschange())); + + // 6. Queue a task to run the Attempt to Resume Playback If Necessary + // algorithm on each of the media element(s) whose mediaKeys attribute is + // the MediaKeys object that created the session. +} + // See https://www.w3.org/TR/encrypted-media/#session-closed. void MediaKeySession::OnClosed() { // 2. Run the Update Key Statuses algorithm on the session, providing an empty
diff --git a/src/cobalt/dom/eme/media_key_session.h b/src/cobalt/dom/eme/media_key_session.h index cad6671..bda41aa 100644 --- a/src/cobalt/dom/eme/media_key_session.h +++ b/src/cobalt/dom/eme/media_key_session.h
@@ -16,14 +16,19 @@ #define COBALT_DOM_EME_MEDIA_KEY_SESSION_H_ #include <string> +#include <vector> #include "base/callback.h" #include "base/memory/weak_ptr.h" #include "cobalt/dom/buffer_source.h" +#include "cobalt/dom/eme/media_key_status.h" +#include "cobalt/dom/eme/media_key_status_map.h" +#include "cobalt/dom/event_queue.h" #include "cobalt/dom/event_target.h" #include "cobalt/media/base/drm_system.h" #include "cobalt/script/promise.h" #include "cobalt/script/script_value_factory.h" +#include "starboard/drm.h" namespace cobalt { namespace dom { @@ -47,6 +52,9 @@ // Web IDL: MediaKeySession. std::string session_id() const; const VoidPromiseValue* closed() const; + const scoped_refptr<MediaKeyStatusMap>& key_statuses() const; + const EventListenerScriptValue* onkeystatuseschange() const; + void set_onkeystatuseschange(const EventListenerScriptValue& event_listener); const EventListenerScriptValue* onmessage() const; void set_onmessage(const EventListenerScriptValue& event_listener); scoped_ptr<VoidPromiseValue> GenerateRequest( @@ -66,8 +74,13 @@ VoidPromiseValue::Reference* promise_reference); void OnSessionUpdated(VoidPromiseValue::Reference* promise_reference); void OnSessionDidNotUpdate(VoidPromiseValue::Reference* promise_reference); + void OnSessionUpdateKeyStatuses( + const std::vector<std::string>& key_ids, + const std::vector<SbDrmKeyStatus>& key_statuses); void OnClosed(); + EventQueue event_queue_; + // Although it doesn't make much sense, it's possible to call session methods // when |MediaKeys| are destroyed. This behavior is underspecified but is // consistent with Chromium. For this reason we need to hold to |drm_system_| @@ -77,6 +90,7 @@ script::ScriptValueFactory* const script_value_factory_; bool uninitialized_; bool callable_; + scoped_refptr<MediaKeyStatusMap> key_status_map_; // TODO: Remove |closed_callback_| and change call sites to use closed() // promise instead, once Cobalt switches to native SpiderMonkey
diff --git a/src/cobalt/dom/eme/media_key_session.idl b/src/cobalt/dom/eme/media_key_session.idl index c458e27..3813c47 100644 --- a/src/cobalt/dom/eme/media_key_session.idl +++ b/src/cobalt/dom/eme/media_key_session.idl
@@ -19,10 +19,9 @@ // TODO: Implement |expiration|. // readonly attribute unrestricted double expiration; readonly attribute Promise<void> closed; - // TODO: Implement |keyStatuses|. - // readonly attribute MediaKeyStatusMap keyStatuses; - // TODO: Implement |onkeystatuseschange|. - // attribute EventHandler onkeystatuseschange; + [Conditional=COBALT_ENCRYPTED_MEDIA_EXTENSION_ENABLE_KEY_STATUSES_UPDATE] + readonly attribute MediaKeyStatusMap keyStatuses; + attribute EventHandler onkeystatuseschange; attribute EventHandler onmessage; Promise<void> generateRequest(DOMString initDataType, BufferSource initData);
diff --git a/src/starboard/win/lib/atomic_public.h b/src/cobalt/dom/eme/media_key_status.idl similarity index 73% copy from src/starboard/win/lib/atomic_public.h copy to src/cobalt/dom/eme/media_key_status.idl index be4e805..37284a0 100644 --- a/src/starboard/win/lib/atomic_public.h +++ b/src/cobalt/dom/eme/media_key_status.idl
@@ -12,9 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ -#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +// https://www.w3.org/TR/encrypted-media/#idl-def-mediakeystatus -#include "starboard/shared/win32/atomic_public.h" - -#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +enum MediaKeyStatus { + "usable", + "expired", + "released", + "output-restricted", + "output-downscaled", + "status-pending", + "internal-error" +};
diff --git a/src/cobalt/dom/eme/media_key_status_map.cc b/src/cobalt/dom/eme/media_key_status_map.cc new file mode 100644 index 0000000..33e0bcc --- /dev/null +++ b/src/cobalt/dom/eme/media_key_status_map.cc
@@ -0,0 +1,71 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/dom/eme/media_key_status_map.h" + +#include "base/logging.h" +#include "cobalt/dom/array_buffer.h" +#include "cobalt/dom/array_buffer_view.h" + +namespace cobalt { +namespace dom { +namespace eme { + +namespace { + +std::string ConvertKeyStatusToString(MediaKeyStatus key_status) { + switch (key_status) { + case kMediaKeyStatusUsable: + return "usable"; + case kMediaKeyStatusExpired: + return "expired"; + case kMediaKeyStatusReleased: + return "released"; + case kMediaKeyStatusOutputRestricted: + return "output-restricted"; + case kMediaKeyStatusOutputDownscaled: + return "output-downscaled"; + case kMediaKeyStatusStatusPending: + return "status-pending"; + case kMediaKeyStatusInternalError: + return "internal-error"; + default: + break; + } + + NOTREACHED(); + return "internal-error"; +} + +BufferSource ConvertStringToBufferSource(const std::string& str) { + scoped_refptr<ArrayBuffer> array_buffer = + new ArrayBuffer(NULL, reinterpret_cast<const uint8*>(str.c_str()), + static_cast<uint32>(str.size())); + return BufferSource(array_buffer); +} + +} // namespace + +void MediaKeyStatusMap::ForEach(const ForEachCallbackArg& callback) { + ForEachCallbackArg::Reference reference(this, callback); + + for (auto& key_status : key_statuses_) { + reference.value().Run(ConvertKeyStatusToString(key_status.second), + ConvertStringToBufferSource(key_status.first), this); + } +} + +} // namespace eme +} // namespace dom +} // namespace cobalt
diff --git a/src/cobalt/dom/eme/media_key_status_map.h b/src/cobalt/dom/eme/media_key_status_map.h new file mode 100644 index 0000000..a2808c6 --- /dev/null +++ b/src/cobalt/dom/eme/media_key_status_map.h
@@ -0,0 +1,98 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef COBALT_DOM_EME_MEDIA_KEY_STATUS_MAP_H_ +#define COBALT_DOM_EME_MEDIA_KEY_STATUS_MAP_H_ + +#include <map> +#include <string> + +#include "base/memory/ref_counted.h" +#include "cobalt/dom/buffer_source.h" +#include "cobalt/dom/eme/media_key_status.h" +#include "cobalt/script/callback_function.h" +#include "cobalt/script/script_value.h" +#include "cobalt/script/wrappable.h" + +namespace cobalt { +namespace dom { +namespace eme { + +// Represents a read-only map of key IDs to the current status of the associated +// key. +// https://www.w3.org/TR/encrypted-media/#mediakeystatusmap-interface +class MediaKeyStatusMap : public script::Wrappable { + public: + typedef script::CallbackFunction<void( + const std::string&, const BufferSource&, + const scoped_refptr<MediaKeyStatusMap>&)> + ForEachCallback; + typedef script::ScriptValue<ForEachCallback> ForEachCallbackArg; + + // Custom, not in any spec. + // + MediaKeyStatusMap() {} + + void Clear() { key_statuses_.clear(); } + + void Add(const std::string& key_id, MediaKeyStatus key_status) { + key_statuses_[key_id] = key_status; + } + + // Web IDL: MediaKeyStatusMap. + // + uint32_t size() const { return static_cast<uint32_t>(key_statuses_.size()); } + MediaKeyStatus Get(const BufferSource& key_id) const { + std::string key_id_copy = GetStringFromBufferSource(key_id); + const auto& iter = key_statuses_.find(key_id_copy); + // TODO: Return "undefined" if `key_id` cannot be found. + return iter == key_statuses_.end() ? kMediaKeyStatusInternalError + : iter->second; + } + + bool Has(const BufferSource& key_id) const { + std::string key_id_copy = GetStringFromBufferSource(key_id); + return key_statuses_.find(key_id_copy) != key_statuses_.end(); + } + + void ForEach(const ForEachCallbackArg& callback); + + DEFINE_WRAPPABLE_TYPE(MediaKeyStatusMap); + + private: + static std::string GetStringFromBufferSource( + const BufferSource& buffer_source) { + const uint8* buffer; + int buffer_size; + + GetBufferAndSize(buffer_source, &buffer, &buffer_size); + + DCHECK(buffer); + DCHECK_GE(buffer_size, 0); + if (buffer && buffer_size > 0) { + return std::string(buffer, buffer + buffer_size); + } + return ""; + } + + std::map<std::string, MediaKeyStatus> key_statuses_; + + DISALLOW_COPY_AND_ASSIGN(MediaKeyStatusMap); +}; + +} // namespace eme +} // namespace dom +} // namespace cobalt + +#endif // COBALT_DOM_EME_MEDIA_KEY_STATUS_MAP_H_
diff --git a/src/cobalt/dom/eme/media_key_status_map.idl b/src/cobalt/dom/eme/media_key_status_map.idl new file mode 100644 index 0000000..60b1279 --- /dev/null +++ b/src/cobalt/dom/eme/media_key_status_map.idl
@@ -0,0 +1,26 @@ +// Copyright 2017 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. + +// https://www.w3.org/TR/encrypted-media/#mediakeystatusmap-interface + +[Conditional=COBALT_ENCRYPTED_MEDIA_EXTENSION_ENABLE_KEY_STATUSES_UPDATE] +interface MediaKeyStatusMap { + iterable<BufferSource, MediaKeyStatus>; + readonly attribute unsigned long size; + boolean has(BufferSource keyId); + any get(BufferSource keyId); + void forEach(ForEachCallback callback); +}; + +callback ForEachCallback = void (DOMString status, BufferSource key, MediaKeyStatusMap map);
diff --git a/src/cobalt/dom/html_image_element.cc b/src/cobalt/dom/html_image_element.cc index aedb344..4d8dfce 100644 --- a/src/cobalt/dom/html_image_element.cc +++ b/src/cobalt/dom/html_image_element.cc
@@ -140,13 +140,13 @@ // img element. Otherwise, queue a task to first fire a simple event named // error at the img element. PreventGarbageCollection(); + node_document()->IncreaseLoadingCounter(); cached_image_loaded_callback_handler_.reset( new loader::image::CachedImage::OnLoadedCallbackHandler( cached_image, base::Bind(&HTMLImageElement::OnLoadingSuccess, base::Unretained(this)), base::Bind(&HTMLImageElement::OnLoadingError, base::Unretained(this)))); - node_document()->IncreaseLoadingCounter(); } void HTMLImageElement::OnLoadingSuccess() {
diff --git a/src/cobalt/dom/html_link_element.cc b/src/cobalt/dom/html_link_element.cc index ac0f16f..8c09292 100644 --- a/src/cobalt/dom/html_link_element.cc +++ b/src/cobalt/dom/html_link_element.cc
@@ -116,6 +116,13 @@ &CspDelegate::CanLoad, base::Unretained(document->csp_delegate()), GetCspResourceTypeForRel(rel())); + if (IsRelContentCriticalResource(rel())) { + // The element must delay the load event of the element's document until all + // the attempts to obtain the resource and its critical subresources are + // complete. + document->IncreaseLoadingCounter(); + } + loader_ = make_scoped_ptr(new loader::Loader( base::Bind( &loader::FetcherFactory::CreateSecureFetcher, @@ -124,13 +131,6 @@ scoped_ptr<loader::Decoder>(new loader::TextDecoder( base::Bind(&HTMLLinkElement::OnLoadingDone, base::Unretained(this)))), base::Bind(&HTMLLinkElement::OnLoadingError, base::Unretained(this)))); - - if (IsRelContentCriticalResource(rel())) { - // The element must delay the load event of the element's document until all - // the attempts to obtain the resource and its critical subresources are - // complete. - document->IncreaseLoadingCounter(); - } } void HTMLLinkElement::OnLoadingDone(const std::string& content) {
diff --git a/src/cobalt/dom/html_script_element.cc b/src/cobalt/dom/html_script_element.cc index e140ed6..652c504 100644 --- a/src/cobalt/dom/html_script_element.cc +++ b/src/cobalt/dom/html_script_element.cc
@@ -285,6 +285,12 @@ std::deque<HTMLScriptElement*>* scripts_to_be_executed = document_->scripts_to_be_executed(); scripts_to_be_executed->push_back(this); + + // Fetching an external script must delay the load event of the element's + // document until the task that is queued by the networking task source + // once the resource has been fetched (defined above) has been run. + document_->IncreaseLoadingCounter(); + loader_.reset(new loader::Loader( base::Bind( &loader::FetcherFactory::CreateSecureFetcher, @@ -294,11 +300,6 @@ &HTMLScriptElement::OnLoadingDone, base::Unretained(this)))), base::Bind(&HTMLScriptElement::OnLoadingError, base::Unretained(this)))); - - // Fetching an external script must delay the load event of the element's - // document until the task that is queued by the networking task source - // once the resource has been fetched (defined above) has been run. - document_->IncreaseLoadingCounter(); } break; case 5: { // This is an asynchronous script. Prevent garbage collection until @@ -307,6 +308,11 @@ // If the element has a src attribute. + // Fetching an external script must delay the load event of the element's + // document until the task that is queued by the networking task source + // once the resource has been fetched (defined above) has been run. + document_->IncreaseLoadingCounter(); + // The element must be added to the set of scripts that will execute as // soon as possible of the Document of the script element at the time the // prepare a script algorithm started. @@ -319,11 +325,6 @@ &HTMLScriptElement::OnLoadingDone, base::Unretained(this)))), base::Bind(&HTMLScriptElement::OnLoadingError, base::Unretained(this)))); - - // Fetching an external script must delay the load event of the element's - // document until the task that is queued by the networking task source - // once the resource has been fetched (defined above) has been run. - document_->IncreaseLoadingCounter(); } break; case 6: { // Otherwise.
diff --git a/src/cobalt/dom/ui_event.h b/src/cobalt/dom/ui_event.h index 46fb6b2..48655a1 100644 --- a/src/cobalt/dom/ui_event.h +++ b/src/cobalt/dom/ui_event.h
@@ -17,7 +17,6 @@ #include <string> -#include "base/string_piece.h" #include "cobalt/dom/document.h" #include "cobalt/dom/event.h" #include "cobalt/dom/ui_event_init.h"
diff --git a/src/cobalt/layout/box.cc b/src/cobalt/layout/box.cc index a65f43f..1c3663f 100644 --- a/src/cobalt/layout/box.cc +++ b/src/cobalt/layout/box.cc
@@ -142,6 +142,38 @@ } } +LayoutUnit Box::GetContainingBlockLeftOffset(bool stop_at_transform) const { + // If the box is absolutely positioned, then its containing block is formed by + // the padding box instead of the content box, as described in + // http://www.w3.org/TR/CSS21/visudet.html#containing-block-details. + // NOTE: While not explicitly stated in the spec, which specifies that the + // containing block of a 'fixed' position element must always be the viewport, + // all major browsers use the padding box of a transformed ancestor as the + // containing block for 'fixed' position elements. + return parent_ ? IsAbsolutelyPositioned() + ? GetContainingBlock()->GetPaddingBoxLeftEdge( + stop_at_transform) + : GetContainingBlock()->GetContentBoxLeftEdge( + stop_at_transform) + : LayoutUnit(); +} + +LayoutUnit Box::GetContainingBlockTopOffset(bool stop_at_transform) const { + // If the box is absolutely positioned, then its containing block is formed by + // the padding box instead of the content box, as described in + // http://www.w3.org/TR/CSS21/visudet.html#containing-block-details. + // NOTE: While not explicitly stated in the spec, which specifies that the + // containing block of a 'fixed' position element must always be the viewport, + // all major browsers use the padding box of a transformed ancestor as the + // containing block for 'fixed' position elements. + return parent_ ? IsAbsolutelyPositioned() + ? GetContainingBlock()->GetPaddingBoxTopEdge( + stop_at_transform) + : GetContainingBlock()->GetContentBoxTopEdge( + stop_at_transform) + : LayoutUnit(); +} + void Box::SetStaticPositionLeftFromParent(LayoutUnit left) { if (left != static_position_offset_from_parent_.x()) { static_position_offset_from_parent_.set_x(left); @@ -215,16 +247,20 @@ return margin_top() + GetBorderBoxHeight() + margin_bottom(); } -LayoutUnit Box::GetMarginBoxLeftEdge() const { - LayoutUnit left_from_containing_block = - parent_ ? GetContainingBlock()->GetContentBoxLeftEdge() : LayoutUnit(); - return left() + left_from_containing_block; +LayoutUnit Box::GetMarginBoxLeftEdge(bool stop_at_transform) const { + LayoutUnit containing_block_left_offset = + (!stop_at_transform || !IsTransformed()) + ? GetContainingBlockLeftOffset(stop_at_transform) + : LayoutUnit(); + return containing_block_left_offset + left(); } -LayoutUnit Box::GetMarginBoxTopEdge() const { - LayoutUnit top_from_containing_block = - parent_ ? GetContainingBlock()->GetContentBoxTopEdge() : LayoutUnit(); - return top() + top_from_containing_block; +LayoutUnit Box::GetMarginBoxTopEdge(bool stop_at_transform) const { + LayoutUnit containing_block_top_offset = + (!stop_at_transform || !IsTransformed()) + ? GetContainingBlockTopOffset(stop_at_transform) + : LayoutUnit(); + return containing_block_top_offset + top(); } LayoutUnit Box::GetMarginBoxRightEdgeOffsetFromContainingBlock() const { @@ -257,8 +293,9 @@ return border_top_width() + GetPaddingBoxHeight() + border_bottom_width(); } -RectLayoutUnit Box::GetBorderBox() const { - return RectLayoutUnit(GetBorderBoxLeftEdge(), GetBorderBoxTopEdge(), +RectLayoutUnit Box::GetBorderBox(bool stop_at_transform) const { + return RectLayoutUnit(GetBorderBoxLeftEdge(stop_at_transform), + GetBorderBoxTopEdge(stop_at_transform), GetBorderBoxWidth(), GetBorderBoxHeight()); } @@ -266,12 +303,12 @@ return SizeLayoutUnit(GetBorderBoxWidth(), GetBorderBoxHeight()); } -LayoutUnit Box::GetBorderBoxLeftEdge() const { - return GetMarginBoxLeftEdge() + margin_left(); +LayoutUnit Box::GetBorderBoxLeftEdge(bool stop_at_transform) const { + return GetMarginBoxLeftEdge(stop_at_transform) + margin_left(); } -LayoutUnit Box::GetBorderBoxTopEdge() const { - return GetMarginBoxTopEdge() + margin_top(); +LayoutUnit Box::GetBorderBoxTopEdge(bool stop_at_transform) const { + return GetMarginBoxTopEdge(stop_at_transform) + margin_top(); } LayoutUnit Box::GetPaddingBoxWidth() const { @@ -286,12 +323,12 @@ return SizeLayoutUnit(GetPaddingBoxWidth(), GetPaddingBoxHeight()); } -LayoutUnit Box::GetPaddingBoxLeftEdge() const { - return GetBorderBoxLeftEdge() + border_left_width(); +LayoutUnit Box::GetPaddingBoxLeftEdge(bool stop_at_transform) const { + return GetBorderBoxLeftEdge(stop_at_transform) + border_left_width(); } -LayoutUnit Box::GetPaddingBoxTopEdge() const { - return GetBorderBoxTopEdge() + border_top_width(); +LayoutUnit Box::GetPaddingBoxTopEdge(bool stop_at_transform) const { + return GetBorderBoxTopEdge(stop_at_transform) + border_top_width(); } Vector2dLayoutUnit Box::GetContentBoxOffsetFromMarginBox() const { @@ -333,12 +370,12 @@ return Vector2dLayoutUnit(padding_left(), padding_top()); } -LayoutUnit Box::GetContentBoxLeftEdge() const { - return GetPaddingBoxLeftEdge() + padding_left(); +LayoutUnit Box::GetContentBoxLeftEdge(bool stop_at_transform) const { + return GetPaddingBoxLeftEdge(stop_at_transform) + padding_left(); } -LayoutUnit Box::GetContentBoxTopEdge() const { - return GetPaddingBoxTopEdge() + padding_top(); +LayoutUnit Box::GetContentBoxTopEdge(bool stop_at_transform) const { + return GetPaddingBoxTopEdge(stop_at_transform) + padding_top(); } LayoutUnit Box::GetInlineLevelBoxHeight() const { return GetMarginBoxHeight(); } @@ -582,10 +619,10 @@ } } -Box::RenderSequence Box::GetRenderSequence() { +Box::RenderSequence Box::GetRenderSequence() const { std::vector<size_t> render_sequence; - Box* ancestor_box = this; - Box* box = NULL; + const Box* ancestor_box = this; + const Box* box = NULL; while (ancestor_box && (box != ancestor_box)) { box = ancestor_box; if (box->cached_render_tree_node_info_) { @@ -660,7 +697,8 @@ if (rounded_corners) { rect_node_builder->rounded_corners = - scoped_ptr<RoundedCorners>(new RoundedCorners(*rounded_corners)); + scoped_ptr<RoundedCorners>(new RoundedCorners( + rounded_corners->Normalize(rect_node_builder->rect))); } } @@ -749,7 +787,8 @@ if (rounded_corners) { rect_node_builder->rounded_corners = - scoped_ptr<RoundedCorners>(new RoundedCorners(*rounded_corners)); + scoped_ptr<RoundedCorners>(new RoundedCorners( + rounded_corners->Normalize(rect_node_builder->rect))); } } @@ -883,7 +922,7 @@ } bool Box::IsUnderCoordinate(const Vector2dLayoutUnit& coordinate) const { - RectLayoutUnit rect = GetBorderBox(); + RectLayoutUnit rect = GetBorderBox(true /*stop_at_transform*/); bool res = coordinate.x() >= rect.x() && coordinate.x() <= rect.x() + rect.width() && coordinate.y() >= rect.y() && coordinate.y() <= rect.y() + rect.height(); @@ -1192,7 +1231,10 @@ render_tree::RectShadowNode::Builder shadow_builder( math::RectF(rect_offset, shadow_rect_size), shadow, shadow_value->has_inset(), spread_radius); - shadow_builder.rounded_corners = rounded_corners; + if (rounded_corners) { + shadow_builder.rounded_corners = rounded_corners->Normalize( + shadow_builder.rect); + } // Finally, create our shadow node. scoped_refptr<render_tree::RectShadowNode> shadow_node( @@ -1346,7 +1388,8 @@ // Apply rounded viewport filter to the background image. FilterNode::Builder filter_node_builder(background_node); filter_node_builder.viewport_filter = - ViewportFilter(image_frame, *rounded_corners); + ViewportFilter(image_frame, + rounded_corners->Normalize(image_frame)); background_node = new FilterNode(filter_node_builder); } @@ -1448,7 +1491,9 @@ border_node_offset.y() + border_top_width().toFloat(), padding_size.width(), padding_size.height())); if (rounded_corners) { - filter_node_builder.viewport_filter->set_rounded_corners(*rounded_corners); + filter_node_builder.viewport_filter->set_rounded_corners( + rounded_corners->Normalize( + filter_node_builder.viewport_filter->viewport())); } return scoped_refptr<render_tree::Node>(new FilterNode(filter_node_builder)); @@ -1552,20 +1597,32 @@ const scoped_refptr<cssom::PropertyValue>& transform = computed_style()->transform(); if (transform != cssom::KeywordValue::GetNone()) { + LayoutUnit containing_block_left_offset = + GetContainingBlockLeftOffset(true /*stop_at_transform*/); + LayoutUnit containing_block_top_offset = + GetContainingBlockTopOffset(true /*stop_at_transform*/); + math::Vector2dF border_box_offset( - left().toFloat() + margin_left().toFloat(), - top().toFloat() + margin_top().toFloat()); + (containing_block_left_offset + left() + margin_left()).toFloat(), + (containing_block_top_offset + top() + margin_top()).toFloat()); + math::RectF rect = math::RectF(PointAtOffsetFromOrigin(border_box_offset), GetBorderBoxSize()); math::Matrix3F matrix = GetCSSTransform(transform, computed_style()->transform_origin(), rect); if (!matrix.IsIdentity()) { - // transform the coordinate. + // Transform the coordinate. math::PointF transformed_point = matrix.Inverse() * math::PointF(coordinate->x(), coordinate->y()); coordinate->set_x(transformed_point.x()); coordinate->set_y(transformed_point.y()); } + + // The transformed box forms a new coordinate system and its containing + // block's offset is considered (0,0) within it. Convert the coordinate to + // the new system. + *coordinate -= math::Vector2dF(containing_block_left_offset.toFloat(), + containing_block_top_offset.toFloat()); } }
diff --git a/src/cobalt/layout/box.h b/src/cobalt/layout/box.h index ddc61a0..7686c84 100644 --- a/src/cobalt/layout/box.h +++ b/src/cobalt/layout/box.h
@@ -213,6 +213,14 @@ // out-of-flow descendants. Does not update the position of the box. void UpdateSize(const LayoutParams& layout_params); + // Returns the left offset from root (or a transform if |stop_at_transform| is + // true) to this box's containing block. + LayoutUnit GetContainingBlockLeftOffset(bool stop_at_transform) const; + + // Returns the top offset from root (or a transform if |stop_at_transform| is + // true) to this box's containing block. + LayoutUnit GetContainingBlockTopOffset(bool stop_at_transform) const; + // Used values of "left" and "top" are publicly readable and writable so that // they can be calculated and adjusted by the formatting context of // the parent box. @@ -267,8 +275,8 @@ const Vector2dLayoutUnit& margin_box_offset_from_containing_block() const { return margin_box_offset_from_containing_block_; } - LayoutUnit GetMarginBoxLeftEdge() const; - LayoutUnit GetMarginBoxTopEdge() const; + LayoutUnit GetMarginBoxLeftEdge(bool stop_at_transform) const; + LayoutUnit GetMarginBoxTopEdge(bool stop_at_transform) const; LayoutUnit GetMarginBoxRightEdgeOffsetFromContainingBlock() const; LayoutUnit GetMarginBoxBottomEdgeOffsetFromContainingBlock() const; LayoutUnit GetMarginBoxStartEdgeOffsetFromContainingBlock( @@ -283,17 +291,17 @@ // Border box. LayoutUnit GetBorderBoxWidth() const; LayoutUnit GetBorderBoxHeight() const; - RectLayoutUnit GetBorderBox() const; + RectLayoutUnit GetBorderBox(bool stop_at_transform) const; SizeLayoutUnit GetBorderBoxSize() const; - LayoutUnit GetBorderBoxLeftEdge() const; - LayoutUnit GetBorderBoxTopEdge() const; + LayoutUnit GetBorderBoxLeftEdge(bool stop_at_transform) const; + LayoutUnit GetBorderBoxTopEdge(bool stop_at_transform) const; // Padding box. LayoutUnit GetPaddingBoxWidth() const; LayoutUnit GetPaddingBoxHeight() const; SizeLayoutUnit GetPaddingBoxSize() const; - LayoutUnit GetPaddingBoxLeftEdge() const; - LayoutUnit GetPaddingBoxTopEdge() const; + LayoutUnit GetPaddingBoxLeftEdge(bool stop_at_transform) const; + LayoutUnit GetPaddingBoxTopEdge(bool stop_at_transform) const; // Content box. LayoutUnit width() const { return content_size_.width(); } @@ -309,8 +317,8 @@ BaseDirection base_direction) const; LayoutUnit GetContentBoxEndEdgeOffsetFromContainingBlock( BaseDirection base_direction) const; - LayoutUnit GetContentBoxLeftEdge() const; - LayoutUnit GetContentBoxTopEdge() const; + LayoutUnit GetContentBoxLeftEdge(bool stop_at_transform) const; + LayoutUnit GetContentBoxTopEdge(bool stop_at_transform) const; // The height of each inline-level box in the line box is calculated. For // replaced elements, inline-block elements, and inline-table elements, this @@ -533,7 +541,7 @@ bool IsUnderCoordinate(const Vector2dLayoutUnit& coordinate) const; // Returns a data structure that can be used by Box::IsRenderedLater(). - RenderSequence GetRenderSequence(); + RenderSequence GetRenderSequence() const; // Returns true if the box for the given render_sequence is rendered after // the box for the other_render_sequence. The boxes must be from the same
diff --git a/src/cobalt/layout/layout_boxes.cc b/src/cobalt/layout/layout_boxes.cc index dc1b5ba..6068bac 100644 --- a/src/cobalt/layout/layout_boxes.cc +++ b/src/cobalt/layout/layout_boxes.cc
@@ -61,8 +61,10 @@ // boxes. Our current clients don't currently rely on GetClientRects() to // do that. - dom_rect->set_x(box->GetBorderBoxLeftEdge().toFloat()); - dom_rect->set_y(box->GetBorderBoxTopEdge().toFloat()); + dom_rect->set_x( + box->GetBorderBoxLeftEdge(false /*stop_at_transform*/).toFloat()); + dom_rect->set_y( + box->GetBorderBoxTopEdge(false /*stop_at_transform*/).toFloat()); SizeLayoutUnit box_size = box->GetBorderBoxSize(); dom_rect->set_width(box_size.width().toFloat()); dom_rect->set_height(box_size.height().toFloat()); @@ -119,12 +121,16 @@ float LayoutBoxes::GetPaddingEdgeLeft() const { DCHECK(!boxes_.empty()); - return boxes_.front()->GetPaddingBoxLeftEdge().toFloat(); + return boxes_.front() + ->GetPaddingBoxLeftEdge(false /*stop_at_transform*/) + .toFloat(); } float LayoutBoxes::GetPaddingEdgeTop() const { DCHECK(!boxes_.empty()); - return boxes_.front()->GetPaddingBoxTopEdge().toFloat(); + return boxes_.front() + ->GetPaddingBoxTopEdge(false /*stop_at_transform*/) + .toFloat(); } float LayoutBoxes::GetPaddingEdgeWidth() const { @@ -187,7 +193,7 @@ box_iterator != boxes_.end(); ++box_iterator) { Box* box = *box_iterator; do { - bounding_rectangle.Union(box->GetBorderBox()); + bounding_rectangle.Union(box->GetBorderBox(false /*stop_at_transform*/)); box = box->GetSplitSibling(); } while (box != NULL); }
diff --git a/src/cobalt/layout/topmost_event_target.cc b/src/cobalt/layout/topmost_event_target.cc index a74dfaf..83cd9cc 100644 --- a/src/cobalt/layout/topmost_event_target.cc +++ b/src/cobalt/layout/topmost_event_target.cc
@@ -74,15 +74,6 @@ if (!boxes.empty()) { const Box* box = boxes.front(); box->UpdateCoordinateForTransform(&element_coordinate); - - if (box->computed_style()->position() == - cssom::KeywordValue::GetAbsolute()) { - // The containing block for position:absolute elements is formed by - // the padding box instead of the content box, as described in - // http://www.w3.org/TR/CSS21/visudet.html#containing-block-details. - element_coordinate += - box->GetContainingBlock()->GetContentBoxOffsetFromPaddingBox(); - } ConsiderBoxes(html_element, layout_boxes, element_coordinate); } } @@ -105,15 +96,18 @@ LayoutUnit(coordinate.y())); for (Boxes::const_iterator box_iterator = boxes.begin(); box_iterator != boxes.end(); ++box_iterator) { - const scoped_refptr<Box>& box = *box_iterator; - if (box->IsUnderCoordinate(layout_coordinate)) { - Box::RenderSequence render_sequence = box->GetRenderSequence(); - if (Box::IsRenderedLater(render_sequence, render_sequence_)) { - html_element_ = html_element; - box_ = box; - render_sequence_.swap(render_sequence); + Box* box = *box_iterator; + do { + if (box->IsUnderCoordinate(layout_coordinate)) { + Box::RenderSequence render_sequence = box->GetRenderSequence(); + if (Box::IsRenderedLater(render_sequence, render_sequence_)) { + html_element_ = html_element; + box_ = box; + render_sequence_.swap(render_sequence); + } } - } + box = box->GetSplitSibling(); + } while (box != NULL); } }
diff --git a/src/cobalt/loader/image/animated_webp_image.cc b/src/cobalt/loader/image/animated_webp_image.cc index 100b919..0df113a 100644 --- a/src/cobalt/loader/image/animated_webp_image.cc +++ b/src/cobalt/loader/image/animated_webp_image.cc
@@ -50,7 +50,6 @@ frame_count_(0), loop_count_(kLoopInfinite), current_frame_index_(0), - next_frame_index_(0), should_dispose_previous_frame_to_background_(false), resource_provider_(resource_provider), frame_provider_(new FrameProvider()) { @@ -58,7 +57,7 @@ "AnimatedWebPImage::AnimatedWebPImage()"); } -scoped_refptr<const AnimatedImage::FrameProvider> +scoped_refptr<AnimatedImage::FrameProvider> AnimatedWebPImage::GetFrameProvider() { TRACE_EVENT0("cobalt::loader::image", "AnimatedWebPImage::GetFrameProvider()"); @@ -110,14 +109,14 @@ received_first_frame_ = true; loop_count_ = WebPDemuxGetI(demux_, WEBP_FF_LOOP_COUNT); - // The default background color of the canvas in [Blue, Green, Red, Alpha] - // byte order. It is read in little endian order as an 32bit int. + // The default background color of the canvas in [Blue, Green, Red, Alpha], + // from most significant byte to least significant byte. uint32_t background_color = WebPDemuxGetI(demux_, WEBP_FF_BACKGROUND_COLOR); background_color_ = - render_tree::ColorRGBA((background_color >> 16 & 0xff) / 255.0f, - (background_color >> 8 & 0xff) / 255.0f, - (background_color & 0xff) / 255.0f, - (background_color >> 24 & 0xff) / 255.0f); + render_tree::ColorRGBA((background_color >> 8 & 0xff) / 255.0f, + (background_color >> 16 & 0xff) / 255.0f, + (background_color >> 24 & 0xff) / 255.0f, + (background_color >> 0 & 0xff) / 255.0f); if (is_playing_) { PlayInternal(); @@ -172,25 +171,25 @@ base::Bind(&AnimatedWebPImage::DecodeFrames, base::Unretained(this))); } - UpdateTimelineInfo(); - - // Decode the frames from current frame to next frame and blend the results. - for (int frame_index = current_frame_index_ + 1; - frame_index <= next_frame_index_; ++frame_index) { - if (!DecodeOneFrame(frame_index)) { - break; - } + if (AdvanceFrame()) { + // Decode the frames from current frame to next frame and blend the results. + DecodeOneFrame(current_frame_index_); } - current_frame_index_ = next_frame_index_; // Set up the next time to call the decode callback. if (is_playing_) { - base::TimeDelta delay = next_frame_time_ - base::TimeTicks::Now(); const base::TimeDelta min_delay = base::TimeDelta::FromMilliseconds(kMinimumDelayInMilliseconds); - if (delay < min_delay) { + base::TimeDelta delay; + if (next_frame_time_) { + delay = *next_frame_time_ - base::TimeTicks::Now(); + if (delay < min_delay) { + delay = min_delay; + } + } else { delay = min_delay; } + message_loop_->PostDelayedTask(FROM_HERE, decode_closure_.callback(), delay); } @@ -288,44 +287,78 @@ return true; } -void AnimatedWebPImage::UpdateTimelineInfo() { - TRACE_EVENT0("cobalt::loader::image", - "AnimatedWebPImage::UpdateTimelineInfo()"); +bool AnimatedWebPImage::AdvanceFrame() { + TRACE_EVENT0("cobalt::loader::image", "AnimatedWebPImage::AdvanceFrame()"); TRACK_MEMORY_SCOPE("Rendering"); DCHECK(message_loop_->BelongsToCurrentThread()); lock_.AssertAcquired(); base::TimeTicks current_time = base::TimeTicks::Now(); - next_frame_index_ = current_frame_index_ ? current_frame_index_ : 1; - while (true) { - // Decode frames, until a frame such that the duration covers the current - // time, i.e. the next frame should be displayed in the future. - WebPIterator webp_iterator; - WebPDemuxGetFrame(demux_, next_frame_index_, &webp_iterator); - next_frame_time_ = current_frame_time_ + base::TimeDelta::FromMilliseconds( - webp_iterator.duration); - WebPDemuxReleaseIterator(&webp_iterator); - if (current_time < next_frame_time_) { - break; + + // If the WebP image hasn't been fully fetched, then stop on the current + // frame. + if (demux_state_ == WEBP_DEMUX_PARSED_HEADER) { + return false; + } + + // If we're done playing the animation, do nothing. + if (LoopingFinished()) { + return false; + } + + // If it's still not time to advance to the next frame, do nothing. + if (next_frame_time_ && current_time < *next_frame_time_) { + return false; + } + + // Always wait for a consumer to consume the previous frame before moving + // forward with decoding the next frame. + if (!frame_provider_->FrameConsumed()) { + return false; + } + + if (next_frame_time_) { + current_frame_time_ = *next_frame_time_; + } else { + current_frame_time_ = current_time; + } + + ++current_frame_index_; + if (current_frame_index_ == frame_count_) { + // Check if we have finished looping, and if so return indicating that there + // is no additional frame available. + if (LoopingFinished()) { + next_frame_time_ = base::nullopt; + return false; } - current_frame_time_ = next_frame_time_; - if (next_frame_index_ < frame_count_) { - next_frame_index_++; - } else { - DCHECK_EQ(next_frame_index_, frame_count_); - // If the WebP image hasn't been fully fetched, or we've reached the end - // of the last loop, then stop on the current frame. - if (demux_state_ == WEBP_DEMUX_PARSED_HEADER || loop_count_ == 1) { - break; - } - next_frame_index_ = 1; - current_frame_index_ = 0; - if (loop_count_ != kLoopInfinite) { - loop_count_--; - } + // Loop around to the beginning + current_frame_index_ = 0; + if (loop_count_ != kLoopInfinite) { + loop_count_--; } } + + // Update the time in the future at which point we should switch to the + // frame after the new current frame. + next_frame_time_ = + current_frame_time_ + GetFrameDuration(current_frame_index_); + if (next_frame_time_ < current_time) { + // Don't let the animation fall back for more than a frame. + next_frame_time_ = current_time; + } + + return true; +} + +base::TimeDelta AnimatedWebPImage::GetFrameDuration(int frame_index) { + lock_.AssertAcquired(); + WebPIterator webp_iterator; + WebPDemuxGetFrame(demux_, frame_index, &webp_iterator); + base::TimeDelta frame_duration = + base::TimeDelta::FromMilliseconds(webp_iterator.duration); + WebPDemuxReleaseIterator(&webp_iterator); + return frame_duration; } scoped_ptr<render_tree::ImageData> AnimatedWebPImage::AllocateImageData( @@ -340,6 +373,10 @@ return image_data.Pass(); } +bool AnimatedWebPImage::LoopingFinished() const { + return loop_count_ == 1 && current_frame_index_ == frame_count_; +} + } // namespace image } // namespace loader } // namespace cobalt
diff --git a/src/cobalt/loader/image/animated_webp_image.h b/src/cobalt/loader/image/animated_webp_image.h index 179d42e..8714c46 100644 --- a/src/cobalt/loader/image/animated_webp_image.h +++ b/src/cobalt/loader/image/animated_webp_image.h
@@ -45,18 +45,21 @@ const math::Size& GetSize() const OVERRIDE { return size_; } uint32 GetEstimatedSizeInBytes() const OVERRIDE { - return static_cast<uint32>(data_buffer_.size()); + // Return the size of 2 frames of images, since we can have two frames in + // memory at a time (the previous decode image passed to the frame provider + // and the next frame that is composed from the previous frame). + return size_.GetArea() * 4 * 2 + static_cast<uint32>(data_buffer_.size()); } bool IsOpaque() const OVERRIDE { return is_opaque_; } - scoped_refptr<const FrameProvider> GetFrameProvider() OVERRIDE; + scoped_refptr<FrameProvider> GetFrameProvider() OVERRIDE; void Play(const scoped_refptr<base::MessageLoopProxy>& message_loop) OVERRIDE; void Stop() OVERRIDE; - void AppendChunk(const uint8* data, size_t size); + void AppendChunk(const uint8* data, size_t input_byte); private: ~AnimatedWebPImage() OVERRIDE; @@ -72,11 +75,17 @@ // Decodes the frame with the given index, returns if it succeeded. bool DecodeOneFrame(int frame_index); - // Updates the index and time info of the current and next frames. - void UpdateTimelineInfo(); - scoped_ptr<render_tree::ImageData> AllocateImageData(const math::Size& size); + // If the time is right, updates the index and time info of the current frame. + bool AdvanceFrame(); + + // Returns the duration of the given frame index. + base::TimeDelta GetFrameDuration(int frame_index); + + // Returns true if the animation loop is finished. + bool LoopingFinished() const; + const math::Size size_; const bool is_opaque_; const render_tree::PixelFormat pixel_format_; @@ -89,7 +98,6 @@ // looping infinitely. int loop_count_; int current_frame_index_; - int next_frame_index_; bool should_dispose_previous_frame_to_background_; render_tree::ResourceProvider* resource_provider_; scoped_refptr<base::MessageLoopProxy> message_loop_; @@ -98,7 +106,7 @@ math::RectF previous_frame_rect_; base::CancelableClosure decode_closure_; base::TimeTicks current_frame_time_; - base::TimeTicks next_frame_time_; + base::optional<base::TimeTicks> next_frame_time_; // The original encoded data. std::vector<uint8> data_buffer_; scoped_refptr<render_tree::Image> current_canvas_;
diff --git a/src/cobalt/loader/image/image.h b/src/cobalt/loader/image/image.h index fe77dac..2b72010 100644 --- a/src/cobalt/loader/image/image.h +++ b/src/cobalt/loader/image/image.h
@@ -88,13 +88,22 @@ // that was in there. class FrameProvider : public base::RefCountedThreadSafe<FrameProvider> { public: + FrameProvider() : frame_consumed_(true) {} + void SetFrame(const scoped_refptr<render_tree::Image>& frame) { base::AutoLock lock(mutex_); frame_ = frame; + frame_consumed_ = false; } - scoped_refptr<render_tree::Image> GetFrame() const { + bool FrameConsumed() const { base::AutoLock lock(mutex_); + return frame_consumed_; + } + + scoped_refptr<render_tree::Image> GetFrame() { + base::AutoLock lock(mutex_); + frame_consumed_ = true; return frame_; } @@ -103,6 +112,9 @@ friend class base::RefCountedThreadSafe<FrameProvider>; mutable base::Lock mutex_; + // True if a call to FrameConsumed() has been made after the last call to + // SetFrame(). + bool frame_consumed_; scoped_refptr<render_tree::Image> frame_; }; @@ -121,11 +133,11 @@ // Returns a FrameProvider object from which frames can be pulled out of. // The AnimatedImage object is expected to push frames into the FrameProvider // as it generates them. - virtual scoped_refptr<const FrameProvider> GetFrameProvider() = 0; + virtual scoped_refptr<FrameProvider> GetFrameProvider() = 0; // This callback is intended to be used in a render_tree::AnimateNode. static void AnimateCallback( - scoped_refptr<const FrameProvider> frame_provider, + scoped_refptr<FrameProvider> frame_provider, const math::RectF& destination_rect, const math::Matrix3F& local_transform, render_tree::ImageNode::Builder* image_node_builder,
diff --git a/src/cobalt/loader/image/image_decoder_test.cc b/src/cobalt/loader/image/image_decoder_test.cc index 7f995fc..fda87ed 100644 --- a/src/cobalt/loader/image/image_decoder_test.cc +++ b/src/cobalt/loader/image/image_decoder_test.cc
@@ -674,7 +674,7 @@ thread.Stop(); // The image should contain the whole undecoded data from the file. - EXPECT_EQ(3224674u, animated_webp_image->GetEstimatedSizeInBytes()); + EXPECT_EQ(4261474u, animated_webp_image->GetEstimatedSizeInBytes()); EXPECT_EQ(math::Size(480, 270), animated_webp_image->GetSize()); EXPECT_TRUE(animated_webp_image->IsOpaque()); @@ -705,7 +705,7 @@ thread.Stop(); // The image should contain the whole undecoded data from the file. - EXPECT_EQ(3224674u, animated_webp_image->GetEstimatedSizeInBytes()); + EXPECT_EQ(4261474u, animated_webp_image->GetEstimatedSizeInBytes()); EXPECT_EQ(math::Size(480, 270), animated_webp_image->GetSize()); EXPECT_TRUE(animated_webp_image->IsOpaque());
diff --git a/src/cobalt/loader/image/webp_image_decoder.cc b/src/cobalt/loader/image/webp_image_decoder.cc index 74afb79..90831fc 100644 --- a/src/cobalt/loader/image/webp_image_decoder.cc +++ b/src/cobalt/loader/image/webp_image_decoder.cc
@@ -90,8 +90,20 @@ if (status == VP8_STATUS_OK) { DCHECK(image_data()); DCHECK(config_.output.u.RGBA.rgba); - SbMemoryCopy(image_data()->GetMemory(), config_.output.u.RGBA.rgba, - config_.output.u.RGBA.size); + + // Copy the image data over line by line. We copy line by line instead + // of all at once so that we can adjust for differences in pitch between + // source and destination buffers. + uint8* cur_src = config_.output.u.RGBA.rgba; + uint8* cur_dest = image_data()->GetMemory(); + int height = image_data()->GetDescriptor().size.height(); + int num_pixel_bytes = image_data()->GetDescriptor().size.width() * 4; + for (int i = 0; i < height; ++i) { + SbMemoryCopy(cur_dest, cur_src, num_pixel_bytes); + cur_src += config_.output.u.RGBA.stride; + cur_dest += image_data()->GetDescriptor().pitch_in_bytes; + } + set_state(kDone); } else if (status != VP8_STATUS_SUSPENDED) { DLOG(ERROR) << "WebPIAppend error, status code: " << status; @@ -140,10 +152,6 @@ config_.output.colorspace = pixel_format() == render_tree::kPixelFormatRGBA8 ? (has_alpha ? MODE_rgbA : MODE_RGBA) : (has_alpha ? MODE_bgrA : MODE_BGRA); - config_.output.u.RGBA.stride = image_data()->GetDescriptor().pitch_in_bytes; - config_.output.u.RGBA.size = - static_cast<size_t>(config_.output.u.RGBA.stride * - image_data()->GetDescriptor().size.height()); // We don't use image buffer as the decoding buffer because libwebp will read // from it while we assume that our image buffer is write only. config_.output.is_external_memory = 0;
diff --git a/src/cobalt/media/base/drm_system.cc b/src/cobalt/media/base/drm_system.cc index bd41763..c3f4d23 100644 --- a/src/cobalt/media/base/drm_system.cc +++ b/src/cobalt/media/base/drm_system.cc
@@ -20,8 +20,19 @@ namespace cobalt { namespace media { +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION +DrmSystem::Session::Session( + DrmSystem* drm_system, + SessionUpdateKeyStatusesCallback update_key_statuses_callback) + : drm_system_(drm_system), + update_key_statuses_callback_(update_key_statuses_callback), + closed_(false) { + DCHECK(!update_key_statuses_callback_.is_null()); +} +#else // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION DrmSystem::Session::Session(DrmSystem* drm_system) : drm_system_(drm_system), closed_(false) {} +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION DrmSystem::Session::~Session() { if (id_ && !closed_) { @@ -65,7 +76,12 @@ DrmSystem::DrmSystem(const char* key_system) : wrapped_drm_system_(SbDrmCreateSystem(key_system, this, OnSessionUpdateRequestGeneratedFunc, - OnSessionUpdatedFunc)), + OnSessionUpdatedFunc +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + , + OnSessionKeyStatusesChangedFunc +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + )), message_loop_(MessageLoop::current()), ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)), weak_this_(weak_ptr_factory_.GetWeakPtr()), @@ -76,9 +92,17 @@ DrmSystem::~DrmSystem() { SbDrmDestroySystem(wrapped_drm_system_); } +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION +scoped_ptr<DrmSystem::Session> DrmSystem::CreateSession( + SessionUpdateKeyStatusesCallback session_update_key_statuses_callback) { + return make_scoped_ptr( + new Session(this, session_update_key_statuses_callback)); +} +#else // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION scoped_ptr<DrmSystem::Session> DrmSystem::CreateSession() { return make_scoped_ptr(new Session(this)); } +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION void DrmSystem::GenerateSessionUpdateRequest( Session* session, const std::string& type, const uint8_t* init_data, @@ -202,6 +226,23 @@ ticket_to_session_update_map_.erase(session_update_iterator); } +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION +void DrmSystem::OnSessionKeyStatusChanged( + const std::string& session_id, const std::vector<std::string>& key_ids, + const std::vector<SbDrmKeyStatus>& key_statuses) { + // Find the session by ID. + IdToSessionMap::iterator session_iterator = + id_to_session_map_.find(session_id); + if (session_iterator == id_to_session_map_.end()) { + LOG(ERROR) << "Unknown session id: " << session_id << "."; + return; + } + Session* session = session_iterator->second; + + session->update_key_statuses_callback().Run(key_ids, key_statuses); +} +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + // static void DrmSystem::OnSessionUpdateRequestGeneratedFunc( SbDrmSystem wrapped_drm_system, void* context, int ticket, @@ -242,5 +283,39 @@ drm_system->weak_this_, ticket, succeeded)); } +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION +// static +void DrmSystem::OnSessionKeyStatusesChangedFunc( + SbDrmSystem wrapped_drm_system, void* context, const void* session_id, + int session_id_size, int number_of_keys, const SbDrmKeyId* key_ids, + const SbDrmKeyStatus* key_statuses) { + DCHECK(context); + DrmSystem* drm_system = static_cast<DrmSystem*>(context); + DCHECK_EQ(wrapped_drm_system, drm_system->wrapped_drm_system_); + + DCHECK(session_id != NULL); + + std::string session_id_copy = + std::string(static_cast<const char*>(session_id), + static_cast<const char*>(session_id) + session_id_size); + + std::vector<std::string> key_ids_copy(number_of_keys); + std::vector<SbDrmKeyStatus> key_statuses_copy(number_of_keys); + + for (int i = 0; i < number_of_keys; ++i) { + const char* identifier = + reinterpret_cast<const char*>(key_ids[i].identifier); + std::string key_id(identifier, identifier + key_ids[i].identifier_size); + key_ids_copy[i] = key_id; + key_statuses_copy[i] = key_statuses[i]; + } + + drm_system->message_loop_->PostTask( + FROM_HERE, + base::Bind(&DrmSystem::OnSessionKeyStatusChanged, drm_system->weak_this_, + session_id_copy, key_ids_copy, key_statuses_copy)); +} +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + } // namespace media } // namespace cobalt
diff --git a/src/cobalt/media/base/drm_system.h b/src/cobalt/media/base/drm_system.h index 7a400c8..00dfa4a 100644 --- a/src/cobalt/media/base/drm_system.h +++ b/src/cobalt/media/base/drm_system.h
@@ -16,6 +16,7 @@ #define COBALT_MEDIA_BASE_DRM_SYSTEM_H_ #include <string> +#include <vector> #include "base/hash_tables.h" #include "base/memory/ref_counted.h" @@ -43,6 +44,11 @@ typedef base::Callback<void()> SessionUpdateRequestDidNotGenerateCallback; typedef base::Callback<void()> SessionUpdatedCallback; typedef base::Callback<void()> SessionDidNotUpdateCallback; +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + typedef base::Callback<void(const std::vector<std::string>& key_ids, + const std::vector<SbDrmKeyStatus>& key_statuses)> + SessionUpdateKeyStatusesCallback; +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION // Flyweight that provides RAII semantics for sessions. // Most of logic is implemented by |DrmSystem| and thus sessions must be @@ -86,18 +92,32 @@ private: // Private API for |DrmSystem|. - explicit Session(DrmSystem* drm_system); + Session(DrmSystem* drm_system +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + , + SessionUpdateKeyStatusesCallback update_key_statuses_callback +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + ); void set_id(const std::string& id) { id_ = id; } const SessionUpdateRequestGeneratedCallback& update_request_generated_callback() const { return update_request_generated_callback_; } +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + const SessionUpdateKeyStatusesCallback& update_key_statuses_callback() + const { + return update_key_statuses_callback_; + } +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION DrmSystem* const drm_system_; bool closed_; base::optional<std::string> id_; // Supports spontaneous invocations of |SbDrmSessionUpdateRequestFunc|. SessionUpdateRequestGeneratedCallback update_request_generated_callback_; +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + SessionUpdateKeyStatusesCallback update_key_statuses_callback_; +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION friend class DrmSystem; @@ -109,7 +129,11 @@ SbDrmSystem wrapped_drm_system() { return wrapped_drm_system_; } - scoped_ptr<Session> CreateSession(); + scoped_ptr<Session> CreateSession( +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + SessionUpdateKeyStatusesCallback session_update_key_statuses_callback +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + ); private: // Stores context of |GenerateSessionUpdateRequest|. @@ -149,6 +173,11 @@ int ticket, const base::optional<std::string>& session_id, scoped_array<uint8> message, int message_size); void OnSessionUpdated(int ticket, bool succeeded); +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + void OnSessionKeyStatusChanged( + const std::string& session_id, const std::vector<std::string>& key_ids, + const std::vector<SbDrmKeyStatus>& key_statuses); +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION // Called on any thread, parameters need to be copied immediately. static void OnSessionUpdateRequestGeneratedFunc( @@ -159,6 +188,12 @@ void* context, int ticket, const void* session_id, int session_id_length, bool succeeded); +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + static void OnSessionKeyStatusesChangedFunc( + SbDrmSystem wrapped_drm_system, void* context, const void* session_id, + int session_id_size, int number_of_keys, const SbDrmKeyId* key_ids, + const SbDrmKeyStatus* key_statuses); +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION const SbDrmSystem wrapped_drm_system_; MessageLoop* const message_loop_;
diff --git a/src/cobalt/render_tree/filter_node.cc b/src/cobalt/render_tree/filter_node.cc index 84fd806..fa66bac 100644 --- a/src/cobalt/render_tree/filter_node.cc +++ b/src/cobalt/render_tree/filter_node.cc
@@ -39,19 +39,19 @@ FilterNode::FilterNode(const OpacityFilter& opacity_filter, const scoped_refptr<render_tree::Node>& source) - : data_(opacity_filter, source) {} + : data_(opacity_filter, source) { AssertValid(); } FilterNode::FilterNode(const ViewportFilter& viewport_filter, const scoped_refptr<render_tree::Node>& source) - : data_(viewport_filter, source) {} + : data_(viewport_filter, source) { AssertValid(); } FilterNode::FilterNode(const BlurFilter& blur_filter, const scoped_refptr<render_tree::Node>& source) - : data_(blur_filter, source) {} + : data_(blur_filter, source) { AssertValid(); } FilterNode::FilterNode(const MapToMeshFilter& map_to_mesh_filter, const scoped_refptr<render_tree::Node>& source) - : data_(map_to_mesh_filter, source) {} + : data_(map_to_mesh_filter, source) { AssertValid(); } void FilterNode::Accept(NodeVisitor* visitor) { visitor->Visit(this); } @@ -83,5 +83,12 @@ return destination_bounds; } +void FilterNode::AssertValid() const { + if (data_.viewport_filter && data_.viewport_filter->has_rounded_corners()) { + DCHECK(data_.viewport_filter->rounded_corners().IsNormalized( + data_.viewport_filter->viewport())); + } +} + } // namespace render_tree } // namespace cobalt
diff --git a/src/cobalt/render_tree/filter_node.h b/src/cobalt/render_tree/filter_node.h index 5ba8ac7..dc3df7c 100644 --- a/src/cobalt/render_tree/filter_node.h +++ b/src/cobalt/render_tree/filter_node.h
@@ -74,7 +74,9 @@ base::optional<MapToMeshFilter> map_to_mesh_filter; }; - explicit FilterNode(const Builder& builder) : data_(builder) {} + explicit FilterNode(const Builder& builder) : data_(builder) { + AssertValid(); + } FilterNode(const OpacityFilter& opacity_filter, const scoped_refptr<render_tree::Node>& source); @@ -98,6 +100,8 @@ const Builder& data() const { return data_; } private: + void AssertValid() const; + const Builder data_; };
diff --git a/src/cobalt/render_tree/rect_node.cc b/src/cobalt/render_tree/rect_node.cc index 7b6f656..17b046e 100644 --- a/src/cobalt/render_tree/rect_node.cc +++ b/src/cobalt/render_tree/rect_node.cc
@@ -88,5 +88,11 @@ math::RectF RectNode::GetBounds() const { return data_.rect; } +void RectNode::AssertValid() const { + if (data_.rounded_corners) { + DCHECK(data_.rounded_corners->IsNormalized(data_.rect)); + } +} + } // namespace render_tree } // namespace cobalt
diff --git a/src/cobalt/render_tree/rect_node.h b/src/cobalt/render_tree/rect_node.h index a632890..a257cd8 100644 --- a/src/cobalt/render_tree/rect_node.h +++ b/src/cobalt/render_tree/rect_node.h
@@ -69,31 +69,39 @@ RectNode(const math::RectF& rect, scoped_ptr<Border> border) : data_(rect, border.Pass()) { + AssertValid(); } RectNode(const math::RectF& rect, scoped_ptr<Border> border, scoped_ptr<RoundedCorners> rounded_corners) : data_(rect, border.Pass(), rounded_corners.Pass()) { + AssertValid(); } RectNode(const math::RectF& rect, scoped_ptr<Brush> background_brush) : data_(rect, background_brush.Pass()) { + AssertValid(); } RectNode(const math::RectF& rect, scoped_ptr<Brush> background_brush, scoped_ptr<Border> border) : data_(rect, background_brush.Pass(), border.Pass()) { + AssertValid(); } RectNode(const math::RectF& rect, scoped_ptr<Brush> background_brush, scoped_ptr<RoundedCorners> rounded_corners) : data_(rect, background_brush.Pass(), rounded_corners.Pass()) { + AssertValid(); } RectNode(const math::RectF& rect, scoped_ptr<Brush> background_brush, scoped_ptr<Border> border, scoped_ptr<RoundedCorners> rounded_corners) : data_(rect, background_brush.Pass(), border.Pass(), rounded_corners.Pass()) { + AssertValid(); } explicit RectNode(const Builder& builder) : data_(builder) { + AssertValid(); } explicit RectNode(Builder::Moved builder) : data_(builder) { + AssertValid(); } void Accept(NodeVisitor* visitor) OVERRIDE; @@ -106,6 +114,8 @@ const Builder& data() const { return data_; } private: + void AssertValid() const; + const Builder data_; };
diff --git a/src/cobalt/render_tree/rect_shadow_node.cc b/src/cobalt/render_tree/rect_shadow_node.cc index 3e602a3..622d42c 100644 --- a/src/cobalt/render_tree/rect_shadow_node.cc +++ b/src/cobalt/render_tree/rect_shadow_node.cc
@@ -31,5 +31,11 @@ } } +void RectShadowNode::AssertValid() const { + if (data_.rounded_corners) { + DCHECK(data_.rounded_corners->IsNormalized(data_.rect)); + } +} + } // namespace render_tree } // namespace cobalt
diff --git a/src/cobalt/render_tree/rect_shadow_node.h b/src/cobalt/render_tree/rect_shadow_node.h index 22344ad..072c80b 100644 --- a/src/cobalt/render_tree/rect_shadow_node.h +++ b/src/cobalt/render_tree/rect_shadow_node.h
@@ -60,14 +60,16 @@ float spread; }; - explicit RectShadowNode(const Builder& builder) : data_(builder) {} + explicit RectShadowNode(const Builder& builder) : data_(builder) { + AssertValid(); + } RectShadowNode(const math::RectF& rect, const Shadow& shadow) - : data_(rect, shadow) {} + : data_(rect, shadow) { AssertValid(); } RectShadowNode(const math::RectF& rect, const Shadow& shadow, bool inset, float spread) - : data_(rect, shadow, inset, spread) {} + : data_(rect, shadow, inset, spread) { AssertValid(); } void Accept(NodeVisitor* visitor) OVERRIDE; math::RectF GetBounds() const OVERRIDE; @@ -79,6 +81,8 @@ const Builder& data() const { return data_; } private: + void AssertValid() const; + const Builder data_; };
diff --git a/src/cobalt/render_tree/rounded_corners.cc b/src/cobalt/render_tree/rounded_corners.cc index a74a30b..b0a3331 100644 --- a/src/cobalt/render_tree/rounded_corners.cc +++ b/src/cobalt/render_tree/rounded_corners.cc
@@ -17,38 +17,59 @@ namespace cobalt { namespace render_tree { -void RoundedCorners::Normalize(const math::RectF& rect) { +RoundedCorners RoundedCorners::Normalize(const math::RectF& rect) const { float scale = 1.0f; float size; - size = top_left.horizontal + top_right.horizontal; + // Normalize overlapping curves. + // https://www.w3.org/TR/css3-background/#corner-overlap + // Additionally, normalize opposing curves so the corners do not overlap. + size = top_left.horizontal + + std::max(top_right.horizontal, bottom_right.horizontal); if (size > rect.width()) { scale = rect.width() / size; } - size = bottom_left.horizontal + bottom_right.horizontal; + size = bottom_left.horizontal + + std::max(bottom_right.horizontal, top_right.horizontal); if (size > rect.width()) { scale = std::min(rect.width() / size, scale); } - size = top_left.vertical + bottom_left.vertical; + size = top_left.vertical + + std::max(bottom_left.vertical, bottom_right.vertical); if (size > rect.height()) { scale = std::min(rect.height() / size, scale); } - size = top_right.vertical + bottom_right.vertical; + size = top_right.vertical + + std::max(bottom_right.vertical, bottom_left.vertical); if (size > rect.height()) { scale = std::min(rect.height() / size, scale); } - top_left.horizontal *= scale; - top_left.vertical *= scale; - top_right.horizontal *= scale; - top_right.vertical *= scale; - bottom_left.horizontal *= scale; - bottom_left.vertical *= scale; - bottom_right.horizontal *= scale; - bottom_right.vertical *= scale; + return RoundedCorners(RoundedCorner(top_left.horizontal * scale, + top_left.vertical * scale), + RoundedCorner(top_right.horizontal * scale, + top_right.vertical * scale), + RoundedCorner(bottom_right.horizontal * scale, + bottom_right.vertical * scale), + RoundedCorner(bottom_left.horizontal * scale, + bottom_left.vertical * scale)); +} + +bool RoundedCorners::IsNormalized(const math::RectF& rect) const { + return + // Adjacent corners must not overlap. + top_left.horizontal + top_right.horizontal <= rect.width() && + bottom_left.horizontal + bottom_right.horizontal <= rect.width() && + top_left.vertical + bottom_left.vertical <= rect.height() && + top_right.vertical + bottom_right.vertical <= rect.height() && + // Opposing corners must not overlap. + top_left.horizontal + bottom_right.horizontal <= rect.width() && + bottom_left.horizontal + top_right.horizontal <= rect.width() && + top_left.vertical + bottom_right.vertical <= rect.height() && + top_right.vertical + bottom_left.vertical <= rect.height(); } } // namespace render_tree
diff --git a/src/cobalt/render_tree/rounded_corners.h b/src/cobalt/render_tree/rounded_corners.h index 0a9a09d..cf1d03e 100644 --- a/src/cobalt/render_tree/rounded_corners.h +++ b/src/cobalt/render_tree/rounded_corners.h
@@ -93,7 +93,8 @@ // Ensure the rounded corners' radii do not exceed the length of the // corresponding edge of the given rect. - void Normalize(const math::RectF& rect); + RoundedCorners Normalize(const math::RectF& rect) const; + bool IsNormalized(const math::RectF& rect) const; bool AreSquares() const { return top_left.IsSquare() && top_right.IsSquare() &&
diff --git a/src/cobalt/renderer/backend/egl/graphics_system.cc b/src/cobalt/renderer/backend/egl/graphics_system.cc index ae84a45..4b317b0 100644 --- a/src/cobalt/renderer/backend/egl/graphics_system.cc +++ b/src/cobalt/renderer/backend/egl/graphics_system.cc
@@ -69,27 +69,33 @@ // Setup our configuration to support RGBA and compatibility with PBuffer // objects (for offscreen rendering). - EGLint attribute_list[] = {EGL_SURFACE_TYPE, // this must be first - EGL_WINDOW_BIT | EGL_PBUFFER_BIT + EGLint attribute_list[] = { + EGL_SURFACE_TYPE, // this must be first + EGL_WINDOW_BIT | EGL_PBUFFER_BIT #if defined(COBALT_RENDER_DIRTY_REGION_ONLY) - | EGL_SWAP_BEHAVIOR_PRESERVED_BIT + | EGL_SWAP_BEHAVIOR_PRESERVED_BIT #endif // #if defined(COBALT_RENDER_DIRTY_REGION_ONLY) - , - EGL_RED_SIZE, - 8, - EGL_GREEN_SIZE, - 8, - EGL_BLUE_SIZE, - 8, - EGL_ALPHA_SIZE, - 8, + , + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 8, #if !SB_HAS_QUIRK(NO_EGL_BIND_TO_TEXTURE) - EGL_BIND_TO_TEXTURE_RGBA, - EGL_TRUE, + EGL_BIND_TO_TEXTURE_RGBA, + EGL_TRUE, #endif - EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, - EGL_NONE}; + EGL_RENDERABLE_TYPE, +#if defined(GLES3_SUPPORTED) + EGL_OPENGL_ES3_BIT, +#else + EGL_OPENGL_ES2_BIT, +#endif // #if defined(GLES3_SUPPORTED) + EGL_NONE + }; EGLint num_configs; eglChooseConfig(display_, attribute_list, &config_, 1, &num_configs);
diff --git a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc index 4a95847..3defd2e 100644 --- a/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc +++ b/src/cobalt/renderer/rasterizer/blitter/render_tree_node_visitor.cc
@@ -190,6 +190,11 @@ void RenderTreeNodeVisitor::Visit(render_tree::ImageNode* image_node) { TRACE_EVENT0_IF_ENABLED("Visit(ImageNode)"); + // The image_node may contain nothing. For example, when it represents a video + // or other kind of animated image element before any frame is decoded. + if (!image_node->data().source) { + return; + } // All Blitter API images derive from skia::Image (so that they can be // compatible with the Skia software renderer), so we start here by casting
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_object.cc b/src/cobalt/renderer/rasterizer/egl/draw_object.cc index 9dc8082..c2084cf 100644 --- a/src/cobalt/renderer/rasterizer/egl/draw_object.cc +++ b/src/cobalt/renderer/rasterizer/egl/draw_object.cc
@@ -59,21 +59,11 @@ void DrawObject::SetRRectUniforms(GLint rect_uniform, GLint corners_uniform, const math::RectF& rect, const render_tree::RoundedCorners& corners, float inset) { - // Ensure corner sizes are non-zero to allow generic handling of square and - // rounded corners. - const float kMinCornerSize = 0.01f; - math::RectF inset_rect(rect); inset_rect.Inset(inset, inset); render_tree::RoundedCorners inset_corners = corners.Inset(inset, inset, inset, inset); - // The rect data is a vec4 representing (min.xy, max.xy). - float rect_data[4] = { - inset_rect.x(), inset_rect.y(), inset_rect.right(), inset_rect.bottom(), - }; - GL_CALL(glUniform4fv(rect_uniform, 1, rect_data)); - // Tweak corners that are square-ish so they have values that play // nicely with the shader. Interpolating x^2 / a^2 + y^2 / b^2 does not // work well when |a| or |b| are very small. @@ -98,26 +88,40 @@ inset_corners.bottom_right.vertical = 0.0f; } + // Ensure corner sizes are non-zero to allow generic handling of square and + // rounded corners. + const float kMinCornerSize = 0.01f; + inset_rect.Outset(kMinCornerSize, kMinCornerSize); + inset_corners = inset_corners.Inset(-kMinCornerSize, -kMinCornerSize, + -kMinCornerSize, -kMinCornerSize); + inset_corners = inset_corners.Normalize(inset_rect); + + // The rect data is a vec4 representing (min.xy, max.xy). + float rect_data[4] = { + inset_rect.x(), inset_rect.y(), inset_rect.right(), inset_rect.bottom(), + }; + GL_CALL(glUniform4fv(rect_uniform, 1, rect_data)); + // The corners data is a mat4 with each vector representing a corner // (ordered top left, top right, bottom left, bottom right). Each corner // vec4 represents (start.xy, radius.xy). float corners_data[16] = { inset_rect.x() + inset_corners.top_left.horizontal, inset_rect.y() + inset_corners.top_left.vertical, - std::max(inset_corners.top_left.horizontal, kMinCornerSize), - std::max(inset_corners.top_left.vertical, kMinCornerSize), + inset_corners.top_left.horizontal, + inset_corners.top_left.vertical, inset_rect.right() - inset_corners.top_right.horizontal, inset_rect.y() + inset_corners.top_right.vertical, - std::max(inset_corners.top_right.horizontal, kMinCornerSize), - std::max(inset_corners.top_right.vertical, kMinCornerSize), + inset_corners.top_right.horizontal, + inset_corners.top_right.vertical, inset_rect.x() + inset_corners.bottom_left.horizontal, inset_rect.bottom() - inset_corners.bottom_left.vertical, - std::max(inset_corners.bottom_left.horizontal, kMinCornerSize), - std::max(inset_corners.bottom_left.vertical, kMinCornerSize), + inset_corners.bottom_left.horizontal, + inset_corners.bottom_left.vertical, inset_rect.right() - inset_corners.bottom_right.horizontal, inset_rect.bottom() - inset_corners.bottom_right.vertical, - std::max(inset_corners.bottom_right.horizontal, kMinCornerSize), - std::max(inset_corners.bottom_right.vertical, kMinCornerSize), + inset_corners.bottom_right.horizontal, + inset_corners.bottom_right.vertical, }; GL_CALL(glUniformMatrix4fv(corners_uniform, 1, false, corners_data)); }
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_object_manager.cc b/src/cobalt/renderer/rasterizer/egl/draw_object_manager.cc index 7662e3c..6212f5f 100644 --- a/src/cobalt/renderer/rasterizer/egl/draw_object_manager.cc +++ b/src/cobalt/renderer/rasterizer/egl/draw_object_manager.cc
@@ -130,7 +130,7 @@ draw->draw_object->ExecuteUpdateVertexBuffer( graphics_state, program_manager); } - graphics_state->UpdateVertexData(); + graphics_state->UpdateVertexBuffers(); } void DrawObjectManager::ExecuteOnscreenRasterize(GraphicsState* graphics_state,
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rect_shadow_blur.cc b/src/cobalt/renderer/rasterizer/egl/draw_rect_shadow_blur.cc index c8031c5..eefc2fe 100644 --- a/src/cobalt/renderer/rasterizer/egl/draw_rect_shadow_blur.cc +++ b/src/cobalt/renderer/rasterizer/egl/draw_rect_shadow_blur.cc
@@ -28,59 +28,55 @@ namespace egl { namespace { +const float kSqrt2 = 1.414213562f; +const float kSqrtPi = 1.772453851f; + // The blur kernel extends for a limited number of sigmas. const float kBlurExtentInSigmas = 3.0f; -// The gaussian integral formula used to calculate blur intensity reaches 0 -// intensity at a distance of 1.5. To express pixels in terms of input for -// this function, a distance of kBlurExtentInSigmas * |blur_sigma| should equal -// kBlurDistance. -const float kBlurDistance = 1.5f; +// The error function is used to calculate the gaussian blur. Inputs for +// the error function should be scaled by 1 / (sqrt(2) * sigma). Alternatively, +// it can be viewed as kBlurDistance is the input value at which the blur +// intensity is effectively 0. +const float kBlurDistance = kBlurExtentInSigmas / kSqrt2; -void SetSigmaTweak(GLint sigma_tweak_uniform, const math::RectF& spread_rect, - const DrawObject::OptionalRoundedCorners& spread_corners, - float blur_sigma) { - const float kBlurExtentInPixels = kBlurExtentInSigmas * blur_sigma; +void SetBlurRRectUniforms(const ShaderFragmentColorBlurRrects& shader, + math::RectF rect, render_tree::RoundedCorners corners, float sigma) { + // Ensure a minimum radius for each corner to avoid division by zero. + const float kMinSize = 0.01f; - // If the blur kernel is larger than the spread rect, then adjust the input - // values to the blur calculations to better match the reference output. - const float kTweakScale = 0.15f; - float sigma_tweak[2] = { - std::max(kBlurExtentInPixels - spread_rect.width(), 0.0f) * - kTweakScale / blur_sigma, - std::max(kBlurExtentInPixels - spread_rect.height(), 0.0f) * - kTweakScale / blur_sigma, - }; + rect.Outset(kMinSize, kMinSize); + corners = corners.Inset(-kMinSize, -kMinSize, -kMinSize, -kMinSize); + corners = corners.Normalize(rect); - if (spread_corners) { - // The shader for blur with rounded rects does not fully factor in - // proximity to rounded corners. For example, given a 15-pixel wide - // spread rect with two neighboring rounded corners with radius 7, - // the center pixels would not include the nearby corners in the - // calculation of distance to the edge -- it would always be 7. - float corner_gap[2] = { - std::min(spread_rect.width() - spread_corners->top_left.horizontal - - spread_corners->top_right.horizontal, - spread_rect.width() - spread_corners->bottom_left.horizontal - - spread_corners->bottom_right.horizontal), - std::min(spread_rect.height() - spread_corners->top_left.vertical - - spread_corners->bottom_left.vertical, - spread_rect.height() - spread_corners->top_right.vertical - - spread_corners->bottom_right.vertical), - }; + // Specify the blur extent size and the (min.y, max.y) for the rect. + const float kBlurExtentInPixels = kBlurExtentInSigmas * sigma; + GL_CALL(glUniform3f(shader.u_blur_extent(), + kBlurExtentInPixels, rect.y(), rect.bottom())); - // This tweak is limited because each edge can have different-sized - // gaps between corners. However, the shader is already pretty large, - // so this tweak will do for now. The situation is only noticeable with - // relatively large blur sigmas. - const float kCornerTweakScale = 0.03f; - sigma_tweak[0] += std::max(kBlurExtentInPixels - corner_gap[0], 0.0f) * - kCornerTweakScale / blur_sigma; - sigma_tweak[1] += std::max(kBlurExtentInPixels - corner_gap[1], 0.0f) * - kCornerTweakScale / blur_sigma; - } - - GL_CALL(glUniform2fv(sigma_tweak_uniform, 1, sigma_tweak)); + // Set the "start" and "scale" values so that (pos - start) * scale is in the + // first quadrant and normalized. Then specify "radius" so that normalized * + // radius + start specifies a point on the respective corner. + GL_CALL(glUniform4f(shader.u_spread_start_x(), + rect.x() + corners.top_left.horizontal, + rect.right() - corners.top_right.horizontal, + rect.x() + corners.bottom_left.horizontal, + rect.right() - corners.bottom_right.horizontal)); + GL_CALL(glUniform4f(shader.u_spread_start_y(), + rect.y() + corners.top_left.vertical, + rect.y() + corners.top_right.vertical, + rect.bottom() - corners.bottom_left.vertical, + rect.bottom() - corners.bottom_right.vertical)); + GL_CALL(glUniform4f(shader.u_spread_scale_y(), + -1.0f / corners.top_left.vertical, + -1.0f / corners.top_right.vertical, + 1.0f / corners.bottom_left.vertical, + 1.0f / corners.bottom_right.vertical)); + GL_CALL(glUniform4f(shader.u_spread_radius_x(), + -corners.top_left.horizontal, + corners.top_right.horizontal, + -corners.bottom_left.horizontal, + corners.bottom_right.horizontal)); } } // namespace @@ -125,9 +121,6 @@ DCHECK(inner_corners_); DCHECK(outer_corners_); DCHECK(spread_corners_); - inner_corners_->Normalize(inner_rect_); - outer_corners_->Normalize(outer_rect_); - spread_corners_->Normalize(spread_rect_); } else { // Non-rounded rects specify vertex offset in terms of sigma from the // center of the spread rect. @@ -152,8 +145,11 @@ float sigma_scale = kBlurDistance / (kBlurExtentInSigmas * blur_sigma_); GL_CALL(glUniform2f(program->GetFragmentShader().u_sigma_scale(), sigma_scale, sigma_scale)); - SetSigmaTweak(program->GetFragmentShader().u_sigma_tweak(), - spread_rect_, spread_corners_, blur_sigma_); + + // Pre-calculate the scale values to calculate the normalized gaussian. + GL_CALL(glUniform2f(program->GetFragmentShader().u_gaussian_scale(), + -1.0f / (2.0f * blur_sigma_ * blur_sigma_), + 1.0f / (kSqrt2 * kSqrtPi * blur_sigma_))); if (is_inset_) { // Set the outer rect to be an inclusive scissor, and invert the shadow. SetRRectUniforms(program->GetFragmentShader().u_scissor_rect(), @@ -169,18 +165,14 @@ GL_CALL(glUniform2f(program->GetFragmentShader().u_scale_add(), 1.0f, 0.0f)); } - SetRRectUniforms(program->GetFragmentShader().u_spread_rect(), - program->GetFragmentShader().u_spread_corners(), - spread_rect_, *spread_corners_, 0.0f); + SetBlurRRectUniforms(program->GetFragmentShader(), + spread_rect_, *spread_corners_, blur_sigma_); } else { ShaderProgram<CommonVertexShader, ShaderFragmentColorBlur>* program; program_manager->GetProgram(&program); graphics_state->UseProgram(program->GetHandle()); SetupShader(program->GetVertexShader(), graphics_state); - - SetSigmaTweak(program->GetFragmentShader().u_sigma_tweak(), - spread_rect_, spread_corners_, blur_sigma_); if (is_inset_) { // Invert the shadow. GL_CALL(glUniform2f(program->GetFragmentShader().u_scale_add(), @@ -190,9 +182,11 @@ GL_CALL(glUniform2f(program->GetFragmentShader().u_scale_add(), 1.0f, 0.0f)); } - GL_CALL(glUniform2f(program->GetFragmentShader().u_blur_radius(), - spread_rect_.width() * 0.5f * offset_scale_, - spread_rect_.height() * 0.5f * offset_scale_)); + GL_CALL(glUniform4f(program->GetFragmentShader().u_blur_rect(), + (spread_rect_.x() - offset_center_.x()) * offset_scale_, + (spread_rect_.y() - offset_center_.y()) * offset_scale_, + (spread_rect_.right() - offset_center_.x()) * offset_scale_, + (spread_rect_.bottom() - offset_center_.y()) * offset_scale_)); } GL_CALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, vertex_count_));
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rect_shadow_spread.cc b/src/cobalt/renderer/rasterizer/egl/draw_rect_shadow_spread.cc index abbd45f..56b7427 100644 --- a/src/cobalt/renderer/rasterizer/egl/draw_rect_shadow_spread.cc +++ b/src/cobalt/renderer/rasterizer/egl/draw_rect_shadow_spread.cc
@@ -49,8 +49,6 @@ // rounded corner definitions. DCHECK(inner_corners_); DCHECK(outer_corners_); - inner_corners_->Normalize(inner_rect_); - outer_corners_->Normalize(outer_rect_); } graphics_state->ReserveVertexData(kVertexCount * sizeof(VertexAttributes)); }
diff --git a/src/cobalt/renderer/rasterizer/egl/draw_rrect_color.cc b/src/cobalt/renderer/rasterizer/egl/draw_rrect_color.cc index c56a4ba..f63e1b5 100644 --- a/src/cobalt/renderer/rasterizer/egl/draw_rrect_color.cc +++ b/src/cobalt/renderer/rasterizer/egl/draw_rrect_color.cc
@@ -52,7 +52,6 @@ corners_(corners), vertex_buffer_(NULL) { color_ = GetGLRGBA(color * base_state_.opacity); - corners_.Normalize(rect_); graphics_state->ReserveVertexData(kVertexCount * sizeof(VertexAttributes)); }
diff --git a/src/cobalt/renderer/rasterizer/egl/graphics_state.cc b/src/cobalt/renderer/rasterizer/egl/graphics_state.cc index d97d12a..64c3c54 100644 --- a/src/cobalt/renderer/rasterizer/egl/graphics_state.cc +++ b/src/cobalt/renderer/rasterizer/egl/graphics_state.cc
@@ -45,23 +45,24 @@ : render_target_handle_(0), render_target_serial_(0), frame_index_(0), + vertex_data_capacity_(0), vertex_data_reserved_(kVertexDataAlignment - 1), vertex_data_allocated_(0), - vertex_data_buffer_updated_(false) { - GL_CALL(glGenBuffers(kNumFramesBuffered, &vertex_data_buffer_handle_[0])); + vertex_index_capacity_(0), + vertex_index_reserved_(0), + vertex_index_allocated_(0), + vertex_buffers_updated_(false) { + GL_CALL(glGenBuffers(kNumFramesBuffered, vertex_data_buffer_handle_)); + GL_CALL(glGenBuffers(kNumFramesBuffered, vertex_index_buffer_handle_)); memset(clip_adjustment_, 0, sizeof(clip_adjustment_)); SetDirty(); blend_enabled_ = false; Reset(); - - // These settings should only need to be set once. Nothing should touch them. - GL_CALL(glDisable(GL_DITHER)); - GL_CALL(glDisable(GL_CULL_FACE)); - GL_CALL(glDisable(GL_STENCIL_TEST)); } GraphicsState::~GraphicsState() { - GL_CALL(glDeleteBuffers(kNumFramesBuffered, &vertex_data_buffer_handle_[0])); + GL_CALL(glDeleteBuffers(kNumFramesBuffered, vertex_data_buffer_handle_)); + GL_CALL(glDeleteBuffers(kNumFramesBuffered, vertex_index_buffer_handle_)); } void GraphicsState::SetDirty() { @@ -71,8 +72,14 @@ void GraphicsState::BeginFrame() { DCHECK_EQ(vertex_data_allocated_, 0); - if (vertex_data_reserved_ > vertex_data_buffer_.capacity()) { - vertex_data_buffer_.reserve(vertex_data_reserved_); + if (vertex_data_reserved_ > vertex_data_capacity_) { + vertex_data_capacity_ = vertex_data_reserved_; + vertex_data_buffer_.reset(new uint8_t[vertex_data_capacity_]); + } + DCHECK_EQ(vertex_index_allocated_, 0); + if (vertex_index_reserved_ > vertex_index_capacity_) { + vertex_index_capacity_ = vertex_index_reserved_; + vertex_index_buffer_.reset(new uint16_t[vertex_index_capacity_]); } // Reset to default GL state. Assume the current state is dirty, so just @@ -83,10 +90,12 @@ } void GraphicsState::EndFrame() { - // Reset the vertex data buffer. + // Reset the vertex data and index buffers. vertex_data_reserved_ = kVertexDataAlignment - 1; vertex_data_allocated_ = 0; - vertex_data_buffer_updated_ = false; + vertex_index_reserved_ = 0; + vertex_index_allocated_ = 0; + vertex_buffers_updated_ = false; frame_index_ = (frame_index_ + 1) % kNumFramesBuffered; // Force default GL state. The current state may be marked dirty, so don't @@ -123,10 +132,16 @@ GL_CALL(glUseProgram(program)); } - if (array_buffer_handle_ != vertex_data_buffer_handle_[frame_index_]) { + if (vertex_data_allocated_ > 0 && + array_buffer_handle_ != vertex_data_buffer_handle_[frame_index_]) { array_buffer_handle_ = vertex_data_buffer_handle_[frame_index_]; GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, array_buffer_handle_)); } + if (vertex_index_allocated_ > 0 && + index_buffer_handle_ != vertex_index_buffer_handle_[frame_index_]) { + index_buffer_handle_ = vertex_index_buffer_handle_[frame_index_]; + GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_handle_)); + } // Disable any vertex attribute arrays that will not be used. disable_vertex_attrib_array_mask_ = enabled_vertex_attrib_array_mask_; @@ -282,13 +297,13 @@ void GraphicsState::ReserveVertexData(size_t bytes) { DCHECK_EQ(vertex_data_allocated_, 0); - DCHECK(!vertex_data_buffer_updated_); + DCHECK(!vertex_buffers_updated_); vertex_data_reserved_ += bytes + (kVertexDataAlignment - 1) & ~(kVertexDataAlignment - 1); } uint8_t* GraphicsState::AllocateVertexData(size_t bytes) { - DCHECK(!vertex_data_buffer_updated_); + DCHECK(!vertex_buffers_updated_); // Ensure the start address is aligned. uintptr_t start_address = @@ -303,16 +318,50 @@ return reinterpret_cast<uint8_t*>(start_address); } -void GraphicsState::UpdateVertexData() { - DCHECK(!vertex_data_buffer_updated_); - vertex_data_buffer_updated_ = true; - if (array_buffer_handle_ != vertex_data_buffer_handle_[frame_index_]) { - array_buffer_handle_ = vertex_data_buffer_handle_[frame_index_]; - GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, array_buffer_handle_)); - } +void GraphicsState::ReserveVertexIndices(size_t count) { + DCHECK_EQ(vertex_index_allocated_, 0); + DCHECK(!vertex_buffers_updated_); + vertex_index_reserved_ += count; +} + +uint16_t* GraphicsState::AllocateVertexIndices(size_t count) { + uint16_t* client_pointer = &vertex_index_buffer_[vertex_index_allocated_]; + vertex_index_allocated_ += count; + DCHECK_LE(vertex_index_allocated_, vertex_index_reserved_); + return client_pointer; +} + +const void* GraphicsState::GetVertexIndexPointer( + const uint16_t* client_pointer) { + DCHECK_GE(client_pointer, &vertex_index_buffer_[0]); + DCHECK_LE(client_pointer, &vertex_index_buffer_[vertex_index_allocated_]); + const GLvoid* gl_pointer = reinterpret_cast<const GLvoid*>( + reinterpret_cast<const uint8_t*>(client_pointer) - + reinterpret_cast<const uint8_t*>(&vertex_index_buffer_[0])); + return gl_pointer; +} + +void GraphicsState::UpdateVertexBuffers() { + DCHECK(!vertex_buffers_updated_); + vertex_buffers_updated_ = true; + if (vertex_data_allocated_ > 0) { + if (array_buffer_handle_ != vertex_data_buffer_handle_[frame_index_]) { + array_buffer_handle_ = vertex_data_buffer_handle_[frame_index_]; + GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, array_buffer_handle_)); + } GL_CALL(glBufferData(GL_ARRAY_BUFFER, vertex_data_allocated_, - &vertex_data_buffer_[0], GL_STREAM_DRAW)); + &vertex_data_buffer_[0], GL_DYNAMIC_DRAW)); + } + + if (vertex_index_allocated_ > 0) { + if (index_buffer_handle_ != vertex_index_buffer_handle_[frame_index_]) { + index_buffer_handle_ = vertex_index_buffer_handle_[frame_index_]; + GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_handle_)); + } + GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, + vertex_index_allocated_ * sizeof(uint16_t), + &vertex_index_buffer_[0], GL_DYNAMIC_DRAW)); } } @@ -346,12 +395,17 @@ void GraphicsState::Reset() { program_ = 0; + GL_CALL(glDisable(GL_DITHER)); + GL_CALL(glDisable(GL_STENCIL_TEST)); + GL_CALL(glDisable(GL_CULL_FACE)); + GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, render_target_handle_)); GLViewport(viewport_, render_target_size_); GLScissor(scissor_, render_target_size_); GL_CALL(glEnable(GL_SCISSOR_TEST)); array_buffer_handle_ = 0; + index_buffer_handle_ = 0; texture_unit_ = 0; memset(&texunit_target_, 0, sizeof(texunit_target_)); memset(&texunit_texture_, 0, sizeof(texunit_texture_)); @@ -359,9 +413,15 @@ disable_vertex_attrib_array_mask_ = 0; clip_adjustment_dirty_ = true; - if (vertex_data_buffer_updated_) { - array_buffer_handle_ = vertex_data_buffer_handle_[frame_index_]; - GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, array_buffer_handle_)); + if (vertex_buffers_updated_) { + if (vertex_data_allocated_ > 0) { + array_buffer_handle_ = vertex_data_buffer_handle_[frame_index_]; + GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, array_buffer_handle_)); + } + if (vertex_index_allocated_ > 0) { + index_buffer_handle_ = vertex_index_buffer_handle_[frame_index_]; + GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_handle_)); + } } if (blend_enabled_) {
diff --git a/src/cobalt/renderer/rasterizer/egl/graphics_state.h b/src/cobalt/renderer/rasterizer/egl/graphics_state.h index dcc8c3c..51c8ec5 100644 --- a/src/cobalt/renderer/rasterizer/egl/graphics_state.h +++ b/src/cobalt/renderer/rasterizer/egl/graphics_state.h
@@ -16,9 +16,9 @@ #define COBALT_RENDERER_RASTERIZER_EGL_GRAPHICS_STATE_H_ #include <GLES2/gl2.h> -#include <vector> #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" #include "cobalt/math/matrix3_f.h" #include "cobalt/math/rect.h" #include "cobalt/math/size.h" @@ -104,9 +104,23 @@ // be done after all calls to ReserveVertexData for a given render frame. uint8_t* AllocateVertexData(size_t bytes); - // Update the GPU with the current contents of the vertex data buffer. This - // should only be called once, after BeginFrame(). - void UpdateVertexData(); + // Reserve the specified number of vertex indices for the upcoming frame. + // This must be called outside of a render frame. + void ReserveVertexIndices(size_t count); + + // Returns a client-side pointer to the specified number of vertex indices. + // These indices should have been reserved using ReserveVertexIndices. + // Allocations can only be made after all calls to reserve indices for a + // given frame. + uint16_t* AllocateVertexIndices(size_t count); + + // Return a pointer to a previously allocated vertex index buffer. The return + // value is suitable for use with glDrawElements. + const GLvoid* GetVertexIndexPointer(const uint16_t* client_pointer); + + // Update the GPU with the current contents of the vertex data and index + // buffers. This should only be called once, after BeginFrame(). + void UpdateVertexBuffers(); // Specify vertex attribute data that the current program will use. // |client_pointer| should be within the range of addresses returned by @@ -134,6 +148,7 @@ GLuint program_; GLuint array_buffer_handle_; + GLuint index_buffer_handle_; GLenum texture_unit_; uint32_t enabled_vertex_attrib_array_mask_; uint32_t disable_vertex_attrib_array_mask_; @@ -151,11 +166,17 @@ int frame_index_; static const size_t kVertexDataAlignment = 4; - std::vector<uint8_t> vertex_data_buffer_; + scoped_array<uint8_t> vertex_data_buffer_; + size_t vertex_data_capacity_; size_t vertex_data_reserved_; size_t vertex_data_allocated_; GLuint vertex_data_buffer_handle_[kNumFramesBuffered]; - bool vertex_data_buffer_updated_; + scoped_array<uint16_t> vertex_index_buffer_; + size_t vertex_index_capacity_; + size_t vertex_index_reserved_; + size_t vertex_index_allocated_; + GLuint vertex_index_buffer_handle_[kNumFramesBuffered]; + bool vertex_buffers_updated_; }; } // namespace egl
diff --git a/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc index e0b33bb..bcd8e49 100644 --- a/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc +++ b/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc
@@ -156,6 +156,10 @@ RasterizeTree(render_tree, render_target_egl, content_rect); graphics_context_->SwapBuffers(render_target_egl); + + // Reset the fallback context in case it is used between frames (e.g. + // to initialize images). + GetFallbackContext()->resetContext(); } void HardwareRasterizer::Impl::SubmitToFallbackRasterizer(
diff --git a/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc index 8153798..c065daf 100644 --- a/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc +++ b/src/cobalt/renderer/rasterizer/egl/render_tree_node_visitor.cc
@@ -214,8 +214,6 @@ draw_state_.rounded_scissor_rect = data.viewport_filter->viewport(); draw_state_.rounded_scissor_corners = data.viewport_filter->rounded_corners(); - draw_state_.rounded_scissor_corners->Normalize( - draw_state_.rounded_scissor_rect); data.source->Accept(this); draw_state_.rounded_scissor_corners = base::nullopt; return;
diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur.glsl b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur.glsl index d83bd62..50ebd6a 100644 --- a/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur.glsl +++ b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur.glsl
@@ -13,54 +13,19 @@ // limitations under the License. precision mediump float; -uniform vec2 u_blur_radius; +uniform vec4 u_blur_rect; uniform vec2 u_scale_add; -// Adjust the sigma input value to tweak the blur output so that it better -// matches the reference. This is usually only needed for very large sigmas. -uniform vec2 u_sigma_tweak; - -varying vec2 v_offset; // Relative to the blur center. +varying vec2 v_offset; varying vec4 v_color; +#include "function_gaussian_integral.inc" + void main() { - // Distance from the blur radius. - // Both v_offset and u_blur_radius are expressed in terms of the - // blur sigma. - vec2 pos = abs(v_offset) - u_blur_radius + u_sigma_tweak; - vec2 pos2 = pos * pos; - vec2 pos3 = pos2 * pos; - vec4 posx = vec4(1.0, pos.x, pos2.x, pos3.x); - vec4 posy = vec4(1.0, pos.y, pos2.y, pos3.y); - - // Approximation of the gaussian integral from [x, +inf). - // http://stereopsis.com/shadowrect/ - const vec4 klower = vec4(0.4375, -1.125, -0.75, -0.1666666); - const vec4 kmiddle = vec4(0.5, -0.75, 0.0, 0.3333333); - const vec4 kupper = vec4(0.5625, -1.125, 0.75, -0.1666666); - - float gaussx = 0.0; - if (pos.x < -1.5) { - gaussx = 1.0; - } else if (pos.x < -0.5) { - gaussx = dot(posx, klower); - } else if (pos.x < 0.5) { - gaussx = dot(posx, kmiddle); - } else if (pos.x < 1.5) { - gaussx = dot(posx, kupper); - } - - float gaussy = 0.0; - if (pos.y < -1.5) { - gaussy = 1.0; - } else if (pos.y < -0.5) { - gaussy = dot(posy, klower); - } else if (pos.y < 0.5) { - gaussy = dot(posy, kmiddle); - } else if (pos.y < 1.5) { - gaussy = dot(posy, kupper); - } - - float alpha_scale = gaussx * gaussy * u_scale_add.x + u_scale_add.y; - gl_FragColor = v_color * alpha_scale; + // Get the integral over the interval occupied by the rectangle. Both + // v_offset and u_blur_rect are already scaled for the integral function. + float integral = GaussianIntegral(u_blur_rect.xz - v_offset.xx) * + GaussianIntegral(u_blur_rect.yw - v_offset.yy); + float blur_scale = integral * u_scale_add.x + u_scale_add.y; + gl_FragColor = v_color * blur_scale; }
diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur_rrects.glsl b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur_rrects.glsl index 1d17a97..ee8c4ae 100644 --- a/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur_rrects.glsl +++ b/src/cobalt/renderer/rasterizer/egl/shaders/fragment_color_blur_rrects.glsl
@@ -20,8 +20,27 @@ // represents (start.xy, radius.xy). uniform vec4 u_scissor_rect; uniform mat4 u_scissor_corners; -uniform vec4 u_spread_rect; -uniform mat4 u_spread_corners; + +// The rounded spread rect is represented in a way to optimize calculation of +// the extents. Each element of a vec4 represents a corner's value -- order +// is top left, top right, bottom left, bottom right. Extents for each corner +// can be calculated as: +// extents_x = start_x + radius_x * sqrt(1 - scaled_y^2) where +// scaled_y = clamp((pos.yyyy - start_y) * scale_y, 0.0, 1.0) +// To simplify handling left vs right and top vs bottom corners, the sign of +// scale_y and radius_x handles negation as needed. +uniform vec4 u_spread_start_x; +uniform vec4 u_spread_start_y; +uniform vec4 u_spread_scale_y; +uniform vec4 u_spread_radius_x; + +// The blur extent specifies (3 * sigma, min_rect_y, max_rect_y). This is used +// to clamp the interval over which integration should be evaluated. +uniform vec3 u_blur_extent; + +// The gaussian scale uniform is used to simplify calculation of the gaussian +// function at a particular point. +uniform vec2 u_gaussian_scale; // The scale_add uniform is used to switch the shader between generating // outset shadows and inset shadows. It impacts the shadow gradient and @@ -34,139 +53,81 @@ // translate pixel distances into sigma distances. uniform vec2 u_sigma_scale; -// Adjust the sigma input value to tweak the blur output so that it better -// matches the reference. This is usually only needed for very large sigmas. -uniform vec2 u_sigma_tweak; - varying vec2 v_offset; varying vec4 v_color; #include "function_is_outside_rrect.inc" +#include "function_gaussian_integral.inc" -// Calculate the distance from a point in the first quadrant to an ellipse -// centered at the origin. -// -// http://iquilezles.org/www/articles/ellipsedist/ellipsedist.htm -float GetEllipseDistance(vec2 p, vec2 ab) { - if (abs(ab.x - ab.y) < 0.5) { - return length(p) - ab.x; - } +vec2 GetXExtents(float y) { + // Use x^2 / a^2 + y^2 / b^2 = 1 to solve for the x value of each rounded + // corner at the given y. + vec4 scaled = clamp((y - u_spread_start_y) * u_spread_scale_y, 0.0, 1.0); + vec4 root = sqrt(1.0 - scaled * scaled); + vec4 extent = u_spread_start_x + u_spread_radius_x * root; - if (p.x > p.y) { - p = p.yx; - ab = ab.yx; - } - - float lr = 1.0 / (ab.y * ab.y - ab.x * ab.x); - float m = ab.x * p.x * lr; - float m2 = m * m; - float n = ab.y * p.y * lr; - float n2 = n * n; - float c = (m2 + n2 - 1.0) * 0.333333333; - float c3 = c * c * c; - float q = c3 + m2 * n2 * 2.0; - float d = c3 + m2 * n2; - float g = m + m * n2; - - float co; - - if (d < 0.0) { - float p = acos(q / c3) * 0.333333333; - float s = cos(p); - float t = sin(p) * 1.732050808; - float rx = sqrt(-c * (s + t + 2.0) + m2); - float ry = sqrt(-c * (s - t + 2.0) + m2); - co = (ry + sign(lr) * rx + abs(g) / (rx * ry) - m) * 0.5; - } else { - float h = 2.0 * m * n * sqrt(d); - float s = sign(q + h) * pow(abs(q + h), 0.333333333); - float u = sign(q - h) * pow(abs(q - h), 0.333333333); - float rx = -s - u - c * 4.0 + 2.0 * m2; - float ry = (s - u) * 1.732050808; - float rm = sqrt(rx * rx + ry * ry); - float p = ry / sqrt(rm - rx); - co = (p + 2.0 * g / rm - m) * 0.5; - } - - float si = sqrt(1.0 - co * co); - vec2 closest = vec2(ab.x * co, ab.y * si); - return length(closest - p) * sign(p.y - closest.y); + // If the y value was before a corner started, then the calculated extent + // would equal the unrounded rectangle's extents (since negative values were + // clamped to 0 in the above calculation). So smaller extents (i.e. extents + // closer to the rectangle center), represent the relevant corners' extents. + return vec2(max(extent.x, extent.z), min(extent.y, extent.w)); } -// Get the x and y distances from the nearest edges of the rounded rect. -vec2 GetBlurPosition(vec4 rect, mat4 corners) { - vec2 pos = max(rect.xy - v_offset, v_offset - rect.zw); +float GetXBlur(float x, float y) { + // Get the integral over the interval occupied by the rectangle. + vec2 pos = (GetXExtents(y) - x) * u_sigma_scale; + return GaussianIntegral(pos); +} - vec4 select_corner = vec4( - step(v_offset.x, corners[0].x) * step(v_offset.y, corners[0].y), - step(corners[1].x, v_offset.x) * step(v_offset.y, corners[1].y), - step(v_offset.x, corners[2].x) * step(corners[2].y, v_offset.y), - step(corners[3].x, v_offset.x) * step(corners[3].y, v_offset.y)); - if (dot(select_corner, vec4(1.0)) > 0.5) { - // Use distance from the closest point on the ellipse as the position - // for blur calculations. - vec4 corner = corners * select_corner; - float dist = GetEllipseDistance(abs(v_offset - corner.xy), corner.zw); +vec3 GetGaussian(vec3 offset) { + // Evaluate the gaussian at the given offsets. + return exp(offset * offset * u_gaussian_scale.x); +} - // Since the transition from non-corner to corner positions happens along - // the ellipse's x or y axis, either pos.x = -corner.z or pos.y = -corner.w - // when the transition happens. Keep one ordinate at a minimum so that - // distance from the ellipse smoothly changes blur intensity. - // - // The return vec2 is used as blur = gi(x) * gi(y) where gi = the guassian - // integral function. Swapping x and y has no impact on the final blur, so - // distance can be substituted for one ordinate as long as the other takes - // the right value. E.g. when pos = (-corner.z, 0), the point is on the top - // center of the ellipse, so dist = 0. When pos = (0, -corner.w), dist = 0. - // When pos = (-corner.z, -corner.w), the point is at the center of the - // ellipse, and dist = max(-corner.z, -corner.w). So dist can be used as - // long as the other ordinate is min(pos.x, pos.y). - return vec2(dist, min(min(pos.x, pos.y), max(-corner.z, -corner.w))); - } +float GetBlur(vec2 pos) { + // Approximate the 2D gaussian filter using numerical integration. Sample + // points between the y extents of the rectangle. + float low = clamp(pos.y - u_blur_extent.x, u_blur_extent.y, u_blur_extent.z); + float high = clamp(pos.y + u_blur_extent.x, u_blur_extent.y, u_blur_extent.z); - return pos; + // Use the Gauss–Legendre quadrature with 6 points to numerically integrate. + // Using fewer samples will show artifacts with elliptical corners that are + // likely to be used. + const vec3 kStepScale1 = vec3(-0.932470, -0.661209, -0.238619); + const vec3 kStepScale2 = vec3( 0.932470, 0.661209, 0.238619); + const vec3 kWeight = vec3(0.171324, 0.360762, 0.467914); + + float half_size = (high - low) * 0.5; + float middle = (high + low) * 0.5; + vec3 weight = half_size * kWeight; + vec3 pos1 = middle + half_size * kStepScale1; + vec3 pos2 = middle + half_size * kStepScale2; + vec3 offset1 = pos1 - pos.yyy; + vec3 offset2 = pos2 - pos.yyy; + + // The integral along the x-axis is computed. The integral along the y-axis + // is roughly approximated. To get the 2D filter, multiply the two integrals. + // Visual artifacts appear when the computed integrals along the x-axis + // change rapidly between samples (e.g. elliptical corners that are much + // wider than they are tall). + vec3 xblur1 = vec3(GetXBlur(pos.x, pos1.x), + GetXBlur(pos.x, pos1.y), + GetXBlur(pos.x, pos1.z)); + vec3 xblur2 = vec3(GetXBlur(pos.x, pos2.x), + GetXBlur(pos.x, pos2.y), + GetXBlur(pos.x, pos2.z)); + vec3 yblur1 = GetGaussian(offset1) * weight; + vec3 yblur2 = GetGaussian(offset2) * weight; + + // Since each yblur value should be scaled by u_gaussian_scale.y, save some + // cycles and multiply the sum by it. + return (dot(xblur1, yblur1) + dot(xblur2, yblur2)) * u_gaussian_scale.y; } void main() { float scissor_scale = IsOutsideRRect(v_offset, u_scissor_rect, u_scissor_corners) * u_scale_add.x + u_scale_add.y; - - vec2 pos = GetBlurPosition(u_spread_rect, u_spread_corners) * - u_sigma_scale + u_sigma_tweak; - vec2 pos2 = pos * pos; - vec2 pos3 = pos2 * pos; - vec4 posx = vec4(1.0, pos.x, pos2.x, pos3.x); - vec4 posy = vec4(1.0, pos.y, pos2.y, pos3.y); - - // Approximation of the gaussian integral from [x, +inf). - // http://stereopsis.com/shadowrect/ - const vec4 klower = vec4(0.4375, -1.125, -0.75, -0.1666666); - const vec4 kmiddle = vec4(0.5, -0.75, 0.0, 0.3333333); - const vec4 kupper = vec4(0.5625, -1.125, 0.75, -0.1666666); - - float gaussx = 0.0; - if (pos.x < -1.5) { - gaussx = 1.0; - } else if (pos.x < -0.5) { - gaussx = dot(posx, klower); - } else if (pos.x < 0.5) { - gaussx = dot(posx, kmiddle); - } else if (pos.x < 1.5) { - gaussx = dot(posx, kupper); - } - - float gaussy = 0.0; - if (pos.y < -1.5) { - gaussy = 1.0; - } else if (pos.y < -0.5) { - gaussy = dot(posy, klower); - } else if (pos.y < 0.5) { - gaussy = dot(posy, kmiddle); - } else if (pos.y < 1.5) { - gaussy = dot(posy, kupper); - } - - float alpha_scale = gaussx * gaussy * u_scale_add.x + u_scale_add.y; - gl_FragColor = v_color * (alpha_scale * scissor_scale); + float blur_scale = GetBlur(v_offset) * u_scale_add.x + u_scale_add.y; + gl_FragColor = v_color * (blur_scale * scissor_scale); }
diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/function_gaussian_integral.inc b/src/cobalt/renderer/rasterizer/egl/shaders/function_gaussian_integral.inc new file mode 100644 index 0000000..36f3236 --- /dev/null +++ b/src/cobalt/renderer/rasterizer/egl/shaders/function_gaussian_integral.inc
@@ -0,0 +1,35 @@ +// Copyright 2017 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. + +// Calculate the normalized gaussian integral from (pos.x * k, pos.y * k) +// where k = sqrt(2) * sigma and pos.x <= pos.y. This is just a 1D filter -- +// the pos.x and pos.y values are expected to be on the same axis. +float GaussianIntegral(vec2 pos) { + // Approximation of the error function. + // For x >= 0, + // erf(x) = 1 - 1 / (1 + k1 * x + k2 * x^2 + k3 * x^3 + k4 * x^4)^4 + // where k1 = 0.278393, k2 = 0.230389, k3 = 0.000972, k4 = 0.078108. + // For y < 0, + // erf(y) = -erf(-y). + vec2 s = sign(pos); + vec2 a = abs(pos); + vec2 t = 1.0 + + (0.278393 + (0.230389 + (0.000972 + 0.078108 * a) * a) * a) * a; + vec2 t2 = t * t; + vec2 erf = s - s / (t2 * t2); + + // erf(x) = the integral of the normalized gaussian from [-x * k, x * k], + // where k = sqrt(2) * sigma. Find the integral from (pos.x * k, pos.y * k). + return dot(erf, vec2(-0.5, 0.5)); +}
diff --git a/src/cobalt/renderer/rasterizer/egl/shaders/shaders.gyp b/src/cobalt/renderer/rasterizer/egl/shaders/shaders.gyp index 444d630..82e71d6 100644 --- a/src/cobalt/renderer/rasterizer/egl/shaders/shaders.gyp +++ b/src/cobalt/renderer/rasterizer/egl/shaders/shaders.gyp
@@ -28,6 +28,7 @@ '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_color_texcoord.glsl', '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_texcoord.glsl', '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/fragment_texcoord_color_rrect.glsl', + '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/function_gaussian_integral.inc', '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/function_is_outside_rrect.inc', '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/vertex_color.glsl', '<(DEPTH)/cobalt/renderer/rasterizer/egl/shaders/vertex_color_offset.glsl',
diff --git a/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc b/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc index b89a099..8df6fd1 100644 --- a/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc +++ b/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc
@@ -489,8 +489,35 @@ } break; case Image::YUV_2PLANE_BT709: { std::vector<TextureInfo> texture_infos; +#if SB_API_VERSION >= SB_DECODE_TARGET_FORMAT_VERSION + switch (image.textures[0].texture->GetFormat()) { + case GL_ALPHA: + texture_infos.push_back(TextureInfo("y", "a")); + break; +#if defined(GL_RED_EXT) + case GL_RED_EXT: + texture_infos.push_back(TextureInfo("y", "r")); + break; +#endif + default: + NOTREACHED(); + } + switch (image.textures[1].texture->GetFormat()) { + case GL_LUMINANCE_ALPHA: + texture_infos.push_back(TextureInfo("uv", "ba")); + break; +#if defined(GL_RG_EXT) + case GL_RG_EXT: + texture_infos.push_back(TextureInfo("uv", "rg")); + break; +#endif + default: + NOTREACHED(); + } +#else // SB_API_VERSION >= SB_DECODE_TARGET_FORMAT_VERSION texture_infos.push_back(TextureInfo("y", "a")); texture_infos.push_back(TextureInfo("uv", "ba")); +#endif // SB_API_VERSION >= SB_DECODE_TARGET_FORMAT_VERSION result = MakeBlitProgram( color_matrix, texture_infos, CreateFragmentShader(texture_target, texture_infos));
diff --git a/src/cobalt/renderer/rasterizer/lib/exported/graphics.h b/src/cobalt/renderer/rasterizer/lib/exported/graphics.h new file mode 100644 index 0000000..7b1d4bd --- /dev/null +++ b/src/cobalt/renderer/rasterizer/lib/exported/graphics.h
@@ -0,0 +1,54 @@ +// Copyright 2017 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. + +// All imported functions defined below MUST be implemented by client +// applications. + +#ifndef COBALT_RENDERER_RASTERIZER_LIB_EXPORTED_GRAPHICS_H_ +#define COBALT_RENDERER_RASTERIZER_LIB_EXPORTED_GRAPHICS_H_ + +#include "starboard/export.h" +#include "starboard/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*CbLibGraphicsContextCreatedCallback)(void* context); +typedef void (*CbLibGraphicsBeginRenderFrameCallback)( + void* context, intptr_t render_tree_texture_handle); +typedef void (*CbLibGraphicsEndRenderFrameCallback)(void* context); + +// Sets a callback which will be called from the rasterization thread once the +// graphics context has been created. +SB_EXPORT_PLATFORM void CbLibGraphicsSetContextCreatedCallback( + void* context, CbLibGraphicsContextCreatedCallback callback); + +// Sets a callback which will be called as often as the platform can swap +// buffers from the rasterization thread. |render_tree_texture_handle| which is +// provided to the callback corresponds to a GLint texture ID for the current +// RenderTree. +SB_EXPORT_PLATFORM void CbLibGraphicsSetBeginRenderFrameCallback( + void* context, CbLibGraphicsBeginRenderFrameCallback callback); + +// Sets a callback which will be called at the end of rendering, after swap +// buffers has been called. +SB_EXPORT_PLATFORM void CbLibGraphicsSetEndRenderFrameCallback( + void* context, CbLibGraphicsEndRenderFrameCallback callback); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // COBALT_RENDERER_RASTERIZER_LIB_EXPORTED_GRAPHICS_H_
diff --git a/src/cobalt/renderer/rasterizer/lib/exported/video.h b/src/cobalt/renderer/rasterizer/lib/exported/video.h index 5cb080c..9f06902 100644 --- a/src/cobalt/renderer/rasterizer/lib/exported/video.h +++ b/src/cobalt/renderer/rasterizer/lib/exported/video.h
@@ -22,11 +22,10 @@ extern "C" { #endif -// Functions to be called to set callbacks for the updates to video rendering -// parameters. When the host application is notified that the graphics context -// has been created, it should install the callbacks within the same call stack -// of CbLibOnGraphicsContextCreated. Failing to do so will crash the application -// on debug mode and no-op on production builds. +// Functions to be called to set callbacks to receive updates to video rendering +// parameters. By default, this callbacks are not set and warnings will be +// when an unhandled parameter change happens. To unset them again, any of these +// setter functions can be called with a null callback function pointer. typedef enum { kCbLibVideoProjectionTypeNone = 0, // When no offscreen video is playing.
diff --git a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc index 7b8415a..e1cb238 100644 --- a/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc +++ b/src/cobalt/renderer/rasterizer/lib/external_rasterizer.cc
@@ -20,14 +20,15 @@ #include "base/bind.h" #include "base/callback.h" +#include "base/lazy_instance.h" #include "base/threading/thread_checker.h" #include "cobalt/math/clamp.h" #include "cobalt/render_tree/image.h" #include "cobalt/renderer/backend/egl/graphics_context.h" #include "cobalt/renderer/backend/egl/render_target.h" #include "cobalt/renderer/rasterizer/common/find_node.h" +#include "cobalt/renderer/rasterizer/lib/exported/graphics.h" #include "cobalt/renderer/rasterizer/lib/exported/video.h" -#include "cobalt/renderer/rasterizer/lib/imported/graphics.h" #include "cobalt/renderer/rasterizer/skia/hardware_image.h" #include "cobalt/renderer/rasterizer/skia/hardware_mesh.h" #include "cobalt/renderer/rasterizer/skia/hardware_rasterizer.h" @@ -49,20 +50,80 @@ const float kMaxRenderTargetSize = 15360.0f; -ExternalRasterizer::Impl* g_external_rasterizer_impl_; +// Matches the signatures of the callback setter functions in exported/video.h +// and exported/graphics.h. +template <typename Ret, typename... Args> +using CallbackSetter = void(void*, Ret (*)(void*, Args...)); -void DefaultOnUpdateProjectionType(CbLibVideoProjectionType) { - LOG(DFATAL) << "CbLibVideoUpdateProjectionTypeCallback not set."; -} -void DefaultOnUpdateMeshes(CbLibVideoMesh, CbLibVideoMesh) { - LOG(DFATAL) << "CbLibVideoUpdateMeshesCallback not set."; -} -void DefaultOnUpdateStereoMode(CbLibVideoStereoMode) { - LOG(DFATAL) << "CbLibVideoStereoMode not set."; -} -void DefaultOnUpdateRgbTextureId(int) { - LOG(DFATAL) << "CbLibVideoUpdateRgbTextureIdCallback not set."; -} +template <typename T, T* t, const char* ErrorMessage> +struct CallbackUpdate; + +// Defines useful base:: wrappers for callback setter functions. +template <typename Ret, typename... Args, CallbackSetter<Ret, Args...>* Setter, + const char* ErrorMessage> +struct CallbackUpdate<CallbackSetter<Ret, Args...>, Setter, ErrorMessage> { + // Equivalent to the callback types defined in exported/video.h and + // exported/graphics.h but with the context bound. + using Callback = base::Callback<Ret(Args...)>; + + static Ret DefaultImplementation(Args...) { LOG(WARNING) << ErrorMessage; } + + struct LazyTraits { + static const bool kRegisterOnExit = true; + static const bool kAllowedToAccessOnNonjoinableThread = false; + + static Callback* New(void* instance) { + return new (instance) Callback(base::Bind(DefaultImplementation)); + } + static void Delete(Callback* instance) { + return base::DefaultLazyInstanceTraits<Callback>::Delete(instance); + } + }; + + // This provides a default warning function for the callbacks and allows to + // set them even before the external rasterizer is created. + using LazyCallback = base::LazyInstance<Callback, LazyTraits>; +}; + +// Creates an instance for the above template for a given callback setter +// function, with an error message. +// We must use 'extern' in here as otherwise we get compiler error C2970 when +// using MSVC for compilation. +#define INSTANCE_CALLBACK_UPDATE(instance_name, callback_setter) \ + extern const char kWarningMessageDidNotSet##instance_name[] = \ + #callback_setter \ + "was never called to set a callback, yet Cobalt is " \ + "attempting to call it."; \ + using instance_name = \ + CallbackUpdate<decltype(callback_setter), &callback_setter, \ + kWarningMessageDidNotSet##instance_name>; + +INSTANCE_CALLBACK_UPDATE(UpdateMeshes, CbLibVideoSetOnUpdateMeshes); +INSTANCE_CALLBACK_UPDATE(UpdateStereoMode, CbLibVideoSetOnUpdateStereoMode); +INSTANCE_CALLBACK_UPDATE(UpdateRgbTextureId, CbLibVideoSetOnUpdateRgbTextureId); +INSTANCE_CALLBACK_UPDATE(UpdateProjectionType, + CbLibVideoSetOnUpdateProjectionType); +INSTANCE_CALLBACK_UPDATE(GraphicsContextCreated, + CbLibGraphicsSetContextCreatedCallback); +INSTANCE_CALLBACK_UPDATE(BeginRenderFrame, + CbLibGraphicsSetBeginRenderFrameCallback); +INSTANCE_CALLBACK_UPDATE(EndRenderFrame, + CbLibGraphicsSetEndRenderFrameCallback); +#undef INSTANCE_CALLBACK_UPDATE + +UpdateMeshes::LazyCallback g_update_meshes_callback = LAZY_INSTANCE_INITIALIZER; +UpdateStereoMode::LazyCallback g_update_stereo_mode_callback = + LAZY_INSTANCE_INITIALIZER; +UpdateRgbTextureId::LazyCallback g_update_rgb_texture_id_callback = + LAZY_INSTANCE_INITIALIZER; +UpdateProjectionType::LazyCallback g_update_projection_type_callback = + LAZY_INSTANCE_INITIALIZER; +GraphicsContextCreated::LazyCallback g_graphics_context_created_callback = + LAZY_INSTANCE_INITIALIZER; +BeginRenderFrame::LazyCallback g_begin_render_frame_callback = + LAZY_INSTANCE_INITIALIZER; +EndRenderFrame::LazyCallback g_end_render_frame_callback = + LAZY_INSTANCE_INITIALIZER; } // namespace @@ -86,31 +147,6 @@ void MakeCurrent() { hardware_rasterizer_.MakeCurrent(); } - // Equivalent to the callback types defined in exported/video.h but with the - // context bound. - typedef base::Callback<void(CbLibVideoMesh, CbLibVideoMesh)> - UpdateMeshesCallback; - typedef base::Callback<void(CbLibVideoStereoMode)> UpdateStereoModeCallback; - typedef base::Callback<void(int)> UpdateRgbTextureIdCallback; - typedef base::Callback<void(CbLibVideoProjectionType projection_type)> - UpdateProjectionTypeCallback; - - void SetUpdateMeshesCallback(UpdateMeshesCallback update_meshes) { - update_meshes_ = update_meshes; - } - void SetUpdateStereoModeCallback( - UpdateStereoModeCallback update_stereo_mode) { - update_stereo_mode_ = update_stereo_mode; - } - void SetUpdateRgbTextureIdCallback( - UpdateRgbTextureIdCallback update_rgb_texture_id) { - update_rgb_texture_id_ = update_rgb_texture_id; - } - void SetUpdateProjectionTypeCallback( - UpdateProjectionTypeCallback update_projection_type) { - update_projection_type_ = update_projection_type; - } - private: void RenderOffscreenVideo(render_tree::FilterNode* map_to_mesh_filter_node); @@ -136,11 +172,6 @@ scoped_refptr<skia::HardwareMesh> right_eye_video_mesh_; render_tree::StereoMode video_stereo_mode_; int video_texture_rgb_; - - UpdateMeshesCallback update_meshes_; - UpdateStereoModeCallback update_stereo_mode_; - UpdateRgbTextureIdCallback update_rgb_texture_id_; - UpdateProjectionTypeCallback update_projection_type_; }; ExternalRasterizer::Impl::Impl(backend::GraphicsContext* graphics_context, @@ -171,20 +202,10 @@ make_scoped_refptr(base::polymorphic_downcast<backend::RenderTargetEGL*>( main_offscreen_render_target_.get())))); - DCHECK(!g_external_rasterizer_impl_); - g_external_rasterizer_impl_ = this; - - // Default parameter update callbacks. - update_projection_type_ = base::Bind(&DefaultOnUpdateProjectionType); - update_meshes_ = base::Bind(&DefaultOnUpdateMeshes); - update_stereo_mode_ = base::Bind(&DefaultOnUpdateStereoMode); - update_rgb_texture_id_ = base::Bind(&DefaultOnUpdateRgbTextureId); - - CbLibOnGraphicsContextCreated(); + g_graphics_context_created_callback.Get().Run(); } ExternalRasterizer::Impl::~Impl() { - g_external_rasterizer_impl_ = NULL; graphics_context_->MakeCurrent(); } @@ -225,12 +246,12 @@ if (video_projection_type_ != new_projection_type) { video_projection_type_ = new_projection_type; - update_projection_type_.Run(video_projection_type_); + g_update_projection_type_callback.Get().Run(video_projection_type_); } if (filter->stereo_mode() != video_stereo_mode_) { video_stereo_mode_ = filter->stereo_mode(); - update_stereo_mode_.Run( + g_update_stereo_mode_callback.Get().Run( static_cast<CbLibVideoStereoMode>(video_stereo_mode_)); } @@ -271,9 +292,9 @@ right_mesh.draw_mode = static_cast<CbLibVideoMeshDrawMode>( right_eye_video_mesh_->GetDrawMode()); right_mesh.vertices = right_eye_video_mesh_->GetVertices(); - update_meshes_.Run(left_mesh, right_mesh); + g_update_meshes_callback.Get().Run(left_mesh, right_mesh); } else { - update_meshes_.Run(left_mesh, left_mesh); + g_update_meshes_callback.Get().Run(left_mesh, left_mesh); } } } @@ -283,7 +304,7 @@ } else { if (video_projection_type_ != kCbLibVideoProjectionTypeNone) { video_projection_type_ = kCbLibVideoProjectionTypeNone; - update_projection_type_.Run(video_projection_type_); + g_update_projection_type_callback.Get().Run(video_projection_type_); } } @@ -296,9 +317,9 @@ // TODO: Allow clients to specify arbitrary subtrees to render into // different textures? const intptr_t texture_handle = main_texture_->GetPlatformHandle(); - CbLibRenderFrame(texture_handle); - + g_begin_render_frame_callback.Get().Run(texture_handle); graphics_context_->SwapBuffers(render_target_egl); + g_end_render_frame_callback.Get().Run(); } render_tree::ResourceProvider* ExternalRasterizer::Impl::GetResourceProvider() { @@ -368,7 +389,7 @@ const intptr_t video_texture_handle = video_texture_->GetPlatformHandle(); if (video_texture_rgb_ != video_texture_handle) { video_texture_rgb_ = video_texture_handle; - update_rgb_texture_id_.Run(video_texture_handle); + g_update_rgb_texture_id_callback.Get().Run(video_texture_handle); } } } @@ -408,36 +429,49 @@ void CbLibVideoSetOnUpdateMeshes(void* context, CbLibVideoUpdateMeshesCallback callback) { - if (g_external_rasterizer_impl_) { - g_external_rasterizer_impl_->SetUpdateMeshesCallback( - callback ? base::Bind(callback, context) - : base::Bind(&DefaultOnUpdateMeshes)); - } + g_update_meshes_callback.Get() = + callback ? base::Bind(callback, context) + : base::Bind(&UpdateMeshes::DefaultImplementation); } void CbLibVideoSetOnUpdateStereoMode( void* context, CbLibVideoUpdateStereoModeCallback callback) { - if (g_external_rasterizer_impl_) { - g_external_rasterizer_impl_->SetUpdateStereoModeCallback( - callback ? base::Bind(callback, context) - : base::Bind(&DefaultOnUpdateStereoMode)); - } + g_update_stereo_mode_callback.Get() = + callback ? base::Bind(callback, context) + : base::Bind(&UpdateStereoMode::DefaultImplementation); } void CbLibVideoSetOnUpdateRgbTextureId( void* context, CbLibVideoUpdateRgbTextureIdCallback callback) { - if (g_external_rasterizer_impl_) { - g_external_rasterizer_impl_->SetUpdateRgbTextureIdCallback( - callback ? base::Bind(callback, context) - : base::Bind(&DefaultOnUpdateRgbTextureId)); - } + g_update_rgb_texture_id_callback.Get() = + callback ? base::Bind(callback, context) + : base::Bind(&UpdateRgbTextureId::DefaultImplementation); } void CbLibVideoSetOnUpdateProjectionType( void* context, CbLibVideoUpdateProjectionTypeCallback callback) { - if (g_external_rasterizer_impl_) { - g_external_rasterizer_impl_->SetUpdateProjectionTypeCallback( - callback ? base::Bind(callback, context) - : base::Bind(&DefaultOnUpdateProjectionType)); - } + g_update_projection_type_callback.Get() = + callback ? base::Bind(callback, context) + : base::Bind(&UpdateProjectionType::DefaultImplementation); +} + +void CbLibGraphicsSetContextCreatedCallback( + void* context, CbLibGraphicsContextCreatedCallback callback) { + g_graphics_context_created_callback.Get() = + callback ? base::Bind(callback, context) + : base::Bind(&GraphicsContextCreated::DefaultImplementation); +} + +void CbLibGraphicsSetBeginRenderFrameCallback( + void* context, CbLibGraphicsBeginRenderFrameCallback callback) { + g_begin_render_frame_callback.Get() = + callback ? base::Bind(callback, context) + : base::Bind(&BeginRenderFrame::DefaultImplementation); +} + +void CbLibGraphicsSetEndRenderFrameCallback( + void* context, CbLibGraphicsEndRenderFrameCallback callback) { + g_end_render_frame_callback.Get() = + callback ? base::Bind(callback, context) + : base::Bind(&EndRenderFrame::DefaultImplementation); }
diff --git a/src/cobalt/renderer/rasterizer/lib/imported/graphics.h b/src/cobalt/renderer/rasterizer/lib/imported/graphics.h deleted file mode 100644 index cde0573..0000000 --- a/src/cobalt/renderer/rasterizer/lib/imported/graphics.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2017 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. - -// All imported functions defined below MUST be implemented by client -// applications. - -#ifndef COBALT_RENDERER_RASTERIZER_LIB_IMPORTED_GRAPHICS_H_ -#define COBALT_RENDERER_RASTERIZER_LIB_IMPORTED_GRAPHICS_H_ - -#include "starboard/export.h" -#include "starboard/types.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -// Invoked from the rasterization thread after the GL context has been created. -SB_IMPORT_PLATFORM void CbLibOnGraphicsContextCreated(); - -// Invoked as often as the platform can swap buffers from the rasterization -// thread. |render_tree_texture_handle| corresponds to a GLint texture ID for -// the current RenderTree. -SB_IMPORT_PLATFORM void CbLibRenderFrame(intptr_t render_tree_texture_handle); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // COBALT_RENDERER_RASTERIZER_LIB_IMPORTED_GRAPHICS_H_
diff --git a/src/cobalt/renderer/rasterizer/lib/imported/graphics_stub.cc b/src/cobalt/renderer/rasterizer/lib/imported/graphics_stub.cc deleted file mode 100644 index 5d9ece0..0000000 --- a/src/cobalt/renderer/rasterizer/lib/imported/graphics_stub.cc +++ /dev/null
@@ -1,8 +0,0 @@ -#include "cobalt/renderer/rasterizer/lib/imported/graphics.h" - -// Empty implementations so that 'lib' targets can be compiled into executables -// by the builder without missing symbol definitions. -void CbLibOnGraphicsContextCreated() {} -void CbLibRenderFrame(intptr_t render_tree_texture_handle) { - (void)render_tree_texture_handle; -}
diff --git a/src/cobalt/renderer/rasterizer/lib/lib.gyp b/src/cobalt/renderer/rasterizer/lib/lib.gyp index 7a3914a..0b5a2c5 100644 --- a/src/cobalt/renderer/rasterizer/lib/lib.gyp +++ b/src/cobalt/renderer/rasterizer/lib/lib.gyp
@@ -21,19 +21,9 @@ '../../renderer_parameters_setup.gypi', ], 'sources': [ - 'external_rasterizer.h', 'external_rasterizer.cc', 'renderer_module_default_options_lib.cc' ], - 'all_dependent_settings': { - 'target_conditions': [ - ['_type=="executable" and _toolset=="target"', { - 'sources': [ - 'imported/graphics_stub.cc', - ], - }], - ], - }, 'dependencies': [ '<(DEPTH)/base/base.gyp:base', '<(DEPTH)/cobalt/render_tree/render_tree.gyp:render_tree',
diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc index 7315496..a3f66eb 100644 --- a/src/cobalt/renderer/rasterizer/pixel_test.cc +++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -236,8 +236,10 @@ RoundedCorner bottom_left(70, 80); scoped_ptr<RoundedCorners> rounded_corners( new RoundedCorners(top_left, top_right, bottom_right, bottom_left)); + math::RectF rect(ScaleSize(output_surface_size(), 0.5f, 0.5f)); + *rounded_corners = rounded_corners->Normalize(rect); TestTree(new RectNode( - RectF(ScaleSize(output_surface_size(), 0.5f, 0.5f)), + rect, scoped_ptr<Brush>(new SolidColorBrush(ColorRGBA(1.0, 0.0, 0.0, 1))), rounded_corners.Pass())); } @@ -3627,6 +3629,12 @@ #endif // defined(ENABLE_MAP_TO_MESH) +TEST_F(PixelTest, DrawNullImage) { + // An ImageNode with no source is legal, though it should result in nothing + // being drawn. + TestTree(new ImageNode(NULL, math::RectF(output_surface_size()))); +} + } // namespace rasterizer } // namespace renderer } // namespace cobalt
diff --git a/src/cobalt/renderer/rasterizer/skia/gl_format_conversions.cc b/src/cobalt/renderer/rasterizer/skia/gl_format_conversions.cc index 3a6f853..af1cad0 100644 --- a/src/cobalt/renderer/rasterizer/skia/gl_format_conversions.cc +++ b/src/cobalt/renderer/rasterizer/skia/gl_format_conversions.cc
@@ -48,9 +48,19 @@ return kRGBA_8888_GrPixelConfig; case GL_BGRA_EXT: return kBGRA_8888_GrPixelConfig; + // Note GL_ALPHA and GL_RED_EXT probably don't really work. + // They're only for use w/ SbDecodeTargets that are never drawn via skia case GL_ALPHA: +#if defined(GL_RED_EXT) + case GL_RED_EXT: +#endif return kAlpha_8_GrPixelConfig; + // Note GL_LUMINANCE_ALPHA and GL_RG_EXT probably don't really work. + // They're only for use w/ SbDecodeTargets that are never drawn via skia case GL_LUMINANCE_ALPHA: +#if defined(GL_RG_EXT) + case GL_RG_EXT: +#endif return kRGBA_8888_GrPixelConfig; default: { NOTREACHED() << "Unsupported GL format."; } }
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc index c385813..576969c 100644 --- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc +++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
@@ -170,7 +170,8 @@ } #endif // SB_API_VERSION < SB_DECODE_TARGET_PLANES_FOR_FORMAT -uint32_t DecodeTargetFormatToGLFormat(SbDecodeTargetFormat format, int plane) { +uint32_t DecodeTargetFormatToGLFormat(SbDecodeTargetFormat format, int plane, + const SbDecodeTargetInfoPlane* plane_info) { switch (format) { case kSbDecodeTargetFormat1PlaneRGBA: #if SB_API_VERSION >= SB_DECODE_TARGET_UYVY_SUPPORT_API_VERSION @@ -184,6 +185,31 @@ } break; case kSbDecodeTargetFormat2PlaneYUVNV12: { DCHECK_LT(plane, 2); +#if SB_API_VERSION >= SB_DECODE_TARGET_FORMAT_VERSION + // If this DCHECK fires, please set gl_texture_format, introduced + // in Starboard SB_DECODE_TARGET_FORMAT_VERSION. + // + // You probably want to set it to GL_ALPHA on plane 0 (luma) and + // GL_LUMINANCE_ALPHA on plane 1 (chroma), which was the default before. + DCHECK_NE(plane_info->gl_texture_format, 0); + switch (plane_info->gl_texture_format) { + case GL_ALPHA: + case GL_LUMINANCE_ALPHA: +#if defined(GL_RED_EXT) + case GL_RED_EXT: +#endif +#if defined(GL_RG_EXT) + case GL_RG_EXT: +#endif + return plane_info->gl_texture_format; + default: + // gl_texture_format is either unassigned or assigned to + // an invalud value. Please see comment above for + // gl_texture_format change, introduced in Starboard 7. + CHECK(false); + return 0; + } +#else // SB_API_VERSION >= SB_DECODE_TARGET_FORMAT_VERSION switch (plane) { case 0: return GL_ALPHA; @@ -193,6 +219,7 @@ NOTREACHED(); return GL_RGBA; } +#endif // SB_API_VERSION >= SB_DECODE_TARGET_FORMAT_VERSION } break; case kSbDecodeTargetFormat3PlaneYUVI420: { DCHECK_LT(plane, 3); @@ -280,7 +307,7 @@ plane.content_region.bottom - plane.content_region.top)); } - uint32_t gl_format = DecodeTargetFormatToGLFormat(info.format, i); + uint32_t gl_format = DecodeTargetFormatToGLFormat(info.format, i, &plane); scoped_ptr<backend::TextureEGL> texture(new backend::TextureEGL( cobalt_context_, gl_handle, math::Size(plane.width, plane.height),
diff --git a/src/cobalt/renderer/rasterizer/testdata/DrawNullImage-expected.png b/src/cobalt/renderer/rasterizer/testdata/DrawNullImage-expected.png new file mode 100644 index 0000000..7f0bfcf --- /dev/null +++ b/src/cobalt/renderer/rasterizer/testdata/DrawNullImage-expected.png Binary files differ
diff --git a/src/cobalt/samples/gn_tutorial/hello.cc b/src/cobalt/samples/gn_tutorial/hello.cc new file mode 100644 index 0000000..34732fc --- /dev/null +++ b/src/cobalt/samples/gn_tutorial/hello.cc
@@ -0,0 +1,17 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cobalt/samples/gn_tutorial/hello.h" + +#include <stdio.h> + +void Hello(const char* who) { + printf("Hello, %s.\n", who); +} + +#if defined(TWO_PEOPLE) +void Hello(const char* one, const char* two) { + printf("Hello, %s and %s.\n", one, two); +} +#endif
diff --git a/src/cobalt/samples/gn_tutorial/hello.h b/src/cobalt/samples/gn_tutorial/hello.h new file mode 100644 index 0000000..812fa54 --- /dev/null +++ b/src/cobalt/samples/gn_tutorial/hello.h
@@ -0,0 +1,14 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COBALT_SAMPLES_GN_TUTORIAL_HELLO_H_ +#define COBALT_SAMPLES_GN_TUTORIAL_HELLO_H_ + +void Hello(const char* who); + +#if defined(TWO_PEOPLE) +void Hello(const char* one, const char* two); +#endif + +#endif // COBALT_SAMPLES_GN_TUTORIAL_HELLO_H_
diff --git a/src/cobalt/samples/gn_tutorial/hello_world.cc b/src/cobalt/samples/gn_tutorial/hello_world.cc new file mode 100644 index 0000000..84ffc3f --- /dev/null +++ b/src/cobalt/samples/gn_tutorial/hello_world.cc
@@ -0,0 +1,10 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stdio.h> + +int main() { + printf("Hello, world.\n"); + return 0; +}
diff --git a/src/cobalt/samples/gn_tutorial/say_hello.cc b/src/cobalt/samples/gn_tutorial/say_hello.cc new file mode 100644 index 0000000..c1bea2c --- /dev/null +++ b/src/cobalt/samples/gn_tutorial/say_hello.cc
@@ -0,0 +1,14 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cobalt/samples/gn_tutorial/hello.h" + +int main() { +#if defined(TWO_PEOPLE) + Hello("Bill", "Joy"); +#else + Hello("everyone"); +#endif + return 0; +}
diff --git a/src/cobalt/script/value_handle.h b/src/cobalt/script/value_handle.h index d00d7d0..373b15f 100644 --- a/src/cobalt/script/value_handle.h +++ b/src/cobalt/script/value_handle.h
@@ -15,7 +15,6 @@ #define COBALT_SCRIPT_VALUE_HANDLE_H_ #include "cobalt/script/script_value.h" -#include "cobalt/script/value_handle.h" namespace cobalt { namespace script {
diff --git a/src/cobalt/storage/savegame.h b/src/cobalt/storage/savegame.h index d635403..fa7e88f 100644 --- a/src/cobalt/storage/savegame.h +++ b/src/cobalt/storage/savegame.h
@@ -21,6 +21,7 @@ #include "base/callback.h" #include "base/file_path.h" #include "base/memory/scoped_ptr.h" +#include "base/optional.h" #include "base/threading/thread_checker.h" #include "sql/connection.h" @@ -39,12 +40,19 @@ typedef scoped_ptr<Savegame>(*Factory)(const Options& options); struct Options { - Options() : factory(&Create), delete_on_destruction(false) {} + Options() + : factory(&Create), + fallback_to_default_id(false), + delete_on_destruction(false) {} scoped_ptr<Savegame> CreateSavegame() { return factory(*this); } // Factory method for constructing a Savegame instance. // Defaults to Savegame::Create() but can be overriden for tests. Savegame::Factory factory; + // The unique savegame ID for this Savegame, if any. + base::optional<std::string> id; + // Whether to fallback to the default ID if data for this ID doesn't exist. + bool fallback_to_default_id; // File path the Savegame should read/write from, rather than its default. std::string path_override; // Delete the savegame file when the Savegame object goes out of scope.
diff --git a/src/cobalt/storage/savegame_file.cc b/src/cobalt/storage/savegame_file.cc deleted file mode 100644 index 7bc4667..0000000 --- a/src/cobalt/storage/savegame_file.cc +++ /dev/null
@@ -1,116 +0,0 @@ -// Copyright 2015 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "cobalt/storage/savegame.h" - -#include <algorithm> - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/path_service.h" - -namespace cobalt { -namespace storage { - -namespace { -const char kDefaultSavegamePath[] = ".cobalt.sav"; - -FilePath GetSavegamePath() { - FilePath home_dir; - bool ok = PathService::Get(base::DIR_HOME, &home_dir); - DCHECK_EQ(true, ok); - return home_dir.Append(kDefaultSavegamePath); -} - -} // namespace - -// Savegame implementation that writes to a regular file, using file_util. -class SavegameFile : public Savegame { - public: - explicit SavegameFile(const Options& options); - ~SavegameFile() OVERRIDE; - bool PlatformRead(size_t max_to_read, ByteVector* bytes) OVERRIDE; - bool PlatformWrite(const ByteVector& bytes) OVERRIDE; - bool PlatformDelete() OVERRIDE; - - private: - FilePath savegame_path_; -}; - -SavegameFile::SavegameFile(const Options& options) : Savegame(options) { - if (options.path_override.length() > 0) { - savegame_path_ = FilePath(options.path_override); - } else { - savegame_path_ = GetSavegamePath(); - } -} - -SavegameFile::~SavegameFile() { - if (options_.delete_on_destruction) { - Delete(); - } -} - -bool SavegameFile::PlatformRead(ByteVector* bytes_ptr, size_t max_to_read) { - if (!file_util::PathExists(savegame_path_)) { - return false; - } - - int64 file_size; - if (!file_util::GetFileSize(savegame_path_, &file_size)) { - DLOG(WARNING) << "GetFileSize of " << savegame_path_.value() << " failed"; - return false; - } - - if (max_to_read < static_cast<size_t>(file_size) { - DLOG(WARNING) << "Savegame larger than max allowed size"; - return false; - } - - ByteVector& bytes = *bytes_ptr; - bytes.resize(static_cast<size_t>(file_size)); - if (!bytes.empty()) { - int bytes_read = - file_util::ReadFile(savegame_path_, reinterpret_cast<char*>(&bytes[0]), - static_cast<int>(file_size)); - bytes.resize(static_cast<size_t>(std::max(0, bytes_read))); - return bytes_read == file_size; - } else { - return true; - } -} - -bool SavegameFile::PlatformWrite(const ByteVector& bytes) { - int byte_count = static_cast<int>(bytes.size()); - int bytes_written = file_util::WriteFile( - savegame_path_, reinterpret_cast<const char*>(&bytes[0]), byte_count); - return bytes_written == byte_count; -} - -bool SavegameFile::PlatformDelete() { - if (file_util::PathExists(savegame_path_)) { - return file_util::Delete(savegame_path_, false /* recursive */); - } else { - return false; - } -} - -// static -scoped_ptr<Savegame> Savegame::Create(const Options& options) { - scoped_ptr<Savegame> savegame(new SavegameFile(options)); - return savegame.Pass(); -} - -} // namespace storage -} // namespace cobalt
diff --git a/src/cobalt/storage/savegame_starboard.cc b/src/cobalt/storage/savegame_starboard.cc index 8201b17..da62a3b 100644 --- a/src/cobalt/storage/savegame_starboard.cc +++ b/src/cobalt/storage/savegame_starboard.cc
@@ -19,12 +19,82 @@ #include "base/file_util.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/optional.h" #include "base/path_service.h" #include "starboard/storage.h" #include "starboard/user.h" namespace cobalt { namespace storage { +namespace { + +// An arbitrary max size for the save game file so that, for example, a corrupt +// filesystem cannot cause us to allocate a fatally large memory buffer. +size_t kMaxSaveGameSizeBytes = 4 * 1024 * 1024; + +bool ReadRecord(Savegame::ByteVector* bytes_ptr, size_t max_to_read, + const scoped_ptr<starboard::StorageRecord>& record) { + if (!record->IsValid()) { + DLOG(WARNING) << __FUNCTION__ << ": Invalid StorageRecord"; + return false; + } + + int64_t size = record->GetSize(); + if (size < 0) { + DLOG(WARNING) << "StorageRecord::GetSize failed"; + return false; + } + + if (static_cast<size_t>(size) > max_to_read) { + DLOG(WARNING) << "Savegame larger than max allowed size"; + return false; + } + + Savegame::ByteVector& bytes = *bytes_ptr; + bytes.resize(static_cast<size_t>(size)); + if (bytes.empty()) { + return true; + } + + int64_t bytes_read = + record->Read(reinterpret_cast<char*>(bytes.data()), size); + bytes.resize( + static_cast<size_t>(std::max(static_cast<int64_t>(0), bytes_read))); + return bytes_read == size; +} + +bool WriteRecord(const scoped_ptr<starboard::StorageRecord>& record, + const Savegame::ByteVector& bytes) { + int64_t byte_count = static_cast<int64_t>(bytes.size()); + return record->Write(reinterpret_cast<const char*>(bytes.data()), byte_count); +} + +scoped_ptr<starboard::StorageRecord> CreateRecord( + const base::optional<std::string>& id) { +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + if (id) { + return make_scoped_ptr(new starboard::StorageRecord(id->c_str())); + } +#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + UNREFERENCED_PARAMETER(id); +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + return make_scoped_ptr(new starboard::StorageRecord()); +} + +bool EnsureRecord(scoped_ptr<starboard::StorageRecord>* record, + const base::optional<std::string>& id) { + if (!(*record) || !(*record)->IsValid()) { + // Might have been deleted, so we'll create a new one. + (*record) = CreateRecord(id); + } + + if (!(*record)->IsValid()) { + DLOG(WARNING) << __FUNCTION__ << ": Invalid StorageRecord: Signed in?"; + return false; + } + + return true; +} // Savegame implementation that writes to the Starboard Storage API. class SavegameStarboard : public Savegame { @@ -36,12 +106,14 @@ bool PlatformDelete() OVERRIDE; private: + bool MigrateFromFallback(); + scoped_ptr<starboard::StorageRecord> record_; }; SavegameStarboard::SavegameStarboard(const Options& options) : Savegame(options) { - record_.reset(new starboard::StorageRecord()); + EnsureRecord(&record_, options_.id); } SavegameStarboard::~SavegameStarboard() { @@ -52,47 +124,30 @@ bool SavegameStarboard::PlatformRead(ByteVector* bytes_ptr, size_t max_to_read) { - if (!record_->IsValid()) { - DLOG(WARNING) << __FUNCTION__ << ": Invalid StorageRecord"; - return false; - } - - int64_t size = record_->GetSize(); - if (size < 0) { - DLOG(WARNING) << "StorageRecord::GetSize failed"; - return false; - } - - if (static_cast<size_t>(size) > max_to_read) { - DLOG(WARNING) << "Savegame larger than max allowed size"; - return false; - } - - ByteVector& bytes = *bytes_ptr; - bytes.resize(static_cast<size_t>(size)); - if (bytes.empty()) { + bool success = ReadRecord(bytes_ptr, max_to_read, record_); + if (success && !bytes_ptr->empty()) { return true; } - int64_t bytes_read = record_->Read(reinterpret_cast<char*>(&bytes[0]), size); - bytes.resize( - static_cast<size_t>(std::max(static_cast<int64_t>(0), bytes_read))); - return bytes_read == size; -} - -bool SavegameStarboard::PlatformWrite(const ByteVector& bytes) { - if (!record_->IsValid()) { - // Might have been deleted, so we'll create a new one. - record_.reset(new starboard::StorageRecord()); - } - - if (!record_->IsValid()) { - DLOG(WARNING) << __FUNCTION__ << ": Invalid StorageRecord: Signed in?"; + if (!options_.fallback_to_default_id) { return false; } - int64_t byte_count = static_cast<int64_t>(bytes.size()); - return record_->Write(reinterpret_cast<const char*>(&bytes[0]), byte_count); + if (!MigrateFromFallback()) { + DLOG(WARNING) << __FUNCTION__ << ": Migration Failed"; + return false; + } + + // Now read the migrated data. + return ReadRecord(bytes_ptr, max_to_read, record_); +} + +bool SavegameStarboard::PlatformWrite(const ByteVector& bytes) { + if (!EnsureRecord(&record_, options_.id)) { + return false; + } + + return WriteRecord(record_, bytes); } bool SavegameStarboard::PlatformDelete() { @@ -104,10 +159,54 @@ return record_->Delete(); } +bool SavegameStarboard::MigrateFromFallback() { + ByteVector buffer; + if (!EnsureRecord(&record_, options_.id)) { + DLOG(WARNING) << __FUNCTION__ << ": " + << "Failed to ensure record for ID: " << options_.id; + return false; + } + + scoped_ptr<starboard::StorageRecord> fallback_record; + if (!EnsureRecord(&fallback_record, base::nullopt)) { + DLOG(WARNING) << __FUNCTION__ << ": " + << "Failed to open default record."; + return false; + } + + if (!ReadRecord(&buffer, kMaxSaveGameSizeBytes, fallback_record)) { + DLOG(WARNING) << __FUNCTION__ << ": " + << "Failed to read default record."; + return false; + } + + if (buffer.size() == 0) { + // We migrated nothing successfully. + return true; + } + + if (!WriteRecord(record_, buffer)) { + DLOG(WARNING) << __FUNCTION__ << ": " + << "Failed to write record for ID: " << options_.id; + return false; + } + + // Flush the migrated record by closing and reopening it. + record_.reset(); + if (!EnsureRecord(&record_, options_.id)) { + return false; + } + + // Now cleanup the fallback record. + fallback_record->Delete(); + return true; +} + +} // namespace + // static scoped_ptr<Savegame> Savegame::Create(const Options& options) { - scoped_ptr<Savegame> savegame(new SavegameStarboard(options)); - return savegame.Pass(); + return make_scoped_ptr(new SavegameStarboard(options)).PassAs<Savegame>(); } } // namespace storage
diff --git a/src/glimp/stub/egl/display_impl.cc b/src/glimp/stub/egl/display_impl.cc index 6b49981..447477c 100644 --- a/src/glimp/stub/egl/display_impl.cc +++ b/src/glimp/stub/egl/display_impl.cc
@@ -15,6 +15,7 @@ */ #include "glimp/stub/egl/display_impl.h" + #include "glimp/stub/egl/pbuffer_surface_impl.h" #include "glimp/stub/egl/window_surface_impl.h" #include "glimp/stub/gles/context_impl.h" @@ -65,8 +66,8 @@ (*config)[EGL_LUMINANCE_SIZE] = 0; (*config)[EGL_STENCIL_SIZE] = 0; (*config)[EGL_COLOR_BUFFER_TYPE] = EGL_RGB_BUFFER; - (*config)[EGL_CONFORMANT] = EGL_OPENGL_ES2_BIT; - (*config)[EGL_RENDERABLE_TYPE] = EGL_OPENGL_ES2_BIT; + (*config)[EGL_CONFORMANT] = EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT; + (*config)[EGL_RENDERABLE_TYPE] = EGL_OPENGL_ES2_BIT | EGL_OPENGL_ES3_BIT; (*config)[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT; (*config)[EGL_BIND_TO_TEXTURE_RGBA] = EGL_TRUE;
diff --git a/src/starboard/BUILD.gn b/src/starboard/BUILD.gn new file mode 100644 index 0000000..8adaf0c --- /dev/null +++ b/src/starboard/BUILD.gn
@@ -0,0 +1,97 @@ +# Copyright 2017 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. + +group("all") { + testonly = true + deps = [ + # TODO: uncomment as each of these are implemented + # "//starboard/client_porting/eztime:all", + # "//starboard/client_porting/icu_init:all", + # "//starboard/client_porting/poem:all", + "//starboard/examples", + # "//starboard/nplb/blitter_pixel_tests:all", + "//starboard/nplb:all", + ":starboard", + ] + + has_platform_tests = + exec_script("//build/dir_exists.py", + [ rebase_path("//$starboard_path/tests", root_build_dir) ], + "string") == "True" + if (has_platform_tests) { + deps += [ "//$starboard_path/tests" ] + } +} + +source_set("starboard") { + sources = [ + "atomic.h", + "audio_sink.h", + "blitter.h", + "byte_swap.h", + "character.h", + "condition_variable.h", + "configuration.h", + "decode_target.h", + "directory.h", + "double.h", + "drm.h", + "event.h", + "export.h", + "file.h", + "input.h", + "key.h", + "log.h", + "media.h", + "memory.h", + "microphone.h", + "mutex.h", + "once.h", + "player.h", + "queue.h", + "socket.h", + "socket_waiter.h", + "spin_lock.h", + "storage.h", + "string.h", + "system.h", + "thread.h", + "thread_types.h", + "time.h", + "time_zone.h", + "types.h", + "user.h", + "window.h", + "//starboard/shared/media_session/playback_state.h", + ] + + private_sources = exec_script("tools/find_private_files.py", + [ + rebase_path("//", root_build_dir), + "*.h", + ], + "list lines", + [ "//starboard/private" ]) + sources += rebase_path(private_sources, ".", root_build_dir) + + deps = [ + "//starboard/common", + ] + + public_deps = [ + "//$starboard_path:starboard_platform", + ] + + # TODO: handle shared_main_adapter.cc +}
diff --git a/src/starboard/CHANGELOG.md b/src/starboard/CHANGELOG.md index acbe7b4..6bcc0d7 100644 --- a/src/starboard/CHANGELOG.md +++ b/src/starboard/CHANGELOG.md
@@ -8,12 +8,18 @@ ## Version 6 -### Introduce pointer (mouse) input support. +### Named `SbStorageRecord`s + +This extends the `SbStorage` interface with the ability to open named +`SbStorageRecord`s. Calling `SbStorageOpenRecord` and `SbStorageDeleteRecord` +with a `NULL` `name` parameter provides access to the old "default" record. + +### Introduce pointer (mouse) input support This extends the `SbInput` interface with some enum values and data members to allow mouse, wheel, and more generic pointer input. -### Flexible audio specific config. +### Flexible audio specific config `SbMediaAudioHeader::audio_specific_config` will be a pointer instead of an array. @@ -26,7 +32,7 @@ Changes `SbTimeZoneGetName()` to be more flexible in what it is allowed to return. -### SbDecodeTargetNumberOfPlanesForFormat +### `SbDecodeTargetNumberOfPlanesForFormat` Adds the convenience inline function, SbDecodeTargetNumberOfPlanesForFormat() to `starboard/decode_target.h`. @@ -40,7 +46,7 @@ Removes `SbSystemPlatformErrorType` values specific to user status. -### SbDecodeTarget support for the UYVY (i.e. YUV 422) format +### `SbDecodeTarget` support for the UYVY (i.e. YUV 422) format Add support for UYVY decode targets (e.g. YUV 422) via the `kSbDecodeTargetFormat1PlaneUYVY` enum. @@ -50,15 +56,19 @@ This adds SbKey codes for the colored keys found on most contemporary TV remotes. -### kSbEventTypeLowMemory +### `kSbEventTypeLowMemory` Adds a new event type -- `kSbEventTypeLowMemory` -- to allow a platform to signal that the application may soon be terminated due to low memory availability. -### Interface change to SbPlayerWriteSample() +### Interface change to `SbPlayerWriteSample()` `const` is added to `sample_buffers` and `sample_buffer_sizes` parameters. +### Support key status change +Add `key_statuses_changed_callback` parameter to `SbDrmCreateSystem()` to +support MediaKeySession::keyStatuses and MediaKeySession::onkeystatuseschange. + ## Version 5 ### Add Speech Recognizer API
diff --git a/src/starboard/README.md b/src/starboard/README.md index 1487a1d..9f2d47f 100644 --- a/src/starboard/README.md +++ b/src/starboard/README.md
@@ -5,6 +5,15 @@ that it does not. +## GN Migration Notice + +Cobalt and Starboard are currently migrating from the GYP build system to the GN +build system. This readme contains instructions for both systems. As of now, GN +is not ready for general use for Cobalt/Starboard. If you are not a core Cobalt +developer, you should probably ignore the sections titled "GN Instructions" for +now. + + ## Interesting Source Locations All source locations are specified relative to `src/starboard/` (this directory). @@ -23,17 +32,6 @@ platforms that share some facet of their OS API. -## Building with Starboard - -Follow the Cobalt instructions, except when invoking gyp: - - $ cobalt/build/gyp_cobalt -C debug linux-x64x11 - -and when invoking ninja: - - $ ninja -C out/linux-x64x11_debug cobalt - - ## Quick Guide to Starting a Port ### I. Enumerate and Name Your Platform Configurations @@ -113,6 +111,31 @@ And so on. +#### GN Instructions + +Each `<binary-variant>/` directory must have at least `configuration_public.h`, +`atomic_public.h`, `thread_types_public.h`, `BUILD.gn`, `configuration.gni`, +and `buildconfig.gni`. + +In the BobCo's BobBox example, we would see a directory tree like: + + * `src/third_party/starboard/bobbox/` + * `shared/` + * `mipseb/` + * `buildconfig.gni` + * `configuration.gni` + * `atomic_public.h` + * `BUILD.gn` + * `configuration_public.h` + * `thread_types_public.h` + * `mipsel/` + * `buildconfig.gni` + * `configuration.gni` + * `atomic_public.h` + * `BUILD.gn` + * `configuration_public.h` + * `thread_types_public.h` + ### III. Base Your Port on a Reference Port @@ -160,6 +183,26 @@ `src/third_party/starboard/bobbox/mipseb/gyp_configuration.py`, it would choose the platform configuration name `bobbox-mipseb`.) +#### GN Instructions + +Update `<binary-variant>/BUILD.gn` to point at all the source files that you +want to build as your new Starboard implementation. The `//` expression in GN +refers to the `src/` directory of your source tree. Otherwise, files are assumed +to be relative to the directory the `BUILD.gn` or `.gni` file is in. The +`BUILD.gn` file contains absolute paths, so the paths will still be valid if you +copy it to a new directory. You can then incrementally replace files with new +implementations as necessary. + +In order to use a new platform configuration in a build, you need to ensure that +you have a `BUILD.gn`, `configuration.gni`, and `buildconfig.gni` in their +own directory for each binary variant, plus the header files +`configuration_public.h`, `atomic_public.h`, and `thread_types_public.h`. The GN +build will scan your directories for these files, and then calculate a port name +based on the directories between `src/third_party/starboard` and your +`configuration.gni` files. (e.g. for +`src/third_party/starboard/bobbox/mipseb/configuration.gni`, it would choose the +platform configuration name `bobbox-mipseb`.) + ### IV. A New Port, Step-by-Step @@ -179,7 +222,7 @@ toolchain analogs for the toolchain for your platform. 1. In `gyp_configuration.gypi` 1. Update the names of the configurations and the default_configuration to - be `<platform-configuation>_<build-type>` for your platform + be `<platform-configuration>_<build-type>` for your platform configuration name, where `<build-type>` is one of `debug`, `devel`, `qa`, `gold`. 1. Update your platform variables. @@ -213,6 +256,46 @@ This will attempt to build the "No Platform Left Behind" test suite with your new Starboard implementation, and you are ready to start porting! +#### GN Instructions + +Follow the above list, except: + + 1. Ignore the steps about `gyp_configuration.py` and `gyp_configuration.gypi`. + 1. Update `BUILD.gn` instead of `starboard_platform.gyp`. + 1. Also in `BUILD.gn`: + 1. Update your toolchain command-line flags and libraries, for all + configurations as well as for each individual configuration. + 1. Implement generic compiler configs such as `sb_pedantic_warnings` + and `rtti`. + 1. If you're not using a predefined toolchain, define one. + 1. In `buildconfig.gni`: + 1. If your platform is Linux-based, set `target_os_ = "linux"`. + 1. Set `target_cpu_` to your target architecture (e.g. `arm`, `ppc`, + `x64`, `x86`, `mips`). + 1. Set the target and host toolchains. If you defined a target + toolchain in `BUILD.gn`, you'll want to set it to that. + 1. In `configuration.gni`, set platform-specific defaults for any + variables that should be overriden for your Starboard platform. You + can find a list of such variables at `//cobalt/build/config/base.gni` + and `//starboard/build/config/base.gni`. + + +You should now be able to run GN with your new port. From your `src/` directory: + + $ gn args out/bobbox-mipseb_debug + +An editor will open up. Type into the editor: + + cobalt_config = "debug" + target_platform = "bobbox-mipseb" + +Save and close the editor. Then run + + $ ninja -C out/bobbox-mipseb_debug nplb + +This will attempt to build the "No Platform Left Behind" test suite with your +new Starboard implementation, and you are ready to start porting! + ## Suggested Implementation Order
diff --git a/src/starboard/build/config/BUILD.gn b/src/starboard/build/config/BUILD.gn new file mode 100644 index 0000000..73454f9 --- /dev/null +++ b/src/starboard/build/config/BUILD.gn
@@ -0,0 +1,91 @@ +# Copyright 2017 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. + +# TODO: change to //starboard eventually +import("//cobalt/build/config/base.gni") +import("//starboard/build/delegated_config.gni") + +# ============================================================================= +# COMPILER DEFAULTS +# ============================================================================= + +# TODO: only set these defines on the files that actually need them +config("compiler_defaults") { + # The canonical way to detect Starboard is #if defined(STARBOARD). This + # should be defined both when building Starboard itself, and when building + # any other source file in a Starboard-based project. + defines = [ "STARBOARD" ] + + if (gl_type == "none") { + defines += [ "SB_GYP_GL_TYPE_IS_NONE=1" ] + } else { + defines += [ "SB_GYP_GL_TYPE_IS_NONE=0" ] + } + + if (abort_on_allocation_failure) { + defines += [ "SB_ABORT_ON_ALLOCATION_FAILURE" ] + } + + if (sb_allow_memory_tracking) { + defines += [ "STARBOARD_ALLOWS_MEMORY_TRACKING" ] + } + + if (sb_enable_lib) { + defines += [ "SB_IS_LIBRARY=1" ] + } + + # There doesn't appear to be any way to use the C preprocessor to do + # string concatenation with the / character. This prevents us from using + # the preprocessor to assemble an include file path, so we have to do + # the concatenation here in GN. + # http://stackoverflow.com/questions/29601786/c-preprocessor-building-a-path-string + defines += [ + "STARBOARD_ATOMIC_INCLUDE=\"$starboard_path/atomic_public.h\"", + "STARBOARD_CONFIGURATION_INCLUDE=\"$starboard_path/configuration_public.h\"", + "STARBOARD_THREAD_TYPES_INCLUDE=\"$starboard_path/thread_types_public.h\"", + ] + + # TODO: find a way to remove this dependence on Cobalt + if (sb_media_platform == "starboard") { + defines += [ "SB_GYP_CAN_MEDIA_USE_STARBOARD_PIPELINE=1" ] + } else { + defines += [ "SB_GYP_CAN_MEDIA_USE_STARBOARD_PIPELINE=0" ] + } +} + +# ============================================================================= +# DELEGATED CONFIGS +# ============================================================================= + +# Enables pedantic levels of warnings for the current toolchain. +delegated_config("pedantic_warnings") { + path = "//$starboard_path" + generate_default = false +} + +# Controls the optimization level +delegated_config("optimizations") { + path = "//$starboard_path" + prefixes = [ "no", "debuggable", "full" ] +} + +# Enables/disables rtti +delegated_config("rtti") { + path = "//$starboard_path" +} + +# Enables the exit-time-destructors warning. +config("wexit_time_destructors") { + configs = [ "//$starboard_path:wexit_time_destructors" ] +}
diff --git a/src/starboard/build/config/base.gni b/src/starboard/build/config/base.gni new file mode 100644 index 0000000..7599e71 --- /dev/null +++ b/src/starboard/build/config/base.gni
@@ -0,0 +1,81 @@ +# Copyright 2017 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. + +# Import platform-specific defaults +import("//$starboard_path/configuration.gni") + +# Starboard variables. + +# Enables embedding Starboard as a shared library within another app. This +# requires a 'lib' starboard implementation for the corresponding platform. +if (!defined(sb_enable_lib)) { + sb_enable_lib = false +} + +# Directory path to static contents. +if (!defined(sb_static_contents_output_base_dir)) { + sb_static_contents_output_base_dir = "$root_out_dir/content" +} + +# Directory path to static contents' data. +if (!defined(sb_static_contents_output_data_dir)) { + sb_static_contents_output_data_dir = "$root_out_dir/content/data" +} + +# Halt execution on failure to allocate memory. +if (!defined(abort_on_allocation_failure)) { + abort_on_allocation_failure = true +} + +# The source of EGL and GLES headers and libraries. +# Valid values (case and everything sensitive!): +# "none" - No EGL + GLES implementation is available on this platform. +# "system_gles3" - Use the system implementation of EGL + GLES3. The +# headers and libraries must be on the system include and +# link paths. +# "system_gles2" - Use the system implementation of EGL + GLES2. The +# headers and libraries must be on the system include and +# link paths. +# "glimp" - Cobalt's own EGL + GLES2 implementation. This requires a +# valid Glimp implementation for the platform. +# "angle" - A DirectX-to-OpenGL adaptation layer. This requires a valid +# ANGLE implementation for the platform. +# Choosing an unsupported value will result in a GN error: +# "Unresolved dependencies: //cobalt/renderer/egl_and_gles:<gl_type>" +if (!defined(gl_type)) { + gl_type = "system_gles2" +} + +# TODO: Temporary indicator for Tizen - should eventually move to feature defines. +if (!defined(is_tizen_os)) { + is_tizen_os = false +} + +# The event polling mechanism available on this platform to support libevent. +# Platforms may redefine to "poll" if necessary. +# Other mechanisms, e.g. devpoll, kqueue, select, are not yet supported. +if (!defined(sb_libevent_method)) { + sb_libevent_method = "epoll" +} + +# Whether to allow memory tracking +if (!defined(sb_allow_memory_tracking)) { + sb_allow_memory_tracking = (cobalt_config != "gold" && !sb_enable_lib) +} + + +# The system root for cross-compiles. Default: none. +if (!defined(sysroot)) { + sysroot = "" +}
diff --git a/src/starboard/build/config/fastbuild.gni b/src/starboard/build/config/fastbuild.gni new file mode 100644 index 0000000..b1fe040 --- /dev/null +++ b/src/starboard/build/config/fastbuild.gni
@@ -0,0 +1,18 @@ +# Copyright 2017 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. + +declare_args() { + # If set to true, omits the generation of debugging symbols + cobalt_use_fastbuild = false +}
diff --git a/src/starboard/build/config/sanitizers.gni b/src/starboard/build/config/sanitizers.gni new file mode 100644 index 0000000..a1e9817 --- /dev/null +++ b/src/starboard/build/config/sanitizers.gni
@@ -0,0 +1,40 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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. + +# Allow for platform-specific customization of use_asan_by_default +import("//$starboard_path/configuration.gni") + +declare_args() { + # Compile for Thread Sanitizer to find threading bugs. + use_tsan = false +} + +declare_args() { + # Compile for Address Sanitizer to find memory bugs. + use_asan = + !use_tsan && (cobalt_config == "debug" || cobalt_config == "devel") && + (defined(use_asan_by_default) && use_asan_by_default) +} + +assert(!(use_asan && use_tsan), "ASan and TSan are mutually exclusive") + +if (current_toolchain != default_toolchain) { + # Disable sanitizers for non-default toolchains. + use_asan = false + use_tsan = false +}
diff --git a/src/starboard/build/delegated_config.gni b/src/starboard/build/delegated_config.gni new file mode 100644 index 0000000..cc96a51 --- /dev/null +++ b/src/starboard/build/delegated_config.gni
@@ -0,0 +1,111 @@ +# Copyright 2017 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. + +# The delegated_config template defines a family of configs which delegate to +# real implementations elsewhere. The most notable use of this template is to +# define toolchain-independent compiler configs, such as +# //starboard/build/config:rtti (and its sisters :no_rtti and :default_rtti). +# +# The simplest way to use delegated_config is to specify only a path: +# +# delegated_config("rtti") { +# path = "//$starboard_path" +# } +# +# The sample code above will expand to: +# +# config("rtti") { +# configs = [ "//$starboard_path:rtti" ] +# } +# +# config("no_rtti") { +# configs = [ "//$starboard_path:no_rtti" ] +# } +# +# config("default_rtti") { +# configs = [ "//$starboard_path:default_rtti" ] +# } +# +# The BUILD.gn file is then expected to define each of those three configs (or +# further delegate them to e.g. a toolchain's implementation). +# +# To use a different list of prefixes, set the prefixes option: +# +# delegated_config("optimizations") { +# path = "//$starboard_path" +# prefixes = [ "no", "debuggable", "full" ] +# } +# +# This will expand to: +# +# config("no_optimizations") { +# configs = [ "//$starboard_path:no_optimizations" ] +# } +# +# config("debuggable_optimizations") { +# configs = [ "//$starboard_path:debuggable_optimizations" ] +# } +# +# config("full_optimizations") { +# configs = [ "//$starboard_path:full_optimizations" ] +# } +# +# config("default_optimizations") { +# configs = [ "//$starboard_path:default_optimizations" ] +# } +# +# Note that the default_optimizations config is generated, even though it is +# not in the list of prefixes. If you don't want the default_optimizations +# config to be generated, set generate_default = false: +# +# delegated_config("optimizations") { +# path = "//$starboard_path" +# prefixes = [ "no", "debuggable", "full" ] +# generate_default = false +# } +# +# Now only the no_, debuggable_, and full_ configs will be generated. + +template("delegated_config") { + assert(defined(invoker.path), + "You need to specify a path to the implementation") + + if (defined(invoker.prefixes)) { + prefixes = invoker.prefixes + } else { + prefixes = [ "", "no" ] + } + + foreach(prefix, prefixes) { + assert(prefix != "default", + "You shouldn't include \"default\" in the list of prefixes " + + "because it's separately generated.") + + if (prefix == "") { + prefix_ = prefix + } else { + prefix_ = "${prefix}_" + } + + config("$prefix_$target_name") { + configs = [ "${invoker.path}:$prefix_$target_name" ] + } + } + + if (!(defined(invoker.generate_default) && !invoker.generate_default)) { + config("default_$target_name") { + configs = [ "${invoker.path}:default_$target_name" ] + } + } +}
diff --git a/src/starboard/build/deploy.gni b/src/starboard/build/deploy.gni new file mode 100644 index 0000000..0cd9369 --- /dev/null +++ b/src/starboard/build/deploy.gni
@@ -0,0 +1,52 @@ +# Copyright 2017 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 file is meant to be included to provide a rule to deploy +# a target on a target platform. +# +# Platforms needing such a deploy rule should define a template called +# "deploy", which defines an action target which performs the necessary +# actions (such as copying per-executable metadata files to the output +# directory). This template should preferably be defined in +# //$starboard_path/deploy.gni. +# +# To use this, at the top of the BUILD.gn file, import +# //starboard/build/deploy.gni. Then, define a deploy target: +# +# deploy("deploy") { +# executable_name = "the_primary_targets_name" +# } +# +# See //starboard/nplb/BUILD.gn for an example. + +import("//$starboard_path/configuration.gni") + +if (defined(include_path_platform_deploy_gni)) { + import(include_path_platform_deploy_gni) +} else { + # The default deploy action is to do nothing. + template("deploy") { + not_needed(invoker, "*") + + # Create an empty target so we can still depend on it. Honor the testonly + # and visibility settings. + group(target_name) { + forward_variables_from(invoker, + [ + "testonly", + "visibility", + ]) + } + } +}
diff --git a/src/starboard/build/toolchain/BUILD.gn b/src/starboard/build/toolchain/BUILD.gn new file mode 100644 index 0000000..daf2fb3 --- /dev/null +++ b/src/starboard/build/toolchain/BUILD.gn
@@ -0,0 +1,11 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//starboard/build/toolchain/concurrent_links.gni") + +if (current_toolchain == default_toolchain) { + pool("link_pool") { + depth = concurrent_links + } +}
diff --git a/src/starboard/build/toolchain/asan_symbolizer_path.gni b/src/starboard/build/toolchain/asan_symbolizer_path.gni new file mode 100644 index 0000000..8ca146d --- /dev/null +++ b/src/starboard/build/toolchain/asan_symbolizer_path.gni
@@ -0,0 +1,23 @@ +# Copyright 2017 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. + +import("//starboard/build/config/sanitizers.gni") +import("//starboard/build/toolchain/clang.gni") + +# TODO: is it really necessary to check whether ASAN is on here? +if (use_asan) { + asan_symbolizer_path = "$clang_base_path/bin/llvm-symbolizer" +} else { + asan_symbolizer_path = "" +}
diff --git a/src/starboard/build/toolchain/clang.gni b/src/starboard/build/toolchain/clang.gni new file mode 100644 index 0000000..6ef471a --- /dev/null +++ b/src/starboard/build/toolchain/clang.gni
@@ -0,0 +1,23 @@ +# Copyright 2017 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. + +declare_args() { + clang_base_path = "" +} + +if (clang_base_path == "") { + # clang_base_path depends on gyp_utils.py for its _CLANG_VERSION variable + clang_base_path = exec_script("get_clang_base_path.py", [], "trim string", + [ "//cobalt/build/gyp_utils.py" ]) +}
diff --git a/src/starboard/build/toolchain/concurrent_links.gni b/src/starboard/build/toolchain/concurrent_links.gni new file mode 100644 index 0000000..22ac7e9 --- /dev/null +++ b/src/starboard/build/toolchain/concurrent_links.gni
@@ -0,0 +1,45 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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 file should only be imported from files that define toolchains. +# There's no way to enforce this exactly, but all toolchains are processed +# in the context of the default_toolchain, so we can at least check for that. +assert(current_toolchain == default_toolchain) + +declare_args() { + # Limit the number of concurrent links; we often want to run fewer + # links at once than we do compiles, because linking is memory-intensive. + # The default to use varies by platform and by the amount of memory + # available, so we call out to a script to get the right value. + concurrent_links = -1 +} + +if (concurrent_links == -1) { + if (host_os == "win") { + _args = [ "--mem_per_link_gb=5" ] + } else if (host_os == "mac") { + _args = [ "--mem_per_link_gb=4" ] + } + else { + _args = [] + } + + # TODO(crbug.com/617429) Pass more build configuration info to the script + # so that we can compute better values. + concurrent_links = exec_script("get_concurrent_links.py", _args, "value") +}
diff --git a/src/starboard/build/toolchain/gcc_ar_wrapper.py b/src/starboard/build/toolchain/gcc_ar_wrapper.py new file mode 100755 index 0000000..4663f98 --- /dev/null +++ b/src/starboard/build/toolchain/gcc_ar_wrapper.py
@@ -0,0 +1,58 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Runs the 'ar' command after removing its output file first. + +This script is invoked like: + python gcc_ar_wrapper.py --ar=$AR --output=$OUT $OP $INPUTS +to do the equivalent of: + rm -f $OUT && $AR $OP $OUT $INPUTS +""" + +import argparse +import os +import subprocess +import sys + +import wrapper_utils + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--ar', + required=True, + help='The ar binary to run', + metavar='PATH') + parser.add_argument('--output', + required=True, + help='Output archive file', + metavar='ARCHIVE') + parser.add_argument('--plugin', + help='Load plugin') + parser.add_argument('operation', + help='Operation on the archive') + parser.add_argument('inputs', nargs='+', + help='Input files') + args = parser.parse_args() + + command = [args.ar, args.operation] + if args.plugin is not None: + command += ['--plugin', args.plugin] + command.append(args.output) + command += args.inputs + + # Remove the output file first. + try: + os.remove(args.output) + except OSError as e: + if e.errno != os.errno.ENOENT: + raise + + # Now just run the ar command. + return subprocess.call(wrapper_utils.CommandToRun(command)) + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/src/starboard/build/toolchain/gcc_link_wrapper.py b/src/starboard/build/toolchain/gcc_link_wrapper.py new file mode 100755 index 0000000..b964347 --- /dev/null +++ b/src/starboard/build/toolchain/gcc_link_wrapper.py
@@ -0,0 +1,75 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Runs a linking command and optionally a strip command. + +This script exists to avoid using complex shell commands in +gcc_toolchain.gni's tool("link"), in case the host running the compiler +does not have a POSIX-like shell (e.g. Windows). +""" + +import argparse +import os +import subprocess +import sys + +import wrapper_utils + + +# When running on a Windows host and using a toolchain whose tools are +# actually wrapper scripts (i.e. .bat files on Windows) rather than binary +# executables, the "command" to run has to be prefixed with this magic. +# The GN toolchain definitions take care of that for when GN/Ninja is +# running the tool directly. When that command is passed in to this +# script, it appears as a unitary string but needs to be split up so that +# just 'cmd' is the actual command given to Python's subprocess module. +BAT_PREFIX = 'cmd /c call ' + + +def CommandToRun(command): + if command[0].startswith(BAT_PREFIX): + command = command[0].split(None, 3) + command[1:] + return command + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--strip', + help='The strip binary to run', + metavar='PATH') + parser.add_argument('--unstripped-file', + help='Executable file produced by linking command', + metavar='FILE') + parser.add_argument('--map-file', + help=('Use --Wl,-Map to generate a map file. Will be ' + 'gzipped if extension ends with .gz'), + metavar='FILE') + parser.add_argument('--output', + required=True, + help='Final output executable file', + metavar='FILE') + parser.add_argument('command', nargs='+', + help='Linking command') + args = parser.parse_args() + + # Work-around for gold being slow-by-default. http://crbug.com/632230 + fast_env = dict(os.environ) + fast_env['LC_ALL'] = 'C' + result = wrapper_utils.RunLinkWithOptionalMapFile(args.command, env=fast_env, + map_file=args.map_file) + if result != 0: + return result + + # Finally, strip the linked executable (if desired). + if args.strip: + result = subprocess.call(CommandToRun([ + args.strip, '--strip-unneeded', '-o', args.output, args.unstripped_file + ])) + + return result + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/src/starboard/build/toolchain/gcc_solink_wrapper.py b/src/starboard/build/toolchain/gcc_solink_wrapper.py new file mode 100755 index 0000000..71af5e3 --- /dev/null +++ b/src/starboard/build/toolchain/gcc_solink_wrapper.py
@@ -0,0 +1,145 @@ +#!/usr/bin/env python +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Runs 'ld -shared' and generates a .TOC file that's untouched when unchanged. + +This script exists to avoid using complex shell commands in +gcc_toolchain.gni's tool("solink"), in case the host running the compiler +does not have a POSIX-like shell (e.g. Windows). +""" + +import argparse +import os +import subprocess +import sys + +import wrapper_utils + + +def CollectSONAME(args): + """Replaces: readelf -d $sofile | grep SONAME. + + Args: + args: the args to pass to the subprocess + + Returns: + A tuple of (return code, output) + """ + toc = '' + readelf = subprocess.Popen(wrapper_utils.CommandToRun( + [args.readelf, '-d', args.sofile]), stdout=subprocess.PIPE, bufsize=-1) + for line in readelf.stdout: + if 'SONAME' in line: + toc += line + return readelf.wait(), toc + + +def CollectDynSym(args): + """Replaces: nm --format=posix -g -D $sofile | cut -f1-2 -d' '. + + Args: + args: the args to pass to the subprocess + + Returns: + A tuple of (return code, output) + """ + toc = '' + nm = subprocess.Popen(wrapper_utils.CommandToRun([ + args.nm, '--format=posix', '-g', '-D', args.sofile]), + stdout=subprocess.PIPE, bufsize=-1) + for line in nm.stdout: + toc += ' '.join(line.split(' ', 2)[:2]) + '\n' + return nm.wait(), toc + + +def CollectTOC(args): + result, toc = CollectSONAME(args) + if result == 0: + result, dynsym = CollectDynSym(args) + toc += dynsym + return result, toc + + +def UpdateTOC(tocfile, toc): + if os.path.exists(tocfile): + old_toc = open(tocfile, 'r').read() + else: + old_toc = None + if toc != old_toc: + open(tocfile, 'w').write(toc) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--readelf', + required=True, + help='The readelf binary to run', + metavar='PATH') + parser.add_argument('--nm', + required=True, + help='The nm binary to run', + metavar='PATH') + parser.add_argument('--strip', + help='The strip binary to run', + metavar='PATH') + parser.add_argument('--sofile', + required=True, + help='Shared object file produced by linking command', + metavar='FILE') + parser.add_argument('--tocfile', + required=True, + help='Output table-of-contents file', + metavar='FILE') + parser.add_argument('--map-file', + help=('Use --Wl,-Map to generate a map file. Will be ' + 'gzipped if extension ends with .gz'), + metavar='FILE') + parser.add_argument('--output', + required=True, + help='Final output shared object file', + metavar='FILE') + parser.add_argument('--resource-whitelist', + help='Merge all resource whitelists into a single file.', + metavar='PATH') + parser.add_argument('command', nargs='+', + help='Linking command') + args = parser.parse_args() + + # Work-around for gold being slow-by-default. http://crbug.com/632230 + fast_env = dict(os.environ) + fast_env['LC_ALL'] = 'C' + + if args.resource_whitelist: + whitelist_candidates = wrapper_utils.ResolveRspLinks(args.command) + wrapper_utils.CombineResourceWhitelists( + whitelist_candidates, args.resource_whitelist) + + # First, run the actual link. + command = wrapper_utils.CommandToRun(args.command) + result = wrapper_utils.RunLinkWithOptionalMapFile(command, env=fast_env, + map_file=args.map_file) + + if result != 0: + return result + + # Next, generate the contents of the TOC file. + result, toc = CollectTOC(args) + if result != 0: + return result + + # If there is an existing TOC file with identical contents, leave it alone. + # Otherwise, write out the TOC file. + UpdateTOC(args.tocfile, toc) + + # Finally, strip the linked shared object file (if desired). + if args.strip: + result = subprocess.call(wrapper_utils.CommandToRun( + [args.strip, '--strip-unneeded', '-o', args.output, args.sofile])) + + return result + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/src/starboard/build/toolchain/gcc_toolchain.gni b/src/starboard/build/toolchain/gcc_toolchain.gni new file mode 100644 index 0000000..94c52f4 --- /dev/null +++ b/src/starboard/build/toolchain/gcc_toolchain.gni
@@ -0,0 +1,487 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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. + +import("//starboard/build/toolchain/clang.gni") +import("//starboard/build/toolchain/goma.gni") + +# This template defines a toolchain for something that works like gcc +# (including clang). +# +# It requires the following variables specifying the executables to run: +# - ar +# - cc +# - cxx +# - ld +# +# Optional parameters that control the tools: +# +# - extra_cflags +# Extra flags to be appended when compiling C files (but not C++ files). +# - extra_cppflags +# Extra flags to be appended when compiling both C and C++ files. "CPP" +# stands for "C PreProcessor" in this context, although it can be +# used for non-preprocessor flags as well. Not to be confused with +# "CXX" (which follows). +# - extra_cxxflags +# Extra flags to be appended when compiling C++ files (but not C files). +# - extra_ldflags +# Extra flags to be appended when linking +# +# - libs_section_prefix +# - libs_section_postfix +# The contents of these strings, if specified, will be placed around +# the libs section of the linker line. It allows one to inject libraries +# at the beginning and end for all targets in a toolchain. +# - solink_libs_section_prefix +# - solink_libs_section_postfix +# Same as libs_section_{pre,post}fix except used for solink instead of link. +# - link_outputs +# The content of this array, if specified, will be added to the list of +# outputs from the link command. This can be useful in conjunction with +# the post_link parameter. +# - post_link +# The content of this string, if specified, will be run as a separate +# command following the the link command. +# - deps +# Just forwarded to the toolchain definition. +# - executable_extension +# If this string is specified it will be used for the file extension +# for an executable, rather than using no extension; targets will +# still be able to override the extension using the output_extension +# variable. +# - rebuild_define +# The contents of this string, if specified, will be passed as a #define +# to the toolchain. It can be used to force recompiles whenever a +# toolchain is updated. +# - shlib_extension +# If this string is specified it will be used for the file extension +# for a shared library, rather than default value specified in +# toolchain.gni +# - strip +# Location of the strip executable. When specified, strip will be run on +# all shared libraries and executables as they are built. The pre-stripped +# artifacts will be put in lib.unstripped/ and exe.unstripped/. +template("gcc_toolchain") { + toolchain(target_name) { + assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value") + assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value") + assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value") + assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value") + assert(defined(invoker.shlib_extension), + "gcc_toolchain() must specify a \"shlib_extension\" value") + + # This define changes when the toolchain changes, forcing a rebuild. + # Nothing should ever use this define. + if (defined(invoker.rebuild_define)) { + rebuild_string = "-D" + invoker.rebuild_define + " " + } else { + rebuild_string = "" + } + + # GN's syntax can't handle more than one scope dereference at once, like + # "invoker.toolchain_args.foo", so make a temporary to hold the toolchain + # args so we can do "invoker_toolchain_args.foo". + assert(defined(invoker.toolchain_args), + "Toolchains must specify toolchain_args") + invoker_toolchain_args = invoker.toolchain_args + assert(defined(invoker_toolchain_args.current_cpu), + "toolchain_args must specify a current_cpu") + assert(defined(invoker_toolchain_args.current_os), + "toolchain_args must specify a current_os") + + # When invoking this toolchain not as the default one, these args will be + # passed to the build. They are ignored when this is the default toolchain. + toolchain_args = { + # Populate toolchain args from the invoker. + forward_variables_from(invoker_toolchain_args, "*") + } + + # When the invoker has explicitly overridden use_goma or cc_wrapper in the + # toolchain args, use those values, otherwise default to the global one. + # This works because the only reasonable override that toolchains might + # supply for these values are to force-disable them. + if (defined(toolchain_args.use_goma)) { + toolchain_uses_goma = toolchain_args.use_goma + } else { + toolchain_uses_goma = use_goma + } + + # When the invoker has explicitly overridden use_goma in the + # toolchain args, use those values, otherwise default to the global one. + # This works because the only reasonable override that toolchains might + # supply for these values are to force-disable them. + if (toolchain_uses_goma) { + goma_path = "$goma_dir/gomacc" + compiler_prefix = "${goma_path} " + } else { + compiler_prefix = "" + } + + cc = compiler_prefix + invoker.cc + cxx = compiler_prefix + invoker.cxx + ar = invoker.ar + ld = invoker.ld + if (!defined(asm)) { + asm = cc + } + if (defined(invoker.readelf)) { + readelf = invoker.readelf + } else { + readelf = "readelf" + } + if (defined(invoker.nm)) { + nm = invoker.nm + } else { + nm = "nm" + } + if (defined(invoker.stamp_command)) { + stamp_command = invoker.stamp_command + } else { + stamp_command = "touch {{output}}" + } + if (defined(invoker.copy_command)) { + copy_command = invoker.copy_command + } else { + copy_command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})" + } + + default_shlib_extension = invoker.shlib_extension + + if (defined(invoker.executable_extension)) { + default_executable_extension = invoker.executable_extension + } else { + default_executable_extension = "" + } + + # Bring these into our scope for string interpolation with default values. + if (defined(invoker.libs_section_prefix)) { + libs_section_prefix = invoker.libs_section_prefix + } else { + libs_section_prefix = "" + } + + if (defined(invoker.libs_section_postfix)) { + libs_section_postfix = invoker.libs_section_postfix + } else { + libs_section_postfix = "" + } + + if (defined(invoker.solink_libs_section_prefix)) { + solink_libs_section_prefix = invoker.solink_libs_section_prefix + } else { + solink_libs_section_prefix = "" + } + + if (defined(invoker.solink_libs_section_postfix)) { + solink_libs_section_postfix = invoker.solink_libs_section_postfix + } else { + solink_libs_section_postfix = "" + } + + if (defined(invoker.extra_cflags) && invoker.extra_cflags != "") { + extra_cflags = " " + invoker.extra_cflags + } else { + extra_cflags = "" + } + + if (defined(invoker.extra_cppflags) && invoker.extra_cppflags != "") { + extra_cppflags = " " + invoker.extra_cppflags + } else { + extra_cppflags = "" + } + + if (defined(invoker.extra_cxxflags) && invoker.extra_cxxflags != "") { + extra_cxxflags = " " + invoker.extra_cxxflags + } else { + extra_cxxflags = "" + } + + if (defined(invoker.extra_ldflags) && invoker.extra_ldflags != "") { + extra_ldflags = " " + invoker.extra_ldflags + } else { + extra_ldflags = "" + } + + # These library switches can apply to all tools below. + lib_switch = "-l" + lib_dir_switch = "-L" + + # Object files go in this directory. + object_subdir = "{{target_out_dir}}/{{label_name}}" + + tool("cc") { + depfile = "{{output}}.d" + command = "$cc -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}${extra_cppflags}${extra_cflags} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "CC {{output}}" + outputs = [ + "$object_subdir/{{source_name_part}}.o", + ] + } + + tool("cxx") { + depfile = "{{output}}.d" + command = "$cxx -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_cppflags}${extra_cxxflags} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "CXX {{output}}" + outputs = [ + "$object_subdir/{{source_name_part}}.o", + ] + } + + tool("asm") { + # For GCC we can just use the C compiler to compile assembly. + depfile = "{{output}}.d" + command = "$asm -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "ASM {{output}}" + outputs = [ + "$object_subdir/{{source_name_part}}.o", + ] + } + + tool("alink") { + rspfile = "{{output}}.rsp" + + # This needs a Python script to avoid using simple sh features in this + # command, in case the host does not use a POSIX shell (e.g. compiling + # POSIX-like toolchains such as NaCl on Windows). + ar_wrapper = rebase_path("//starboard/build/toolchain/gcc_ar_wrapper.py", + root_build_dir) + extra_arflags = "rcsD" + command = "$python_path \"$ar_wrapper\" --output={{output}} --ar=\"$ar\" {{arflags}} $extra_arflags @\"$rspfile\"" + description = "AR {{output}}" + rspfile_content = "{{inputs}}" + outputs = [ + "{{output_dir}}/{{target_output_name}}{{output_extension}}", + ] + + # Shared libraries go in the target out directory by default so we can + # generate different targets with the same name and not have them collide. + default_output_dir = "{{target_out_dir}}" + default_output_extension = ".a" + output_prefix = "lib" + } + + tool("solink") { + soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". + sofile = "{{output_dir}}/$soname" # Possibly including toolchain dir. + rspfile = sofile + ".rsp" + pool = "//starboard/build/toolchain:link_pool($default_toolchain)" + + if (defined(invoker.strip)) { + unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname" + } else { + unstripped_sofile = sofile + } + + # These variables are not built into GN but are helpers that + # implement (1) linking to produce a .so, (2) extracting the symbols + # from that file (3) if the extracted list differs from the existing + # .TOC file, overwrite it, otherwise, don't change it. + tocfile = sofile + ".TOC" + + link_command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\"" + + assert(defined(readelf), "to solink you must have a readelf") + assert(defined(nm), "to solink you must have an nm") + strip_switch = "" + if (defined(invoker.strip)) { + strip_switch = "--strip=${invoker.strip} " + } + + # This needs a Python script to avoid using a complex shell command + # requiring sh control structures, pipelines, and POSIX utilities. + # The host might not have a POSIX shell and utilities (e.g. Windows). + solink_wrapper = + rebase_path("//starboard/build/toolchain/gcc_solink_wrapper.py", + root_build_dir) + command = "$python_path \"$solink_wrapper\" --readelf=\"$readelf\" --nm=\"$nm\" $strip_switch--sofile=\"$unstripped_sofile\" --tocfile=\"$tocfile\" --output=\"$sofile\" -- $link_command" + + rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" + + description = "SOLINK $sofile" + + # Use this for {{output_extension}} expansions unless a target manually + # overrides it (in which case {{output_extension}} will be what the target + # specifies). + default_output_extension = default_shlib_extension + + default_output_dir = "{{root_out_dir}}" + + output_prefix = "lib" + + # Since the above commands only updates the .TOC file when it changes, ask + # Ninja to check if the timestamp actually changed to know if downstream + # dependencies should be recompiled. + restat = true + + # Tell GN about the output files. It will link to the sofile but use the + # tocfile for dependency management. + outputs = [ + sofile, + tocfile, + ] + if (sofile != unstripped_sofile) { + outputs += [ unstripped_sofile ] + } + link_output = sofile + depend_output = tocfile + } + + tool("solink_module") { + soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". + sofile = "{{output_dir}}/$soname" + rspfile = sofile + ".rsp" + pool = "//starboard/build/toolchain:link_pool($default_toolchain)" + + if (defined(invoker.strip)) { + unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname" + } else { + unstripped_sofile = sofile + } + + command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\"" + + if (defined(invoker.strip)) { + strip_command = "${invoker.strip} --strip-unneeded -o \"$sofile\" \"$unstripped_sofile\"" + command += " && " + strip_command + } + rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" + + description = "SOLINK_MODULE $sofile" + + # Use this for {{output_extension}} expansions unless a target manually + # overrides it (in which case {{output_extension}} will be what the target + # specifies). + if (defined(invoker.loadable_module_extension)) { + default_output_extension = invoker.loadable_module_extension + } else { + default_output_extension = default_shlib_extension + } + + default_output_dir = "{{root_out_dir}}" + + output_prefix = "lib" + + outputs = [ + sofile, + ] + if (sofile != unstripped_sofile) { + outputs += [ unstripped_sofile ] + } + } + + tool("link") { + exename = "{{target_output_name}}{{output_extension}}" + outfile = "{{output_dir}}/$exename" + rspfile = "$outfile.rsp" + unstripped_outfile = outfile + pool = "//starboard/build/toolchain:link_pool($default_toolchain)" + + # Use this for {{output_extension}} expansions unless a target manually + # overrides it (in which case {{output_extension}} will be what the target + # specifies). + default_output_extension = default_executable_extension + + default_output_dir = "{{root_out_dir}}" + + if (defined(invoker.strip)) { + unstripped_outfile = "{{root_out_dir}}/exe.unstripped/$exename" + } + + start_group_flag = "-Wl,--start-group" + end_group_flag = "-Wl,--end-group " + link_command = "$ld {{ldflags}}${extra_ldflags} -o \"$unstripped_outfile\" $start_group_flag @\"$rspfile\" {{solibs}} $end_group_flag $libs_section_prefix {{libs}} $libs_section_postfix" + + strip_switch = "" + + if (defined(invoker.strip)) { + strip_switch = " --strip=\"${invoker.strip}\" --unstripped-file=\"$unstripped_outfile\"" + } + + link_wrapper = + rebase_path("//starboard/build/toolchain/gcc_link_wrapper.py", + root_build_dir) + command = "$python_path \"$link_wrapper\" --output=\"$outfile\"$strip_switch -- $link_command" + description = "LINK $outfile" + rspfile_content = "{{inputs}}" + outputs = [ + outfile, + ] + if (outfile != unstripped_outfile) { + outputs += [ unstripped_outfile ] + } + if (defined(invoker.link_outputs)) { + outputs += invoker.link_outputs + } + } + + # These two are really entirely generic, but have to be repeated in + # each toolchain because GN doesn't allow a template to be used here. + # See //build/toolchain/toolchain.gni for details. + tool("stamp") { + command = stamp_command + description = "STAMP {{output}}" + } + tool("copy") { + command = copy_command + description = "COPY {{source}} {{output}}" + } + + forward_variables_from(invoker, [ "deps" ]) + } +} + +# This is a shorthand for gcc_toolchain instances based on the Chromium-built +# version of Clang. Only the toolchain_cpu and toolchain_os variables need to +# be specified by the invoker, and optionally toolprefix if it's a +# cross-compile case. Note that for a cross-compile case this toolchain +# requires a config to pass the appropriate -target option, or else it will +# actually just be doing a native compile. The invoker can optionally override +# use_gold too. +template("clang_toolchain") { + if (defined(invoker.toolprefix)) { + toolprefix = invoker.toolprefix + } else { + toolprefix = "" + } + + gcc_toolchain(target_name) { + prefix = rebase_path("$clang_base_path/bin", root_build_dir) + cc = "$prefix/clang" + cxx = "$prefix/clang++" + ld = cxx + readelf = "${toolprefix}readelf" + ar = "${prefix}/llvm-ar" + nm = "${toolprefix}nm" + + forward_variables_from(invoker, + [ + "strip", + "is_clang_analysis_supported", + "shlib_extension", + ]) + + toolchain_args = { + if (defined(invoker.toolchain_args)) { + forward_variables_from(invoker.toolchain_args, "*") + } + } + } +}
diff --git a/src/starboard/build/toolchain/get_clang_base_path.py b/src/starboard/build/toolchain/get_clang_base_path.py new file mode 100755 index 0000000..d6fc75a --- /dev/null +++ b/src/starboard/build/toolchain/get_clang_base_path.py
@@ -0,0 +1,40 @@ +#!/usr/bin/env python +# Copyright 2017 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. + +"""Finds and prints the Clang base path. + +If Clang is not present, it will be downloaded. +""" + +import os.path +import sys + +sys.path.append( + os.path.realpath( + os.path.join( + os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))) +from cobalt.build.gyp_utils import EnsureClangAvailable # pylint: disable=g-import-not-at-top +from cobalt.build.gyp_utils import GetClangBasePath +from cobalt.build.gyp_utils import GetClangBinPath + + +def main(): + base_dir = GetClangBasePath() + bin_path = GetClangBinPath() + EnsureClangAvailable(base_dir, bin_path) + print os.path.join(base_dir, 'llvm-build', 'Release+Asserts') + +if __name__ == '__main__': + main()
diff --git a/src/starboard/build/toolchain/get_concurrent_links.py b/src/starboard/build/toolchain/get_concurrent_links.py new file mode 100644 index 0000000..be5640a --- /dev/null +++ b/src/starboard/build/toolchain/get_concurrent_links.py
@@ -0,0 +1,86 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Computes and prints the default number of concurrent links. + +Computes the number of concurrent links to be run in the build, as a function +of machine spec. Based on GetDefaultConcurrentLinks in GYP. +""" + +import ctypes +import optparse +import os +import re +import subprocess +import sys + + +def _GetTotalMemoryInBytes(): + """Gets the total amount of virtual memory in bytes. + + Returns: + See above + """ + if sys.platform in ('win32', 'cygwin'): + + class MEMORYSTATUSEX(ctypes.Structure): + _fields_ = [ + ('dwLength', ctypes.c_ulong), + ('dwMemoryLoad', ctypes.c_ulong), + ('ullTotalPhys', ctypes.c_ulonglong), + ('ullAvailPhys', ctypes.c_ulonglong), + ('ullTotalPageFile', ctypes.c_ulonglong), + ('ullAvailPageFile', ctypes.c_ulonglong), + ('ullTotalVirtual', ctypes.c_ulonglong), + ('ullAvailVirtual', ctypes.c_ulonglong), + ('sullAvailExtendedVirtual', ctypes.c_ulonglong), + ] + + stat = MEMORYSTATUSEX(dwLength=ctypes.sizeof(MEMORYSTATUSEX)) + ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat)) + return stat.ullTotalPhys + elif sys.platform.startswith('linux'): + if os.path.exists('/proc/meminfo'): + with open('/proc/meminfo') as meminfo: + memtotal_re = re.compile(r'^MemTotal:\s*(\d*)\s*kB') + for line in meminfo: + match = memtotal_re.match(line) + if not match: + continue + return float(match.group(1)) * 2**10 + elif sys.platform == 'darwin': + try: + return int(subprocess.check_output(['sysctl', '-n', 'hw.memsize'])) + except subprocess.CalledProcessError: + return 0 + # TODO: Implement this for other platforms. + return 0 + + +def _GetDefaultConcurrentLinks(mem_per_link_gb, reserve_mem_gb): + # Inherit the legacy environment variable for people that have set it in GYP. + pool_size = int(os.getenv('GYP_LINK_CONCURRENCY', 0)) + if pool_size: + return pool_size + + mem_total_bytes = _GetTotalMemoryInBytes() + mem_total_bytes = max(0, mem_total_bytes - reserve_mem_gb * 2**30) + num_concurrent_links = int(max(1, mem_total_bytes / mem_per_link_gb / 2**30)) + hard_cap = max(1, int(os.getenv('GYP_LINK_CONCURRENCY_MAX', 2**32))) + return min(num_concurrent_links, hard_cap) + + +def main(): + parser = optparse.OptionParser() + parser.add_option('--mem_per_link_gb', action='store', type='int', default=6) + parser.add_option('--reserve_mem_gb', action='store', type='int', default=0) + parser.disable_interspersed_args() + options, _ = parser.parse_args() + + print _GetDefaultConcurrentLinks(options.mem_per_link_gb, + options.reserve_mem_gb) + return 0 + +if __name__ == '__main__': + sys.exit(main())
diff --git a/src/starboard/build/toolchain/goma.gni b/src/starboard/build/toolchain/goma.gni new file mode 100644 index 0000000..dd72cefe --- /dev/null +++ b/src/starboard/build/toolchain/goma.gni
@@ -0,0 +1,40 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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. + +# Defines the configuration of Goma. + +# Allow ports to set an alternate default for use_goma +import("//$starboard_path/configuration.gni") + +declare_args() { + if (!defined(use_goma)) { + # Set to true to enable distributed compilation using Goma. By default we + # use Goma for stub and linux. + use_goma = false + } + + # Set the default value based on the platform. + if (host_os == "win" || host_os == "winrt_81" || + host_os == "winrt_81_phone" || host_os == "winrt_10") { + # Absolute directory containing the gomacc.exe binary. + goma_dir = "C:\goma\goma-win64" + } else { + # Absolute directory containing the gomacc binary. + goma_dir = getenv("HOME") + "/goma" + } +}
diff --git a/src/starboard/build/toolchain/linux/BUILD.gn b/src/starboard/build/toolchain/linux/BUILD.gn new file mode 100644 index 0000000..962109a --- /dev/null +++ b/src/starboard/build/toolchain/linux/BUILD.gn
@@ -0,0 +1,217 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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. + +import("//starboard/build/toolchain/gcc_toolchain.gni") + +clang_toolchain("clang_arm") { + toolprefix = "arm-linux-gnueabihf-" + shlib_extension = ".so" + toolchain_args = { + current_cpu = "arm" + current_os = "linux" + } +} + +clang_toolchain("clang_arm64") { + toolprefix = "aarch64-linux-gnu-" + shlib_extension = ".so" + toolchain_args = { + current_cpu = "arm64" + current_os = "linux" + } +} + +gcc_toolchain("arm64") { + toolprefix = "aarch64-linux-gnu-" + shlib_extension = ".so" + + cc = "${toolprefix}gcc" + cxx = "${toolprefix}g++" + + ar = "${toolprefix}ar" + ld = cxx + readelf = "${toolprefix}readelf" + nm = "${toolprefix}nm" + + toolchain_args = { + current_cpu = "arm64" + current_os = "linux" + } +} + +gcc_toolchain("arm") { + toolprefix = "arm-linux-gnueabihf-" + shlib_extension = ".so" + + cc = "${toolprefix}gcc" + cxx = "${toolprefix}g++" + + ar = "${toolprefix}ar" + ld = cxx + readelf = "${toolprefix}readelf" + nm = "${toolprefix}nm" + + toolchain_args = { + current_cpu = "arm" + current_os = "linux" + } +} + +clang_toolchain("clang_x86") { + shlib_extension = ".so" + + toolchain_args = { + current_cpu = "x86" + current_os = "linux" + } +} + +gcc_toolchain("x86") { + shlib_extension = ".so" + + cc = "gcc" + cxx = "g++" + + readelf = "readelf" + nm = "nm" + ar = "ar" + ld = cxx + + toolchain_args = { + current_cpu = "x86" + current_os = "linux" + } +} + +clang_toolchain("clang_x64") { + shlib_extension = ".so" + + toolchain_args = { + current_cpu = "x64" + current_os = "linux" + } +} + +gcc_toolchain("x64") { + shlib_extension = ".so" + + cc = "gcc" + cxx = "g++" + + readelf = "readelf" + nm = "nm" + ar = "ar" + ld = cxx + + toolchain_args = { + current_cpu = "x64" + current_os = "linux" + } +} + +clang_toolchain("clang_mipsel") { + shlib_extension = ".so" + toolchain_args = { + current_cpu = "mipsel" + current_os = "linux" + } +} + +gcc_toolchain("mipsel") { + shlib_extension = ".so" + + cc = "mipsel-linux-gnu-gcc" + cxx = "mipsel-linux-gnu-g++" + ar = "mipsel-linux-gnu-ar" + ld = cxx + readelf = "mipsel-linux-gnu-readelf" + nm = "mipsel-linux-gnu-nm" + + toolchain_args = { + current_cpu = "mipsel" + current_os = "linux" + } +} + +gcc_toolchain("s390x") { + shlib_extension = ".so" + + cc = "gcc" + cxx = "g++" + + readelf = "readelf" + nm = "nm" + ar = "ar" + ld = cxx + + toolchain_args = { + current_cpu = "s390x" + current_os = "linux" + } +} + +gcc_toolchain("ppc64") { + shlib_extension = ".so" + + cc = "gcc" + cxx = "g++" + + readelf = "readelf" + nm = "nm" + ar = "ar" + ld = cxx + + toolchain_args = { + current_cpu = "ppc64" + current_os = "linux" + } +} + +gcc_toolchain("mips") { + shlib_extension = ".so" + + cc = "gcc" + cxx = "g++" + + readelf = "readelf" + nm = "nm" + ar = "ar" + ld = cxx + + toolchain_args = { + current_cpu = "mips" + current_os = "linux" + } +} + +gcc_toolchain("mips64") { + shlib_extension = ".so" + + cc = "gcc" + cxx = "g++" + + readelf = "readelf" + nm = "nm" + ar = "ar" + ld = cxx + + toolchain_args = { + current_cpu = "mips64" + current_os = "linux" + } +}
diff --git a/src/starboard/build/toolchain/linux/config/BUILD.gn b/src/starboard/build/toolchain/linux/config/BUILD.gn new file mode 100644 index 0000000..63f8da6 --- /dev/null +++ b/src/starboard/build/toolchain/linux/config/BUILD.gn
@@ -0,0 +1,42 @@ +# Copyright 2017 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. + +# Sets the optimization level +config("no_optimizations") { + cflags = [ "-O0" ] +} + +config("debuggable_optimizations") { + cflags = [ "-O2" ] +} + +config("full_optimizations") { + cflags = [ "-O3" ] +} + + +# Enables/disables RTTI +config("rtti") { + cflags_cc = [ "-frtti" ] +} + +config("no_rtti") { + cflags_cc = [ "-fno-rtti" ] +} + + +# Enables -Wexit-time-destructors. Only usable for Clang. +config("wexit_time_destructors") { + cflags = [ "-Wexit-time-destructors" ] +}
diff --git a/src/starboard/build/toolchain/wrapper_utils.py b/src/starboard/build/toolchain/wrapper_utils.py new file mode 100644 index 0000000..d01933d --- /dev/null +++ b/src/starboard/build/toolchain/wrapper_utils.py
@@ -0,0 +1,150 @@ +# Copyright (c) 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Helper functions for gcc_toolchain.gni wrappers.""" + +import gzip +import os +import re +import shlex +import shutil +import subprocess +import threading + +_BAT_PREFIX = 'cmd /c call ' +_WHITELIST_RE = re.compile('whitelisted_resource_(?P<resource_id>[0-9]+)') + + +def _GzipThenDelete(src_path, dest_path): + # Results for Android map file with GCC on a z620: + # Uncompressed: 207MB + # gzip -9: 16.4MB, takes 8.7 seconds. + # gzip -1: 21.8MB, takes 2.0 seconds. + # Piping directly from the linker via -print-map (or via -Map with a fifo) + # adds a whopping 30-45 seconds! + with open(src_path, 'rb') as f_in, gzip.GzipFile(dest_path, 'wb', 1) as f_out: + shutil.copyfileobj(f_in, f_out) + os.unlink(src_path) + + +def CommandToRun(command): + """Generates commands compatible with Windows. + + When running on a Windows host and using a toolchain whose tools are + actually wrapper scripts (i.e. .bat files on Windows) rather than binary + executables, the |command| to run has to be prefixed with this magic. + The GN toolchain definitions take care of that for when GN/Ninja is + running the tool directly. When that command is passed in to this + script, it appears as a unitary string but needs to be split up so that + just 'cmd' is the actual command given to Python's subprocess module. + + Args: + command: List containing the UNIX style |command|. + + Returns: + A list containing the Windows version of the |command|. + """ + if command[0].startswith(_BAT_PREFIX): + command = command[0].split(None, 3) + command[1:] + return command + + +def RunLinkWithOptionalMapFile(command, env=None, map_file=None): + """Runs the given command, adding in -Wl,-Map when |map_file| is given. + + Also takes care of gzipping when |map_file| ends with .gz. + + Args: + command: List of arguments comprising the command. + env: Environment variables. + map_file: Path to output map_file. + + Returns: + The exit code of running |command|. + """ + tmp_map_path = None + if map_file and map_file.endswith('.gz'): + tmp_map_path = map_file + '.tmp' + command.append('-Wl,-Map,' + tmp_map_path) + elif map_file: + command.append('-Wl,-Map,' + map_file) + + result = subprocess.call(command, env=env) + + if tmp_map_path and result == 0: + threading.Thread( + target=lambda: _GzipThenDelete(tmp_map_path, map_file)).start() + elif tmp_map_path and os.path.exists(tmp_map_path): + os.unlink(tmp_map_path) + + return result + + +def ResolveRspLinks(inputs): + """Return a list of files contained in a response file. + + Args: + inputs: A command containing rsp files. + + Returns: + A set containing the rsp file content. + """ + rspfiles = [a[1:] for a in inputs if a.startswith('@')] + resolved = set() + for rspfile in rspfiles: + with open(rspfile, 'r') as f: + resolved.update(shlex.split(f.read())) + + return resolved + + +def CombineResourceWhitelists(whitelist_candidates, outfile): + """Combines all whitelists for a resource file into a single whitelist. + + Args: + whitelist_candidates: List of paths to rsp files containing all targets. + outfile: Path to save the combined whitelist. + """ + whitelists = ('%s.whitelist' % candidate for candidate in whitelist_candidates + if os.path.exists('%s.whitelist' % candidate)) + + resources = set() + for whitelist in whitelists: + with open(whitelist, 'r') as f: + resources.update(f.readlines()) + + with open(outfile, 'w') as f: + f.writelines(resources) + + +def ExtractResourceIdsFromPragmaWarnings(text): + """Returns set of resource IDs that are inside unknown pragma warnings. + + Args: + text: The text that will be scanned for unknown pragma warnings. + + Returns: + A set containing integers representing resource IDs. + """ + used_resources = set() + lines = text.splitlines() + for ln in lines: + match = _WHITELIST_RE.search(ln) + if match: + resource_id = int(match.group('resource_id')) + used_resources.add(resource_id) + + return used_resources + + +def CaptureCommandStderr(command, env=None): + """Returns the stderr of a command. + + Args: + command: A list containing the command and arguments. + env: Environment variables for the new process. + """ + child = subprocess.Popen(command, stderr=subprocess.PIPE, env=env) + _, stderr = child.communicate() + return child.returncode, stderr
diff --git a/src/starboard/byte_swap.h b/src/starboard/byte_swap.h index 9fbd1fa..2347bd2 100644 --- a/src/starboard/byte_swap.h +++ b/src/starboard/byte_swap.h
@@ -82,4 +82,47 @@ } // extern "C" #endif +#ifdef __cplusplus + +#include <algorithm> + +template <typename T> +T SbByteSwap(T value) { + std::reverse(reinterpret_cast<uint8_t*>(&value), + reinterpret_cast<uint8_t*>(&value + 1)); + return value; +} + +template <> +inline int16_t SbByteSwap(int16_t value) { + return SbByteSwapS16(value); +} + +template <> +inline uint16_t SbByteSwap(uint16_t value) { + return SbByteSwapU16(value); +} + +template <> +inline int32_t SbByteSwap(int32_t value) { + return SbByteSwapS32(value); +} + +template <> +inline uint32_t SbByteSwap(uint32_t value) { + return SbByteSwapU32(value); +} + +template <> +inline int64_t SbByteSwap(int64_t value) { + return SbByteSwapS64(value); +} + +template <> +inline uint64_t SbByteSwap(uint64_t value) { + return SbByteSwapU64(value); +} + +#endif + #endif // STARBOARD_BYTE_SWAP_H_
diff --git a/src/starboard/common/BUILD.gn b/src/starboard/common/BUILD.gn new file mode 100644 index 0000000..6d9fcbd --- /dev/null +++ b/src/starboard/common/BUILD.gn
@@ -0,0 +1,46 @@ +# Copyright 2017 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. + +# TODO: change to //starboard eventually +import("//cobalt/build/config/base.gni") + +static_library("common") { + sources = [ + "common.cc", + "flat_map.h", + "memory.cc", + "move.h", + "new.cc", + "optional.cc", + "ref_counted.cc", + "ref_counted.h", + "reset_and_return.h", + "rwlock.h", + "semaphore.h", + "scoped_ptr.h", + "state_machine.cc", + "state_machine.h", + "thread_collision_warner.cc", + "thread_collision_warner.h", + ] + + # TODO: get rid of dependence on Cobalt + if (!enable_custom_media_session_client) { + sources += [ "//starboard/shared/media_session/stub_playback_state.cc" ] + } + + # This must be defined when building Starboard, and must not when building + # Starboard client code. + defines = [ "STARBOARD_IMPLEMENTATION" ] +}
diff --git a/src/starboard/common/common.gyp b/src/starboard/common/common.gyp index bf285ef..f85fbb5 100644 --- a/src/starboard/common/common.gyp +++ b/src/starboard/common/common.gyp
@@ -29,12 +29,15 @@ 'memory.cc', 'move.h', 'new.cc', + 'optional.cc', 'ref_counted.cc', 'ref_counted.h', 'reset_and_return.h', 'rwlock.h', 'semaphore.h', 'scoped_ptr.h', + 'state_machine.cc', + 'state_machine.h', 'thread_collision_warner.cc', 'thread_collision_warner.h', ],
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/common/optional.cc similarity index 69% copy from src/starboard/win/lib/atomic_public.h copy to src/starboard/common/optional.cc index be4e805..f9618d1 100644 --- a/src/starboard/win/lib/atomic_public.h +++ b/src/starboard/common/optional.cc
@@ -1,4 +1,4 @@ -// Copyright 2017 Google Inc. All Rights Reserved. +// Copyright 2014 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. @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ -#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +#include "starboard/common/optional.h" -#include "starboard/shared/win32/atomic_public.h" - -#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +namespace starboard { +const nullopt_t nullopt; +const in_place_t in_place; +} // namespace starboard
diff --git a/src/starboard/common/optional.h b/src/starboard/common/optional.h new file mode 100644 index 0000000..8e8fc00 --- /dev/null +++ b/src/starboard/common/optional.h
@@ -0,0 +1,428 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef STARBOARD_COMMON_OPTIONAL_H_ +#define STARBOARD_COMMON_OPTIONAL_H_ + +#include <algorithm> +#include <iosfwd> + +#include "starboard/configuration.h" +#include "starboard/export.h" +#include "starboard/log.h" +#include "starboard/memory.h" + +namespace starboard { + +// This class is based off of std::experimental::optional: +// http://en.cppreference.com/w/cpp/experimental/optional +// +// It is a template class where instances parameterized by type T contain +// memory for an instance of type T, but it may or may not be constructed. +// If it is not constructed, it cannot be accessed, and if it is, it can +// be accessed. This allows one to check if the inner object exists or not +// before using it, and is useful for functions that may or may not return +// a value. Note that the memory for the object is stored internally, so +// no heap allocations are made over the course of construction and destruction +// of the internal object (unless the internal object allocates memory within +// its constructor). +// +// Some functionality is left out. For example, most C++11 functionality +// is not implemented, since we would like this to be friendly to non-C++11 +// compilers. +// +// In the future, if C++11 functionality is needed, it can be implemented +// and surrounded by preprocessor guards to maintain compatibility with non +// C++11 compilers. +// + +// The nullopt_t type is used as a signal for an empty optional. If any +// optional is assigned the value of nullopt, it will be disengaged. +// For example, +// starboard::optional<int> my_int_optional(5); +// EXPECT_FALSE(!my_int_optional); +// my_int_optional = starboard::nullopt; +// EXPECT_TRUE(!my_int_optional); +// +struct nullopt_t { + nullopt_t() {} +}; +extern const nullopt_t nullopt; + +// The in_place_t type is used to signal in-place construction of the internal +// object. This is used by the in place constructor of optional, which forwards +// its parameters to the internal object's constructor. +// For example, +// class Foo { +// public: +// Foo(int x, int y) { x_ = x; y_ = y; } +// int x() const { return x_; } +// int y() const { return y_; } +// +// private: +// int x_; +// int y_; +// }; +// +// ... +// +// base::optional<Foo> my_foo(base::in_place, 2, 3); +// EXPECT_FALSE(!my_foo); +// EXPECT_EQ(2, my_foo->x()); +// EXPECT_EQ(3, my_foo->y()); +// +struct in_place_t { + in_place_t() {} +}; +extern const in_place_t in_place; + +template <typename T> +class SB_EXPORT optional { + public: + // Construction via the default constructor results in an optional that is + // not engaged. + optional() { InitializeAsDisengaged(); } + + optional(nullopt_t) { InitializeAsDisengaged(); } // NOLINT(runtime/explicit) + + // This non-explicit singleton constructor is provided so users can pass in a + // T wherever a optional<T> is expected. + optional(const T& value) { SetValue(value); } // NOLINT(runtime/explicit) + + optional(const optional<T>& other) { // NOLINT(runtime/explicit) + if (other.engaged_) { + SetValue(other.value()); + } else { + InitializeAsDisengaged(); + } + } + + // Move constructor. + // NOLINTNEXTLINE(runtime/explicit) + optional(optional&& other) { // NOLINT(build/c++11) + if (other.engaged_) { + SetValue(std::move(other.value())); + } else { + InitializeAsDisengaged(); + } + } + + // Move value constructor. + // NOLINTNEXTLINE(runtime/explicit) + optional(T&& other) { // NOLINT(build/c++11) + SetValue(std::move(other)); + } + + // Destruct contained object upon optional's destruction. + ~optional() { EnsureDisengaged(); } + + // Disengages the optional, calling the destructor of the contained object + // if it is engaged. + optional<T>& operator=(nullopt_t) { + EnsureDisengaged(); + return *this; + } + + // Reassigns the underlying optional to value passed in on the right hand + // side. This will destruct the lhs contained object first if it exists. + template <typename U> + optional<T>& operator=(const U& other) { + if (engaged_) { + value() = other; + } else { + SetValue(other); + } + return *this; + } + + // Copy assignment. + optional<T>& operator=(const optional<T>& other) { + if (engaged_ && other.engaged_) { + value() = other.value(); + } else if (!engaged_ && other.engaged_) { + SetValue(other.value()); + } else if (engaged_ && !other.engaged_) { + EnsureDisengaged(); + } + // Do nothing if lhs and rhs are both not engaged. + return *this; + } + + // Move value assignment. + optional<T>& operator=(T&& other) { // NOLINT(build/c++11) + if (engaged_) { + value() = std::move(other); + } else { + SetValue(std::move(other)); + } + return *this; + } + + // Move optional assignment. + optional<T>& operator=(optional&& other) { // NOLINT(build/c++11) + if (engaged_ && other.engaged_) { + value() = std::move(other.value()); + } else if (!engaged_ && other.engaged_) { + SetValue(std::move(other.value())); + } else if (engaged_ && !other.engaged_) { + EnsureDisengaged(); + } + // Do nothing if lhs and rhs are both not engaged. + return *this; + } + +// Overloaded conversion to bool operator for determining whether the optional +// is engaged or not. It returns true if the optional is engaged, and false +// otherwise. +#if (defined(_MSC_VER) && (_MSC_VER < 1800)) || \ + (defined(__GNUC__) && \ + (__GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 5)))) + // MSVC 2012 does not support explicit cast operators. + // http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx + + // For any compiler that doesn't support explicit bool operators, we instead + // use the Safe Bool Idiom: http://www.artima.com/cppsource/safebool.html + private: + // The type of SafeBoolIdiomType (pointer to data member of a private type) is + // limited in functionality so much that the only thing a user can do with it + // is test for null, or apply to operator==/operator!=. Since both operators + // == and != are already overloaded for optional, this leaves null tests, + // which we use for boolean testing. + class PrivateSafeBoolIdiomFakeMemberType; + typedef PrivateSafeBoolIdiomFakeMemberType optional::*SafeBoolIdiomType; + + public: + operator const SafeBoolIdiomType() const { + // If we wish to return true, we cast engaged_ to our private type giving + // a non-null pointer to data member. Otherwise, we return NULL. The + // only thing the user can do with the return type is test for NULL. + return engaged_ + ? reinterpret_cast<const SafeBoolIdiomType>(&optional::engaged_) + : NULL; + } +#else + explicit operator bool() const { return engaged_; } +#endif + + // Dereferences the internal object. + const T* operator->() const { return &(value()); } + + T* operator->() { return &(value()); } + + const T& operator*() const { return value(); } + + T& operator*() { return value(); } + + // Dereferences and returns the internal object. + const T& value() const { + SB_DCHECK(engaged_) + << "Attempted to access object in a disengaged optional."; + return *static_cast<const T*>(void_value()); + } + + T& value() { + SB_DCHECK(engaged_) + << "Attempted to access object in a disengaged optional."; + return *static_cast<T*>(void_value()); + } + + template <typename U> + T value_or(const U& value) const { + if (engaged_) { + return this->value(); + } else { + return value; + } + } + + // Swaps the values of two optionals. + void swap(optional<T>& other) { + if (engaged_ && other.engaged_) { + // Swap the value contents with each other. + std::swap(value(), other.value()); + } else if (engaged_) { + other.SetValue(std::move(value())); + EnsureDisengaged(); + } else if (other.engaged_) { + SetValue(std::move(other.value())); + other.EnsureDisengaged(); + } + // If both the lhs and rhs are not engaged, we do nothing. + } + +// Include the pump.py-generated declaration and implementation for the +// forwarding constructor and emplace. +#include "starboard/common/optional_internal.h" + + private: + // Sets a non-engaged optional to a specified value, and marks it as engaged. + void SetValue(T&& value) { // NOLINT(build/c++11) + new (void_value()) T(std::move(value)); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + + // Sets a non-engaged optional to a specified value, and marks it as engaged. + template <typename U> + void SetValue(const U& value) { + new (void_value()) T(value); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + + // If an optional is engaged, it destructs the wrapped value and marks the + // optional as disengaged. Does nothing to a disengaged optional. + void EnsureDisengaged() { + if (engaged_) { + static_cast<T*>(void_value())->~T(); + engaged_ = false; +#if !defined(NDEBUG) + value_ptr_ = NULL; +#endif + } + } + + // Called upon object construction to initialize the object into a disengaged + // state. + void InitializeAsDisengaged() { + engaged_ = false; +#if !defined(NDEBUG) + value_ptr_ = NULL; +#endif + } + + const void* void_value() const { + return reinterpret_cast<const void*>(value_memory_); + } + void* void_value() { return reinterpret_cast<void*>(value_memory_); } + + // The actual memory reserved for the object that may or may not exist. + SB_ALIGNAS(SB_ALIGNOF(T)) uint8_t value_memory_[sizeof(T)]; + // This boolean tracks whether or not the object is constructed yet or not. + bool engaged_; +#if !defined(NDEBUG) + // In debug builds, this member makes it easy to inspect the value contained + // in the optional via a debugger. + const T* value_ptr_; +#endif +}; + +// Comparison between 2 optionals +template <typename T> +inline bool operator==(const optional<T>& lhs, const optional<T>& rhs) { + if (!lhs) { + return !rhs; + } + + return rhs == lhs.value(); +} + +template <typename T> +inline bool operator<(const optional<T>& lhs, const optional<T>& rhs) { + if (lhs && rhs) { + return lhs.value() < rhs.value(); + } else { + // Handle all other cases simply in terms of whether the optionals are + // engaged or not. + return static_cast<bool>(lhs) < static_cast<bool>(rhs); + } +} + +// Comparison with nullopt_t +template <typename T> +inline bool operator==(nullopt_t, const optional<T>& rhs) { + return !rhs; +} + +template <typename T> +inline bool operator==(const optional<T>& lhs, nullopt_t rhs) { + return rhs == lhs; +} + +template <typename T> +inline bool operator<(const optional<T>& /* lhs */, nullopt_t) { + return false; +} + +template <typename T> +inline bool operator<(nullopt_t, const optional<T>& rhs) { + return static_cast<bool>(rhs); +} + +// Comparison between an optional and a value +template <typename T> +inline bool operator==(const optional<T>& lhs, const T& rhs) { + return (!lhs ? false : lhs.value() == rhs); +} + +template <typename T> +inline bool operator==(const T& lhs, const optional<T>& rhs) { + return rhs == lhs; +} + +template <typename T> +inline bool operator<(const T& lhs, const optional<T>& rhs) { + return rhs && lhs < rhs.value(); +} + +template <typename T> +inline bool operator<(const optional<T>& lhs, const T& rhs) { + return !lhs || lhs.value() < rhs; +} + +// This is a convenient but non-standard method, do not rely on it if you expect +// the compatibility with upcoming C++ versions. +template <typename T> +inline std::ostream& operator<<(std::ostream& stream, + const optional<T>& maybe_value) { + if (maybe_value) { + stream << *maybe_value; + } else { + stream << "nullopt"; + } + return stream; +} + +template <typename T> +optional<T> make_optional(const T& value) { + return optional<T>(value); +} + +} // namespace starboard + +namespace std { + +template <typename T> +struct hash<::starboard::optional<T> > { + public: + size_t operator()(const ::starboard::optional<T>& value) const { + return (value ? value_hash_(value.value()) : 0); + } + + private: + hash<T> value_hash_; +}; + +template <typename T> +void swap(::starboard::optional<T>& lhs, ::starboard::optional<T>& rhs) { + lhs.swap(rhs); +} + +} // namespace std + +#endif // STARBOARD_COMMON_OPTIONAL_H_
diff --git a/src/starboard/common/optional_internal.h b/src/starboard/common/optional_internal.h new file mode 100644 index 0000000..355e1db --- /dev/null +++ b/src/starboard/common/optional_internal.h
@@ -0,0 +1,180 @@ +// This file was GENERATED by command: +// pump.py optional_internal.h.pump +// DO NOT EDIT BY HAND!!! + +// +// 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. +// + +// clang-format off +// Begin forwarding constructor definitions //////////////////////////////////// + explicit optional(in_place_t) { + InitializeAsDisengaged(); + new (void_value()) T(); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1> + explicit optional(in_place_t, const P1& p1) { + InitializeAsDisengaged(); + new (void_value()) T(p1); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2> + explicit optional(in_place_t, const P1& p1, const P2& p2) { + InitializeAsDisengaged(); + new (void_value()) T(p1, p2); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2, typename P3> + explicit optional(in_place_t, const P1& p1, const P2& p2, const P3& p3) { + InitializeAsDisengaged(); + new (void_value()) T(p1, p2, p3); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2, typename P3, typename P4> + explicit optional(in_place_t, const P1& p1, const P2& p2, const P3& p3, + const P4& p4) { + InitializeAsDisengaged(); + new (void_value()) T(p1, p2, p3, p4); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2, typename P3, typename P4, typename P5> + explicit optional(in_place_t, const P1& p1, const P2& p2, const P3& p3, + const P4& p4, const P5& p5) { + InitializeAsDisengaged(); + new (void_value()) T(p1, p2, p3, p4, p5); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6> + explicit optional(in_place_t, const P1& p1, const P2& p2, const P3& p3, + const P4& p4, const P5& p5, const P6& p6) { + InitializeAsDisengaged(); + new (void_value()) T(p1, p2, p3, p4, p5, p6); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7> + explicit optional(in_place_t, const P1& p1, const P2& p2, const P3& p3, + const P4& p4, const P5& p5, const P6& p6, const P7& p7) { + InitializeAsDisengaged(); + new (void_value()) T(p1, p2, p3, p4, p5, p6, p7); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } +// End forwarding constructor definitions ////////////////////////////////////// + +// Begin emplace(...) definitions ////////////////////////////////////////////// + void emplace() { + EnsureDisengaged(); + new (void_value()) T(); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1> + void emplace(const P1& p1) { + EnsureDisengaged(); + new (void_value()) T(p1); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2> + void emplace(const P1& p1, const P2& p2) { + EnsureDisengaged(); + new (void_value()) T(p1, p2); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2, typename P3> + void emplace(const P1& p1, const P2& p2, const P3& p3) { + EnsureDisengaged(); + new (void_value()) T(p1, p2, p3); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2, typename P3, typename P4> + void emplace(const P1& p1, const P2& p2, const P3& p3, const P4& p4) { + EnsureDisengaged(); + new (void_value()) T(p1, p2, p3, p4); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2, typename P3, typename P4, typename P5> + void emplace(const P1& p1, const P2& p2, const P3& p3, const P4& p4, + const P5& p5) { + EnsureDisengaged(); + new (void_value()) T(p1, p2, p3, p4, p5); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6> + void emplace(const P1& p1, const P2& p2, const P3& p3, const P4& p4, + const P5& p5, const P6& p6) { + EnsureDisengaged(); + new (void_value()) T(p1, p2, p3, p4, p5, p6); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + template <typename P1, typename P2, typename P3, typename P4, typename P5, + typename P6, typename P7> + void emplace(const P1& p1, const P2& p2, const P3& p3, const P4& p4, + const P5& p5, const P6& p6, const P7& p7) { + EnsureDisengaged(); + new (void_value()) T(p1, p2, p3, p4, p5, p6, p7); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } +// End emplace(...) definitions //////////////////////////////////////////////// +// clang-format on
diff --git a/src/starboard/common/optional_internal.h.pump b/src/starboard/common/optional_internal.h.pump new file mode 100644 index 0000000..aaf152a --- /dev/null +++ b/src/starboard/common/optional_internal.h.pump
@@ -0,0 +1,74 @@ +// +// 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 is a pump file for generating the interface and implementation of +$$ optional's forwarding constructor and emplace() method. Pump is a python +$$ script that is part of the Google Test suite of utilities. Description +$$ can be found here: +$$ +$$ http://code.google.com/p/googletest/wiki/PumpManual +$$ + +$var MAX_ARITY = 7 + +$range ARITY 0..MAX_ARITY + +// clang-format off +// Begin forwarding constructor definitions //////////////////////////////////// + +$for ARITY [[ + +$range ARG 1..ARITY + +$if ARITY > 0 [[ + template <$for ARG , [[typename P$(ARG)]]> + +]] + explicit optional(in_place_t$if ARITY > 0 [[, ]] + $for ARG , [[const P$(ARG)& p$(ARG)]]) { + InitializeAsDisengaged(); + new (void_value()) T($for ARG , [[p$(ARG)]]); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + +]] +// End forwarding constructor definitions ////////////////////////////////////// + +// Begin emplace(...) definitions ////////////////////////////////////////////// + +$for ARITY [[ + +$range ARG 1..ARITY + +$if ARITY > 0 [[ + template <$for ARG , [[typename P$(ARG)]]> + +]] + void emplace($for ARG , [[const P$(ARG)& p$(ARG)]]) { + EnsureDisengaged(); + new (void_value()) T($for ARG , [[p$(ARG)]]); + engaged_ = true; +#if !defined(NDEBUG) + value_ptr_ = static_cast<const T*>(void_value()); +#endif + } + +]] +// End emplace(...) definitions //////////////////////////////////////////////// +// clang-format on \ No newline at end of file
diff --git a/src/base/state_machine_shell.cc b/src/starboard/common/state_machine.cc similarity index 64% rename from src/base/state_machine_shell.cc rename to src/starboard/common/state_machine.cc index 29a8786..a87e0c7 100644 --- a/src/base/state_machine_shell.cc +++ b/src/starboard/common/state_machine.cc
@@ -2,30 +2,30 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/state_machine_shell.h" +#include "starboard/common/state_machine.h" -#include "base/logging.h" +#include <algorithm> + +#include "starboard/log.h" // --- Macros for common logging idioms --- #define SM_STATE(s) GetStateString(s) << "(" << s << ")" #define SM_STATEN(s) GetStateString(s) << "(" << s.value_or(0) << ")" #define SM_EVENT(e) GetEventString(e) << "(" << e << ")" -#define SM_PREFIX \ - name_ << "-" << SM_STATEN(state_) << "v" << version_ << ": " -#define SM_DLOG(level) DLOG(level) << SM_PREFIX +#define SM_PREFIX name_ << "-" << SM_STATEN(state_) << "v" << version_ << ": " +#define SM_DLOG(level) SB_DLOG(level) << SM_PREFIX -namespace base { +namespace starboard { -StateMachineBaseShell::StateMachineBaseShell(const std::string &name) +StateMachineBase::StateMachineBase(const std::string& name) : name_(name), version_(0), is_handling_(false), is_initialized_(false), - should_log_(false) { -} + should_log_(false) {} -void StateMachineBaseShell::Initialize() { +void StateMachineBase::Initialize() { if (is_initialized_) { return; } @@ -33,14 +33,14 @@ if (should_log_) { SM_DLOG(INFO) << "INITIALIZING"; } - DCHECK(!state_) << SM_PREFIX; - DCHECK(!GetParentState(GetUserInitialState())) << SM_PREFIX; + SB_DCHECK(!state_) << SM_PREFIX; + SB_DCHECK(!GetParentState(GetUserInitialState())) << SM_PREFIX; is_initialized_ = true; FollowInitialSubstates(); } -bool StateMachineBaseShell::IsIn(State state) const { - StateN currentState = state_; +bool StateMachineBase::IsIn(State state) const { + optional<State> currentState = state_; while (currentState) { if (state == currentState.value()) { return true; @@ -52,12 +52,12 @@ return false; } -const char *StateMachineBaseShell::GetStateString(StateN state) const { +const char* StateMachineBase::GetStateString(optional<State> state) const { if (!state) { return "<none>"; } - const char *user = GetUserStateString(state.value()); + const char* user = GetUserStateString(state.value()); if (user) { return user; } @@ -65,12 +65,12 @@ return "UNKNOWN_STATE"; } -const char *StateMachineBaseShell::GetEventString(EventN event) const { +const char* StateMachineBase::GetEventString(optional<Event> event) const { if (!event) { return "<none>"; } - const char *user = GetUserEventString(event.value()); + const char* user = GetUserEventString(event.value()); if (user) { return user; } @@ -78,7 +78,7 @@ return "UNKNOWN_EVENT"; } -void StateMachineBaseShell::Handle(Event event, void *data) { +void StateMachineBase::Handle(Event event, void* data) { Initialize(); if (is_handling_) { @@ -86,8 +86,7 @@ SM_DLOG(INFO) << "QUEUEING " << SM_EVENT(event); } - event_queue_.push(Bind(&StateMachineBaseShell::HandleOneEvent, Unretained(this), - event, Unretained(data))); + event_queue_.push(EventWithData(event, data)); return; } @@ -95,42 +94,43 @@ HandleQueuedEvents(); } -StateMachineBaseShell::StateN -StateMachineBaseShell::GetParentState(StateN state) const { +optional<StateMachineBase::State> StateMachineBase::GetParentState( + optional<State> state) const { if (!state) { - return StateN(); + return optional<State>(); } return GetUserParentState(state.value()); } -StateMachineBaseShell::StateN -StateMachineBaseShell::GetInitialSubstate(StateN state) const { +optional<StateMachineBase::State> StateMachineBase::GetInitialSubstate( + optional<State> state) const { if (!state) { - return StateN(); + return optional<State>(); } return GetUserInitialSubstate(state.value()); } -void StateMachineBaseShell::HandleQueuedEvents() { +void StateMachineBase::HandleQueuedEvents() { while (!event_queue_.empty()) { - event_queue_.front().Run(); + EventWithData& event = event_queue_.front(); + HandleOneEvent(event.event, event.data); event_queue_.pop(); } } -void StateMachineBaseShell::HandleOneEvent(Event event, void *data) { +void StateMachineBase::HandleOneEvent(Event event, void* data) { if (should_log_) { SM_DLOG(INFO) << "HANDLING " << SM_EVENT(event); } - DCHECK(!is_handling_) << SM_PREFIX; + SB_DCHECK(!is_handling_) << SM_PREFIX; is_handling_ = true; // Walk up the hierarchy from the simplest current state, looking for event // handlers, stopping at the first state that decides to handle the event. - StateN source = state_; + optional<State> source = state_; Result result; while (source) { result = HandleUserStateEvent(source.value(), event, data); @@ -161,8 +161,8 @@ // Returns the index of |state| in |path|, or -1 if not found in |path_length| // elements. If |state| is null, then it will always return -1. -static int IndexOf(StateMachineBaseShell::StateN state, - const StateMachineBaseShell::State *path, +static int IndexOf(optional<StateMachineBase::State> state, + const StateMachineBase::State* path, size_t path_length) { if (!state) { return -1; @@ -176,19 +176,22 @@ // Finds the least common ancestor between the two state paths. If there is no // common ancestor, returns null. -static StateMachineBaseShell::StateN FindLeastCommonAncestor( - const StateMachineBaseShell::State *path_a, +static optional<StateMachineBase::State> FindLeastCommonAncestor( + const StateMachineBase::State* path_a, size_t length_a, - const StateMachineBaseShell::State *path_b, + const StateMachineBase::State* path_b, size_t length_b) { size_t max = std::min(length_a, length_b); size_t i; - for (i = 0; path_a[i] == path_b[i] && i < max; ++i) { } - return (i == 0 ? StateMachineBaseShell::StateN() : path_a[i - 1]); + for (i = 0; path_a[i] == path_b[i] && i < max; ++i) { + } + return (i == 0 ? optional<StateMachineBase::State>() : path_a[i - 1]); } -void StateMachineBaseShell::GetPath(State state, size_t max_depth, State *out_path, - size_t *out_depth) const { +void StateMachineBase::GetPath(State state, + size_t max_depth, + State* out_path, + size_t* out_depth) const { if (max_depth == 0) { SM_DLOG(FATAL) << "max_depth must be > 0"; if (out_depth) { @@ -198,7 +201,7 @@ } size_t depth = 0; - StateN currentState = state; + optional<State> currentState = state; while (currentState && depth < max_depth) { out_path[depth] = currentState.value(); ++depth; @@ -212,8 +215,10 @@ } } -void StateMachineBaseShell::Transition(Event event, State source, State target, - bool is_external) { +void StateMachineBase::Transition(Event event, + State source, + State target, + bool is_external) { if (should_log_) { SM_DLOG(INFO) << SM_EVENT(event) << " caused " << SM_STATE(source) << " -> " << SM_STATE(target) << (is_external ? " (external)" : ""); @@ -229,14 +234,13 @@ State target_path[kMaxDepth]; size_t target_depth; GetPath(target, kMaxDepth, target_path, &target_depth); - StateN least_common_ancestor = - FindLeastCommonAncestor(source_path, source_depth, target_path, - target_depth); + optional<State> least_common_ancestor = FindLeastCommonAncestor( + source_path, source_depth, target_path, target_depth); // External transitions must exit the source state and enter the target // state, so if the LCA is one of the two, we need to go one level up. - if (is_external && (least_common_ancestor == source || - least_common_ancestor == target)) { + if (is_external && + (least_common_ancestor == source || least_common_ancestor == target)) { least_common_ancestor = GetParentState(least_common_ancestor); } @@ -250,7 +254,7 @@ // Wind (enter) states down to the target state. size_t next_depth = IndexOf(state_, target_path, target_depth) + 1; - DCHECK_LE(next_depth, target_depth); + SB_DCHECK(next_depth <= target_depth); while (next_depth < target_depth) { EnterState(target_path[next_depth]); ++next_depth; @@ -259,9 +263,9 @@ FollowInitialSubstates(); } -void StateMachineBaseShell::FollowInitialSubstates() { +void StateMachineBase::FollowInitialSubstates() { while (true) { - StateN substate = + optional<State> substate = (state_ ? GetInitialSubstate(state_) : GetUserInitialState()); if (!substate) { break; @@ -270,7 +274,7 @@ } } -void StateMachineBaseShell::EnterState(State state) { +void StateMachineBase::EnterState(State state) { state_ = state; if (should_log_) { @@ -280,7 +284,7 @@ HandleUserStateEnter(state); } -void StateMachineBaseShell::ExitCurrentState() { +void StateMachineBase::ExitCurrentState() { if (should_log_) { SM_DLOG(INFO) << "EXIT"; } @@ -289,4 +293,4 @@ state_ = GetParentState(state_); } -} // namespace base +} // namespace starboard
diff --git a/src/starboard/common/state_machine.h b/src/starboard/common/state_machine.h new file mode 100644 index 0000000..017c06d --- /dev/null +++ b/src/starboard/common/state_machine.h
@@ -0,0 +1,517 @@ +// Copyright (c) 2014 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STARBOARD_COMMON_STATE_MACHINE_H_ +#define STARBOARD_COMMON_STATE_MACHINE_H_ + +#include <queue> +#include <string> + +#include "starboard/common/optional.h" +#include "starboard/configuration.h" +#include "starboard/export.h" + +#ifdef __cplusplus +namespace starboard { + +// An approximate implementation of a run-to-completion (RTC) Hierarchical State +// Machine (HSM), supporting most UML Statechart semantics. +// +// Some good background information on UML Statecharts, mostly written by Miro +// Samek: +// http://en.wikipedia.org/wiki/UML_state_machine +// +// And Miro Samek's 3-part article on practical UML Statecharts: +// http://www.embedded.com/design/prototyping-and-development/4008247/A-crash-course-in-UML-state-machines-Part-1 +// +// This class does not provide any intrinsic support for "orthogonal regions," +// "extended state," or "deferred events." "Guard conditions" are easily +// implemented by the client directly in the event handler. It also minorly +// deviates from the UML Statechart specification by calling transition handlers +// before exiting the current states. This is because this implementation uses a +// simplification which combines the transition handlers and the +// state-event-transition map into a single function (HandleUserStateEvent). +// +// This class is not thread-safe. It is the user's responsibility to synchronize +// calls into the state machine, either with locks or by simply using from a +// single thread. +// +// Terse suggestions for using this class: +// * Use the templated StateMachine wrapper class instead of this class +// directly. +// * Define two enums, one for your states, and one for your events. +// * Subclass to define your state machine and event handlers. +// * Avoid directly exposing or passing around state machines (wrap instead). +// Handle() is not a great public interface. +// * Include your state machine in another class as a private by-value member. +// * Synchronize access to the state machine. +// * Prefer writing state machine event handlers over checking if the machine +// IsIn() a particular state. +// * Convert public methods into events, get into the state machine as quickly +// as possible. +// * You only need to define a state when you are going to leave the state +// machine in a particular condition where events can occur. +// * Create a superstate when you have an event you want to handle the same +// way for a collection of states. +// * When managing resources, create a state or superstate that represents the +// acquisition of that resource, and release the resource in the Exit +// handler. +// +// Some Definitions: +// Simple State - A State with no substates. The state machine is always +// left in exactly one Simple State. +// Composite State - A State with at least one substate. +// Guard Condition - An external condition on which an event handler +// branches. +// Run-To-Completion - A property specifying that the state machine handles +// one event at a time, and no events are handled until +// the previous event is done being handled. +// +// See the unittests for this class for a contrived example state machine +// implementation. +class StateMachineBase { + public: + // --- Nested Types and Constants --- + + typedef uint32_t State; + typedef uint32_t Event; + + // --- Public Methods --- + + // Constructor with name. The name is helpful for debugging. + explicit StateMachineBase(const std::string& name); + virtual ~StateMachineBase() {} + + // Enters the initial state, as specified by |GetUserInitialState()| and + // follows the initial substates down to the first simple (childless) state + // found. Idempotent. Will happen automatically on the first |Handle()| call, + // if not done explicitly. + void Initialize(); + + // Gets the name of this state machine, for logging purposes. + const char* name() const { return name_.c_str(); } + + // Gets a version number that increases monotonically with each state + // transition (unless it overflows |uint64_t|). This can be useful for timers + // and asynchronous events that only want to do their action if the state has + // not changed since they were queued. + // + // The state version changes exactly once per transition. In other words, it + // doesn't change for every Enter and Exit for a transition. + uint64_t version() const { return version_; } + + // Gets the simplest current state that this state machine is in. To check if + // the state machine is in a particular composite state, use |IsIn()|. Returns + // null if uninitialized. + optional<State> state() const { return state_; } + + // Reports whether the state machine is currently in the given state. A state + // machine is considered to be "in" the current simple state, but also "in" + // all superstates of the current simple state. + bool IsIn(State state) const; + + // Gets a printable string for the given state. + const char* GetStateString(optional<State> state) const; + + // Gets a printable string for the given event. + const char* GetEventString(optional<Event> event) const; + + // Handles the given event in the context of the state machine's current + // state, executing the appropriate event handlers and performing any + // precipitate state transitions. If called reentrantly, the event will be + // queued until the current event has run to completion. + // + // |data| is a way to pass auxiliary data to the event handler. No retention + // or ref-counting is done on that data, it is simply passed through to the + // event handler. Since |Handle()| will queue the event if (and only if) + // called from an event handler, it is up to the caller to ensure the lifetime + // of whatever is passed in here. + void Handle(Event event, void* data = NULL); + + protected: + // --- Protected Nested Types --- + + // A type that can be returned from a state-event handler, which will be + // coerced into the appropriate Result structure. + enum HandledState { + // The event handler returns this to say that the handler consume the event, + // but caused no state transition. + kHandled, + + // The event handler returns this to say that the handler did not consume + // the event, and it should bubble up to the parent state, if any. + kNotHandled, + }; + + // Structure that handlers return, allowing them to cause state transitions or + // prevent the event from bubbling. State-event handlers may just return a + // HandledState or a state to transition to, and it will be coerced into this + // structure. + struct Result { + // Default constructor is unhandled. + Result() : is_transition(false), is_external(false), is_handled(false) {} + + // The no-transition constructor. Non-explicit so that the implementor of + // |HandleUserStateEvent()| just needs to return a |HandledState| and it + // does the right thing. + Result(HandledState handled) // NOLINT(runtime/explicit) + : is_transition(false), + is_external(false), + is_handled(handled == kHandled) {} + + // The state transition constructor. This implies that the event was + // handled. Non-explicit so that the implementor of |HandleUserStateEvent()| + // just needs to return a State and it does a non-external transition. + Result(State transition_target, + bool external = false) // NOLINT(runtime/explicit) + : target(transition_target), + is_transition(true), + is_external(external), + is_handled(true) {} + + Result& operator=(HandledState rhs) { + target = nullopt; + is_transition = false; + is_external = false; + is_handled = (rhs == kHandled); + return *this; + } + + Result& operator=(State transition_target) { + target = transition_target; + is_transition = true; + is_external = false; + is_handled = true; + return *this; + } + + // State to transition to. Only valid if is_transition is true. + optional<State> target; + + // Whether this result indicates a state transition. + bool is_transition; + + // Whether the specified transition is external. Only meaningful if + // is_transition is true. + // + // For more on state transitions, see: + // http://en.wikipedia.org/wiki/UML_state_machine#Transition_execution_sequence + bool is_external; + + // Whether the event was handled by the handler. If true, consumes the + // event, and prevents bubbling up to superstates. False propagates the + // event to superstates. + bool is_handled; + }; + + struct EventWithData { + EventWithData(Event event, void* data) : event(event), data(data) {} + Event event; + void* data; + }; + + // --- Implementation Interface for Subclasses --- + + // Abstract method for subclasses to define the state hierarchy. It is + // recommended that all user-defined states be descendents of a single "top" + // state. + virtual optional<State> GetUserParentState(State state) const = 0; + + // Abstract method for subclasses to define the initial substate of their + // states, which is required for all complex states. If a state is a simple + // state (no substates), returns null. + virtual optional<State> GetUserInitialSubstate(State state) const = 0; + + // Abstract method for subclasses to define the initial (top) state of their + // state machine. This must be a state that has no parent. This state will be + // entered upon calling |Initialize()|. + virtual State GetUserInitialState() const = 0; + + // Optional method for subclasses to define strings for their states, solely + // used for debugging purposes. + virtual const char* GetUserStateString(State state) const { return NULL; } + + // Optional method for subclasses to define strings for their events, solely + // used for debugging purposes. + virtual const char* GetUserEventString(Event event) const { return NULL; } + + // Abstract method for subclasses to define handlers for events in given + // states. This method must return either: + // a) a state to transition to, meaning the event was handled and caused + // a transition + // b) |kHandled| meaning the event was handled but no transition occurred + // c) |kNotHandled|, meaning the event should bubble up to the parent state + // d) an explicit Result structure, mainly for external transitions. + // + // Implementations wishing to catch all unhandled events may do so in their + // top state. + // + // This method is generally implemented as a nested switch statement, with the + // outer switch on |state| and the inner switch on |event|. You may want to + // break this apart into per-state or per-state-event functions for + // readability and maintainability. + virtual Result HandleUserStateEvent(State state, Event event, void* data) = 0; + + // Abstract method for subclasses to define state entry behaviors. + virtual void HandleUserStateEnter(State state) = 0; + + // Abstract method for subclasses to define state exit behaviors. + virtual void HandleUserStateExit(State state) = 0; + + // --- Helper Methods for Subclasses --- + + // Subclasses can call this method to turn on logging. Logging is opt-in, + // because it can be very verbose, and is likely only useful during + // development of a particular state machine. + void EnableLogging() { should_log_ = true; } + + private: + // --- Private Helper Methods --- + + // Gets the parent state of the given state. + optional<State> GetParentState(optional<State> state) const; + + // Gets the initial substate of given state. + optional<State> GetInitialSubstate(optional<State> state) const; + + // Handles all queued events until there are no more to run. Event handlers + // may queue more events by calling |Handle()|, and this method will also + // process all precipitate events. + void HandleQueuedEvents(); + + // Workhorse method for handling a single event. + void HandleOneEvent(Event event, void* data); + + // Gets the path from the Top state to the given |state|, storing it in the + // given |out_path| array, up to |max_depth| entries. If specified, + // |out_depth| will be set to the number of valid states that fit in the given + // array. + void GetPath(State state, + size_t max_depth, + State* out_path, + size_t* out_depth) const; + + // Transitions between the given source and target states, assuming that the + // source state is in the current state path to the Top state. The source + // state is the state whose handler generated the transition. + // + // See: + // http://en.wikipedia.org/wiki/UML_state_machine#Transition_execution_sequence + void Transition(Event event, State source, State target, bool is_external); + + // Follows the initial substates from the current state until it reaches a + // simple state. + void FollowInitialSubstates(); + + // Enters the given state. + void EnterState(State state); + + // Exits the current state to its parent. + void ExitCurrentState(); + + // --- Members --- + + // The name of this state machine, for debugging purposes. + const std::string name_; + + // The current state of this state machine. Null until initialized. + optional<State> state_; + + // The unique version of this state machine's state, updated on every + // transition. + uint64_t version_; + + // Queue of events to handle once the current event is done being + // handled. Should always be empty unless |is_handling_| is true. + std::queue<EventWithData> event_queue_; + + // Whether this state machine is actively handling an event. Used to detect + // reentrant calls to |Handle()|. + bool is_handling_; + + // Whether the state machine has been initialized into its initial state + // yet. Used to make |Initialize()| idempotent. + bool is_initialized_; + + // Whether the state machine should log information about state transitions. + bool should_log_; +}; + +// A convenience template wrapper for StateMachineBase. See the above class +// for complete documentation. Basically, you define your states and events as +// two enums, and then pass them as template args to this template class. Your +// state machine should then subclass this template class. It then does the work +// of casting and converting back and forth from your enums to +// StateMachineBase's numeric State and Event definitions. +// +// All the methods in this class, protected and public, match the description +// and behavioral contracts of the equivalently named method in +// StateMachineBase. +template <typename StateEnum, typename EventEnum> +class StateMachine { + public: + // --- Nested Types and Constants --- + + explicit StateMachine(const std::string& name) : machine_(this, name) {} + virtual ~StateMachine() {} + + void Initialize() { machine_.Initialize(); } + + const char* name() const { return machine_.name(); } + + uint64_t version() const { return machine_.version(); } + + optional<StateEnum> state() const { + optional<BaseState> wrappedState = machine_.state(); + return (wrappedState ? static_cast<StateEnum>(*wrappedState) + : optional<StateEnum>()); + } + + bool IsIn(StateEnum state) const { + return machine_.IsIn(static_cast<BaseState>(state)); + } + + const char* GetStateString(optional<StateEnum> state) const { + return machine_.GetStateString(state ? static_cast<BaseState>(*state) + : optional<BaseState>()); + } + + const char* GetEventString(optional<EventEnum> event) const { + return machine_.GetEventString(event ? static_cast<BaseEvent>(*event) + : optional<BaseEvent>()); + } + + void Handle(EventEnum event, void* data = NULL) { + machine_.Handle(static_cast<BaseEvent>(event), data); + } + + protected: + // See the other HandledState in StateMachineBase. + enum HandledState { + kHandled, + kNotHandled, + }; + + // See the other Result in StateMachineBase. + struct Result { + Result(HandledState handled) // NOLINT(runtime/explicit) + : target(), + is_transition(false), + is_external(false), + is_handled(handled == kHandled) {} + + Result(StateEnum transition_target, + bool external = false) // NOLINT(runtime/explicit) + : target(transition_target), + is_transition(true), + is_external(external), + is_handled(true) {} + + Result& operator=(HandledState rhs) { + target = nullopt; + is_transition = false; + is_external = false; + is_handled = (rhs == kHandled); + return *this; + } + + Result& operator=(StateEnum transition_target) { + target = transition_target; + is_transition = true; + is_external = false; + is_handled = true; + return *this; + } + + optional<StateEnum> target; + bool is_transition; + bool is_external; + bool is_handled; + }; + + virtual optional<StateEnum> GetUserParentState(StateEnum state) const = 0; + virtual optional<StateEnum> GetUserInitialSubstate(StateEnum state) const = 0; + virtual StateEnum GetUserInitialState() const = 0; + virtual const char* GetUserStateString(StateEnum state) const { return NULL; } + virtual const char* GetUserEventString(EventEnum event) const { return NULL; } + virtual Result HandleUserStateEvent(StateEnum state, + EventEnum event, + void* data) = 0; + virtual void HandleUserStateEnter(StateEnum state) = 0; + virtual void HandleUserStateExit(StateEnum state) = 0; + + void EnableLogging() { machine_.EnableLoggingPublic(); } + + private: + typedef StateMachineBase::State BaseState; + typedef StateMachineBase::Event BaseEvent; + + // Private contained subclass that forwards and adapts all virtual methods + // into this class's equivalent virtual methods. + class WrappedMachine : public StateMachineBase { + public: + WrappedMachine(StateMachine<StateEnum, EventEnum>* wrapper, + const std::string& name) + : StateMachineBase(name), wrapper_(wrapper) {} + + optional<State> GetUserParentState(State state) const SB_OVERRIDE { + optional<StateEnum> result = + wrapper_->GetUserParentState(static_cast<StateEnum>(state)); + return (result ? static_cast<State>(*result) : optional<State>()); + } + + optional<State> GetUserInitialSubstate(State state) const SB_OVERRIDE { + optional<StateEnum> result = + wrapper_->GetUserInitialSubstate(static_cast<StateEnum>(state)); + return (result ? static_cast<State>(*result) : optional<State>()); + } + + State GetUserInitialState() const SB_OVERRIDE { + return static_cast<State>(wrapper_->GetUserInitialState()); + } + + const char* GetUserStateString(State state) const SB_OVERRIDE { + return wrapper_->GetUserStateString(static_cast<StateEnum>(state)); + } + + const char* GetUserEventString(Event event) const SB_OVERRIDE { + return wrapper_->GetUserEventString(static_cast<EventEnum>(event)); + } + + Result HandleUserStateEvent(State state, + Event event, + void* data) SB_OVERRIDE { + typename StateMachine<StateEnum, EventEnum>::Result result = + wrapper_->HandleUserStateEvent(static_cast<StateEnum>(state), + static_cast<EventEnum>(event), data); + if (result.is_transition) { + return Result(static_cast<State>(*result.target), result.is_external); + } + + return result.is_handled ? kHandled : kNotHandled; + } + + void HandleUserStateEnter(State state) SB_OVERRIDE { + wrapper_->HandleUserStateEnter(static_cast<StateEnum>(state)); + } + + void HandleUserStateExit(State state) SB_OVERRIDE { + wrapper_->HandleUserStateExit(static_cast<StateEnum>(state)); + } + + // A public exposure of EnableLogging so the wrapper can access it. Since + // this class is private to the wrapper, it is the only one who can see it. + void EnableLoggingPublic() { EnableLogging(); } + + private: + StateMachine<StateEnum, EventEnum>* wrapper_; + }; + + WrappedMachine machine_; +}; + +} // namespace starboard +#endif // __cplusplus + +#endif // STARBOARD_COMMON_STATE_MACHINE_H_
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h index d6007c9..cb8d84a 100644 --- a/src/starboard/configuration.h +++ b/src/starboard/configuration.h
@@ -64,6 +64,15 @@ // // exposes functionality for my new feature. // #define SB_MY_EXPERIMENTAL_FEATURE_VERSION SB_EXPERIMENTAL_API_VERSION +// SbDecodeTargetInfoPlane's now can specify color plane information. +// Previously: Planes of type kSbDecodeTargetFormat2PlaneYUVNV12 +// were assumed to have the luma mapped to the alpha channel (GL_ALPHA) +// and the chroma mapped to blue and alpha (GL_LUMINANCE_ALPHA). However, +// some graphics systems require that luma is on GL_RED_EXT and the chroma +// is on GL_RG_EXT. + +#define SB_DECODE_TARGET_PLANE_FORMAT_VERSION SB_EXPERIMENTAL_API_VERSION + // --- Release Candidate Feature Defines ------------------------------------- #define SB_POINTER_INPUT_API_VERSION SB_RELEASE_CANDIDATE_API_VERSION @@ -78,6 +87,9 @@ #define SB_LOW_MEMORY_EVENT_API_VERSION SB_RELEASE_CANDIDATE_API_VERSION #define SB_PLAYER_WRITE_SAMPLE_EXTRA_CONST_API_VERSION \ SB_RELEASE_CANDIDATE_API_VERSION +#define SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION \ + SB_RELEASE_CANDIDATE_API_VERSION +#define SB_STORAGE_NAMES_API_VERSION SB_RELEASE_CANDIDATE_API_VERSION // --- Common Detected Features ---------------------------------------------- @@ -312,6 +324,32 @@ #endif // SB_NORETURN #endif // SB_API_VERSION >= 4 +// Specifies the alignment for a class, struct, union, enum, class/struct field, +// or stack variable. +#if !defined(SB_ALIGNAS) +#if SB_IS(COMPILER_GCC) +#define SB_ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#elif SB_IS(COMPILER_MSVC) +#define SB_ALIGNAS(byte_alignment) __declspec(align(byte_alignment)) +#else +// Fallback to the C++11 form. +#define SB_ALIGNAS(byte_alignment) alignas(byte_alignment) +#endif +#endif // !defined(SB_ALIGNAS) + +// Returns the alignment reqiured for any instance of the type indicated by +// |type|. +#if !defined(SB_ALIGNOF) +#if SB_IS(COMPILER_GCC) +#define SB_ALIGNOF(type) __alignof__(type) +#elif SB_IS(COMPILER_MSVC) +#define SB_ALIGNOF(type) (sizeof(type) - sizeof(type) + __alignof(type)) +#else +// Fallback to the C++11 form. +#define SB_ALIGNOF(type) alignof(type) +#endif +#endif // !defined(SB_ALIGNOF) + // --- Configuration Audits -------------------------------------------------- #if !defined(SB_API_VERSION)
diff --git a/src/starboard/decode_target.h b/src/starboard/decode_target.h index e109b6a..c437c96 100644 --- a/src/starboard/decode_target.h +++ b/src/starboard/decode_target.h
@@ -287,6 +287,16 @@ // Typically this would be GL_TEXTURE_2D, but some platforms may require // that it be set to something else like GL_TEXTURE_EXTERNAL_OES. uint32_t gl_texture_target; + +#if SB_API_VERSION >= SB_DECODE_TARGET_FORMAT_VERSION + // For kSbDecodeTargetFormat2PlaneYUVNV12 planes: the format of the + // texture. Usually, for the luma plane, this is either GL_ALPHA or + // GL_RED_EXT. For the chroma plane, this is usually GL_LUMINANCE_ALPHA + // or GL_RG_EXT. + // Ignored for other plane types. + uint32_t gl_texture_format; +#endif // SB_API_VERSION >= SB_DECODE_TARGET_NV12_R_RG_API_VERSION + #endif // SB_HAS(BLITTER) // The width of the texture/surface for this particular plane.
diff --git a/src/starboard/drm.h b/src/starboard/drm.h index dad7d24..cae076d 100644 --- a/src/starboard/drm.h +++ b/src/starboard/drm.h
@@ -52,6 +52,15 @@ int32_t encrypted_byte_count; } SbDrmSubSampleMapping; +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION +typedef struct SbDrmKeyId { + // The ID of the license (or key) required to decrypt this sample. For + // PlayReady, this is the license GUID in packed little-endian binary form. + uint8_t identifier[16]; + int identifier_size; +} SbDrmKeyId; +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + // All the optional information needed per sample for encrypted samples. typedef struct SbDrmSampleInfo { // The Initialization Vector needed to decrypt this sample. @@ -113,6 +122,20 @@ int session_id_size, bool succeeded); +// A callback for notifications that the status of one or more keys in a session +// has been changed. All keys of the session and their new status will be +// passed along. Any keys not in the list is considered as deleted. +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION +typedef void (*SbDrmSessionKeyStatusesChangedFunc)( + SbDrmSystem drm_system, + void* context, + const void* session_id, + int session_id_size, + int number_of_keys, + const SbDrmKeyId* key_ids, + const SbDrmKeyStatus* key_statuses); +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + // --- Constants ------------------------------------------------------------- // An invalid SbDrmSystem. @@ -156,12 +179,25 @@ // SbDrmGenerateSessionUpdateRequest() is called. // |session_updated_callback|: A function that is called every time after // SbDrmUpdateSession() is called. +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + +SB_EXPORT SbDrmSystem SbDrmCreateSystem( + const char* key_system, + void* context, + SbDrmSessionUpdateRequestFunc update_request_callback, + SbDrmSessionUpdatedFunc session_updated_callback, + SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback); + +#else // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + SB_EXPORT SbDrmSystem SbDrmCreateSystem(const char* key_system, void* context, SbDrmSessionUpdateRequestFunc update_request_callback, SbDrmSessionUpdatedFunc session_updated_callback); +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUS_UPDATE_SUPPORT_API_VERSION + // Asynchronously generates a session update request payload for // |initialization_data|, of |initialization_data_size|, in case sensitive // |type|, extracted from the media stream, in |drm_system|'s key system.
diff --git a/src/starboard/egl_and_gles/egl_and_gles_angle.gyp b/src/starboard/egl_and_gles/egl_and_gles_angle.gyp index 8812c25..52a9d96 100644 --- a/src/starboard/egl_and_gles/egl_and_gles_angle.gyp +++ b/src/starboard/egl_and_gles/egl_and_gles_angle.gyp
@@ -13,6 +13,9 @@ # limitations under the License. { + 'variables': { + 'enable_d3d11_feature_level_11%': 0, + }, 'targets': [ { 'target_name': 'egl_and_gles_implementation', @@ -27,6 +30,18 @@ '<(DEPTH)/third_party/angle/include', ], }, + 'conditions': [ + # ANGLE supports GLES3 on Windows only if DirectX11 feauture level 11 is + # supported. + ['target_os=="win" and enable_d3d11_feature_level_11==1', { + 'direct_dependent_settings': { + 'defines': [ + 'GLES3_SUPPORTED', + 'GL_GLEXT_PROTOTYPES', + ], + }, + }] + ] }, ], }
diff --git a/src/starboard/examples/BUILD.gn b/src/starboard/examples/BUILD.gn new file mode 100644 index 0000000..0012617 --- /dev/null +++ b/src/starboard/examples/BUILD.gn
@@ -0,0 +1,28 @@ +# Copyright 2017 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. + +import("//starboard/build/config/base.gni") + +group("examples") { + deps = [ + "//starboard/examples/blitter", + "//starboard/examples/window", + ] + + if (gl_type != "none") { + deps += [ + "//starboard/examples/glclear", + ] + } +}
diff --git a/src/starboard/examples/blitter/BUILD.gn b/src/starboard/examples/blitter/BUILD.gn new file mode 100644 index 0000000..403815f --- /dev/null +++ b/src/starboard/examples/blitter/BUILD.gn
@@ -0,0 +1,27 @@ +# Copyright 2017 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. + +final_executable("blitter") { + output_name = "starboard_blitter_example" + + sources = [ + "main.cc", + ] + + deps = [ + "//starboard", + ] +} + +# TODO: add the deploy target if it's desirable
diff --git a/src/starboard/examples/glclear/BUILD.gn b/src/starboard/examples/glclear/BUILD.gn new file mode 100644 index 0000000..d90f020 --- /dev/null +++ b/src/starboard/examples/glclear/BUILD.gn
@@ -0,0 +1,29 @@ +# Copyright 2017 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. + +final_executable("glclear") { + output_name = "starboard_glclear_example" + + sources = [ + "main.cc", + ] + + deps = [ + "//starboard", + # TODO: convert this target over + # "//starboard/egl_and_gles", + ] +} + +# TODO: add the deploy target if it's desirable
diff --git a/src/starboard/examples/window/BUILD.gn b/src/starboard/examples/window/BUILD.gn new file mode 100644 index 0000000..b8a295a --- /dev/null +++ b/src/starboard/examples/window/BUILD.gn
@@ -0,0 +1,27 @@ +# Copyright 2017 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. + +final_executable("window") { + output_name = "starboard_window_example" + + sources = [ + "main.cc", + ] + + deps = [ + "//starboard", + ] +} + +# TODO: add the deploy target if it's desirable
diff --git a/src/starboard/input.h b/src/starboard/input.h index 0959a00..9c1e2cc 100644 --- a/src/starboard/input.h +++ b/src/starboard/input.h
@@ -173,7 +173,10 @@ unsigned int key_modifiers; // The (x, y) coordinates of the persistent cursor controlled by this device. - // The value is |0| if this data is not applicable. + // The value is |0| if this data is not applicable. For events with type + // kSbInputEventTypeMove and device_type kSbInputDeviceTypeGamepad, this field + // is interpreted as a stick position with the range [-1, 1], with positive + // values for the up and left direction. SbInputVector position; // The relative motion vector of this input. The value is |0| if this data is
diff --git a/src/starboard/linux/shared/BUILD.gn b/src/starboard/linux/shared/BUILD.gn new file mode 100644 index 0000000..66579d8 --- /dev/null +++ b/src/starboard/linux/shared/BUILD.gn
@@ -0,0 +1,608 @@ +# Copyright 2017 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. + +import("//starboard/build/config/base.gni") +import("//starboard/build/config/fastbuild.gni") +import("//starboard/build/config/sanitizers.gni") +import("//starboard/build/toolchain/asan_symbolizer_path.gni") +import("//starboard/build/delegated_config.gni") +import("//starboard/linux/shared/clang.gni") +import("//starboard/linux/shared/dlmalloc.gni") + +# ============================================================================= +# DEFAULT COMPILER CONFIGS +# ============================================================================= + +config("compiler_defaults") { + cflags = [ + # We'll pretend not to be Linux, but Starboard instead. + "-U__linux__", + ] + + cflags_c = [ + # Limit to C99. This allows Linux to be a canary build for any + # C11 features that are not supported on some platforms' compilers. + "-std=c99", + ] + + cflags_cc = [ + "-std=gnu++11", + ] + + libs = [ + "asound", + "avcodec", + "avformat", + "avresample", + "avutil", + "pthread", + "rt", + ] + + ldflags = [] + + if (use_dlmalloc_allocator && !use_asan) { + ldflags += [ + "-Wl,--wrap=malloc", + "-Wl,--wrap=calloc", + "-Wl,--wrap=realloc", + "-Wl,--wrap=memalign", + "-Wl,--wrap=reallocalign", + "-Wl,--wrap=free", + "-Wl,--wrap=strdup", + "-Wl,--wrap=malloc_usable_size", + "-Wl,--wrap=malloc_stats_fast", + "-Wl,--wrap=__cxa_demangle", + ] + } + + defines = [ + # Cobalt on Linux flag + "COBALT_LINUX", + "__STDC_FORMAT_MACROS", # so that we get PRI* + # Enable GNU extensions to get prototypes like ffsl. + "_GNU_SOURCE=1", + + # By default, <EGL/eglplatform.h> pulls in some X11 headers that have some + # nasty macros (|Status|, for example) that conflict with Chromium base. + "MESA_EGL_NO_X11_HEADERS", + ] + + if (use_clang) { + cflags += [ + "-Werror", + "-fcolor-diagnostics", + # Default visibility to hidden, to enable dead stripping. + "-fvisibility=hidden", + # Warn for implicit type conversions that may change a value. + "-Wconversion", + "-Wno-c++11-compat", + # This complains about "override", which we use heavily. + "-Wno-c++11-extensions", + # Warns on switches on enums that cover all enum values but + # also contain a default: branch. Chrome is full of that. + "-Wno-covered-switch-default", + # protobuf uses hash_map. + "-Wno-deprecated", + "-fno-exceptions", + # Don't warn about the "struct foo f = {0};" initialization pattern. + "-Wno-missing-field-initializers", + # Do not warn for implicit sign conversions. + "-Wno-sign-conversion", + "-fno-strict-aliasing", # See http://crbug.com/32204 + "-Wno-unnamed-type-template-args", + # Triggered by the COMPILE_ASSERT macro. + "-Wno-unused-local-typedef", + # Do not warn if a function or variable cannot be implicitly + # instantiated. + "-Wno-undefined-var-template", + # Do not warn about an implicit exception spec mismatch. + "-Wno-implicit-exception-spec-mismatch", + ] + + ldflags += [ "-fuse-ld=lld" ] + + if (use_asan) { + cflags += [ + "-fsanitize=address", + "-fno-omit-frame-pointer", + ] + + ldflags += [ + "-fsanitize=address", + # Force linking of the helpers in sanitizer_options.cc + "-Wl,-u_sanitizer_options_link_helper", + ] + + defines += [ + "ADDRESS_SANITIZER", + ] + + if (asan_symbolizer_path != "") { + defines += [ + "ASAN_SYMBOLIZER_PATH=\"$asan_symbolizer_path\"", + ] + } + } + + if (use_tsan) { + cflags += [ + "-fsanitize=thread", + "-fno-omit-frame-pointer", + ] + + ldflags += [ + "-fsanitize-thread", + ] + + defines += [ + "THREAD_SANITIZER", + ] + } + } +} + +config("compiler_defaults_debug") { + cflags = [] + if (!cobalt_use_fastbuild) { + cflags += [ "-g" ] + } +} + +config("compiler_defaults_devel") { + cflags = [] + if (!cobalt_use_fastbuild) { + cflags += [ "-g" ] + } +} + +config("compiler_defaults_qa") { + cflags = [ + "-gline-tables-only", + ] +} + +config("compiler_defaults_gold") { + cflags = [ + "-gline-tables-only", + ] +} + +config("compiler_defaults_host") { + cflags = [ + "-O2", + ] +} + +# ============================================================================== +# DELEGATED CONFIGS +# ============================================================================== + +config("pedantic_warnings") { + cflags = [ + "-Wall", + "-Wextra", + "-Wunreachable-code", + ] +} + +config("no_pedantic_warnings") { + cflags = [ + # "this" pointer cannot be NULL...pointer may be assumed + # to always convert to true. + "-Wno-undefined-bool-conversion", + # Skia doesn't use overrides. + "-Wno-inconsistent-missing-override", + # Do not warn about unused function params. + "-Wno-unused-parameter", + # Do not warn for implicit type conversions that may change a value. + "-Wno-conversion", + # shifting a negative signed value is undefined + "-Wno-shift-negative-value", + # Width of bit-field exceeds width of its type- value will be truncated + "-Wno-bitfield-width", + "-Wno-undefined-var-template", + ] +} + + +delegated_config("optimizations") { + path = "//starboard/build/toolchain/linux/config" + prefixes = [ "no", "debuggable", "full" ] + generate_default = false +} + +config("default_optimizations") { + if (cobalt_config == "debug") { + configs = [ ":no_optimizations" ] + } else { + configs = [ ":debuggable_optimizations" ] + } +} + + +delegated_config("rtti") { + path = "//starboard/build/toolchain/linux/config" + generate_default = false +} + +config("default_rtti") { + if (cobalt_config == "debug" || cobalt_config == "devel") { + configs = [ ":rtti" ] + } else { + configs = [ ":no_rtti" ] + } +} + + +config("wexit_time_destructors") { + if (use_clang) { + configs = + [ "//starboard/build/toolchain/linux/config:wexit_time_destructors" ] + } +} + +# ============================================================================= +# starboard_platform TARGET +# ============================================================================= + +source_set("starboard_platform") { + visibility = [ "//starboard/linux/*" ] + + sources = [ + "//starboard/linux/shared/atomic_public.h", + "//starboard/linux/shared/configuration_public.h", + "//starboard/linux/shared/decode_target_get_info.cc", + "//starboard/linux/shared/decode_target_internal.cc", + "//starboard/linux/shared/decode_target_internal.h", + "//starboard/linux/shared/decode_target_release.cc", + "//starboard/linux/shared/media_is_video_supported.cc", + "//starboard/linux/shared/player_components_impl.cc", + "//starboard/linux/shared/system_get_connection_type.cc", + "//starboard/linux/shared/system_get_device_type.cc", + "//starboard/linux/shared/system_get_path.cc", + "//starboard/linux/shared/system_has_capability.cc", + "//starboard/shared/alsa/alsa_audio_sink_type.cc", + "//starboard/shared/alsa/alsa_audio_sink_type.h", + "//starboard/shared/alsa/alsa_util.cc", + "//starboard/shared/alsa/alsa_util.h", + "//starboard/shared/alsa/audio_sink_get_max_channels.cc", + "//starboard/shared/alsa/audio_sink_get_nearest_supported_sample_frequency.cc", + "//starboard/shared/alsa/audio_sink_is_audio_frame_storage_type_supported.cc", + "//starboard/shared/alsa/audio_sink_is_audio_sample_type_supported.cc", + "//starboard/shared/dlmalloc/memory_map.cc", + "//starboard/shared/dlmalloc/memory_unmap.cc", + "//starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc", + "//starboard/shared/ffmpeg/ffmpeg_audio_decoder.h", + "//starboard/shared/ffmpeg/ffmpeg_audio_resampler.cc", + "//starboard/shared/ffmpeg/ffmpeg_audio_resampler.h", + "//starboard/shared/ffmpeg/ffmpeg_common.cc", + "//starboard/shared/ffmpeg/ffmpeg_common.h", + "//starboard/shared/ffmpeg/ffmpeg_video_decoder.cc", + "//starboard/shared/ffmpeg/ffmpeg_video_decoder.h", + "//starboard/shared/gcc/atomic_gcc_public.h", + "//starboard/shared/iso/character_is_alphanumeric.cc", + "//starboard/shared/iso/character_is_digit.cc", + "//starboard/shared/iso/character_is_hex_digit.cc", + "//starboard/shared/iso/character_is_space.cc", + "//starboard/shared/iso/character_is_upper.cc", + "//starboard/shared/iso/character_to_lower.cc", + "//starboard/shared/iso/character_to_upper.cc", + "//starboard/shared/iso/directory_close.cc", + "//starboard/shared/iso/directory_get_next.cc", + "//starboard/shared/iso/directory_open.cc", + "//starboard/shared/iso/double_absolute.cc", + "//starboard/shared/iso/double_exponent.cc", + "//starboard/shared/iso/double_floor.cc", + "//starboard/shared/iso/double_is_finite.cc", + "//starboard/shared/iso/double_is_nan.cc", + "//starboard/shared/iso/memory_compare.cc", + "//starboard/shared/iso/memory_copy.cc", + "//starboard/shared/iso/memory_find_byte.cc", + "//starboard/shared/iso/memory_move.cc", + "//starboard/shared/iso/memory_set.cc", + "//starboard/shared/iso/string_compare.cc", + "//starboard/shared/iso/string_compare_all.cc", + "//starboard/shared/iso/string_find_character.cc", + "//starboard/shared/iso/string_find_last_character.cc", + "//starboard/shared/iso/string_find_string.cc", + "//starboard/shared/iso/string_get_length.cc", + "//starboard/shared/iso/string_get_length_wide.cc", + "//starboard/shared/iso/string_parse_double.cc", + "//starboard/shared/iso/string_parse_signed_integer.cc", + "//starboard/shared/iso/string_parse_uint64.cc", + "//starboard/shared/iso/string_parse_unsigned_integer.cc", + "//starboard/shared/iso/string_scan.cc", + "//starboard/shared/iso/system_binary_search.cc", + "//starboard/shared/iso/system_sort.cc", + "//starboard/shared/libevent/socket_waiter_add.cc", + "//starboard/shared/libevent/socket_waiter_create.cc", + "//starboard/shared/libevent/socket_waiter_destroy.cc", + "//starboard/shared/libevent/socket_waiter_internal.cc", + "//starboard/shared/libevent/socket_waiter_remove.cc", + "//starboard/shared/libevent/socket_waiter_wait.cc", + "//starboard/shared/libevent/socket_waiter_wait_timed.cc", + "//starboard/shared/libevent/socket_waiter_wake_up.cc", + "//starboard/shared/libvpx/vpx_video_decoder.cc", + "//starboard/shared/libvpx/vpx_video_decoder.h", + "//starboard/shared/linux/byte_swap.cc", + "//starboard/shared/linux/get_home_directory.cc", + "//starboard/shared/linux/memory_get_stack_bounds.cc", + "//starboard/shared/linux/page_internal.cc", + "//starboard/shared/linux/socket_get_interface_address.cc", + "//starboard/shared/linux/socket_get_local_interface_address.cc", + "//starboard/shared/linux/system_get_random_data.cc", + "//starboard/shared/linux/system_get_stack.cc", + "//starboard/shared/linux/system_get_total_cpu_memory.cc", + "//starboard/shared/linux/system_is_debugger_attached.cc", + "//starboard/shared/linux/system_symbolize.cc", + "//starboard/shared/linux/thread_get_id.cc", + "//starboard/shared/linux/thread_get_name.cc", + "//starboard/shared/linux/thread_set_name.cc", + "//starboard/shared/nouser/user_get_current.cc", + "//starboard/shared/nouser/user_get_property.cc", + "//starboard/shared/nouser/user_get_signed_in.cc", + "//starboard/shared/nouser/user_internal.cc", + "//starboard/shared/posix/directory_create.cc", + "//starboard/shared/posix/file_can_open.cc", + "//starboard/shared/posix/file_close.cc", + "//starboard/shared/posix/file_delete.cc", + "//starboard/shared/posix/file_exists.cc", + "//starboard/shared/posix/file_flush.cc", + "//starboard/shared/posix/file_get_info.cc", + "//starboard/shared/posix/file_get_path_info.cc", + "//starboard/shared/posix/file_open.cc", + "//starboard/shared/posix/file_read.cc", + "//starboard/shared/posix/file_seek.cc", + "//starboard/shared/posix/file_truncate.cc", + "//starboard/shared/posix/file_write.cc", + "//starboard/shared/posix/log.cc", + "//starboard/shared/posix/log_flush.cc", + "//starboard/shared/posix/log_format.cc", + "//starboard/shared/posix/log_is_tty.cc", + "//starboard/shared/posix/log_raw.cc", + "//starboard/shared/posix/memory_flush.cc", + "//starboard/shared/posix/set_non_blocking_internal.cc", + "//starboard/shared/posix/socket_accept.cc", + "//starboard/shared/posix/socket_bind.cc", + "//starboard/shared/posix/socket_clear_last_error.cc", + "//starboard/shared/posix/socket_connect.cc", + "//starboard/shared/posix/socket_create.cc", + "//starboard/shared/posix/socket_destroy.cc", + "//starboard/shared/posix/socket_free_resolution.cc", + "//starboard/shared/posix/socket_get_last_error.cc", + "//starboard/shared/posix/socket_get_local_address.cc", + "//starboard/shared/posix/socket_internal.cc", + "//starboard/shared/posix/socket_is_connected.cc", + "//starboard/shared/posix/socket_is_connected_and_idle.cc", + "//starboard/shared/posix/socket_join_multicast_group.cc", + "//starboard/shared/posix/socket_listen.cc", + "//starboard/shared/posix/socket_receive_from.cc", + "//starboard/shared/posix/socket_resolve.cc", + "//starboard/shared/posix/socket_send_to.cc", + "//starboard/shared/posix/socket_set_broadcast.cc", + "//starboard/shared/posix/socket_set_receive_buffer_size.cc", + "//starboard/shared/posix/socket_set_reuse_address.cc", + "//starboard/shared/posix/socket_set_send_buffer_size.cc", + "//starboard/shared/posix/socket_set_tcp_keep_alive.cc", + "//starboard/shared/posix/socket_set_tcp_no_delay.cc", + "//starboard/shared/posix/socket_set_tcp_window_scaling.cc", + "//starboard/shared/posix/string_compare_no_case.cc", + "//starboard/shared/posix/string_compare_no_case_n.cc", + "//starboard/shared/posix/string_compare_wide.cc", + "//starboard/shared/posix/string_format.cc", + "//starboard/shared/posix/string_format_wide.cc", + "//starboard/shared/posix/system_break_into_debugger.cc", + "//starboard/shared/posix/system_clear_last_error.cc", + "//starboard/shared/posix/system_get_error_string.cc", + "//starboard/shared/posix/system_get_last_error.cc", + "//starboard/shared/posix/system_get_locale_id.cc", + "//starboard/shared/posix/system_get_number_of_processors.cc", + "//starboard/shared/posix/thread_sleep.cc", + "//starboard/shared/posix/time_get_monotonic_now.cc", + "//starboard/shared/posix/time_get_monotonic_thread_now.cc", + "//starboard/shared/posix/time_get_now.cc", + "//starboard/shared/posix/time_zone_get_current.cc", + "//starboard/shared/posix/time_zone_get_dst_name.cc", + "//starboard/shared/posix/time_zone_get_name.cc", + "//starboard/shared/pthread/condition_variable_broadcast.cc", + "//starboard/shared/pthread/condition_variable_create.cc", + "//starboard/shared/pthread/condition_variable_destroy.cc", + "//starboard/shared/pthread/condition_variable_signal.cc", + "//starboard/shared/pthread/condition_variable_wait.cc", + "//starboard/shared/pthread/condition_variable_wait_timed.cc", + "//starboard/shared/pthread/mutex_acquire.cc", + "//starboard/shared/pthread/mutex_acquire_try.cc", + "//starboard/shared/pthread/mutex_create.cc", + "//starboard/shared/pthread/mutex_destroy.cc", + "//starboard/shared/pthread/mutex_release.cc", + "//starboard/shared/pthread/once.cc", + "//starboard/shared/pthread/thread_create.cc", + "//starboard/shared/pthread/thread_create_local_key.cc", + "//starboard/shared/pthread/thread_create_priority.h", + "//starboard/shared/pthread/thread_destroy_local_key.cc", + "//starboard/shared/pthread/thread_detach.cc", + "//starboard/shared/pthread/thread_get_current.cc", + "//starboard/shared/pthread/thread_get_local_value.cc", + "//starboard/shared/pthread/thread_is_equal.cc", + "//starboard/shared/pthread/thread_join.cc", + "//starboard/shared/pthread/thread_set_local_value.cc", + "//starboard/shared/pthread/thread_yield.cc", + "//starboard/shared/signal/crash_signals.h", + "//starboard/shared/signal/crash_signals_sigaction.cc", + "//starboard/shared/signal/suspend_signals.cc", + "//starboard/shared/signal/suspend_signals.h", + "//starboard/shared/starboard/application.cc", + "//starboard/shared/starboard/audio_sink/audio_sink_create.cc", + "//starboard/shared/starboard/audio_sink/audio_sink_destroy.cc", + "//starboard/shared/starboard/audio_sink/audio_sink_internal.cc", + "//starboard/shared/starboard/audio_sink/audio_sink_internal.h", + "//starboard/shared/starboard/audio_sink/audio_sink_is_valid.cc", + "//starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc", + "//starboard/shared/starboard/audio_sink/stub_audio_sink_type.h", + "//starboard/shared/starboard/command_line.cc", + "//starboard/shared/starboard/command_line.h", + "//starboard/shared/starboard/directory_can_open.cc", + "//starboard/shared/starboard/event_cancel.cc", + "//starboard/shared/starboard/event_schedule.cc", + "//starboard/shared/starboard/file_mode_string_to_flags.cc", + "//starboard/shared/starboard/file_storage/storage_close_record.cc", + "//starboard/shared/starboard/file_storage/storage_delete_record.cc", + "//starboard/shared/starboard/file_storage/storage_get_record_size.cc", + "//starboard/shared/starboard/file_storage/storage_open_record.cc", + "//starboard/shared/starboard/file_storage/storage_read_record.cc", + "//starboard/shared/starboard/file_storage/storage_write_record.cc", + "//starboard/shared/starboard/log_message.cc", + "//starboard/shared/starboard/log_raw_dump_stack.cc", + "//starboard/shared/starboard/log_raw_format.cc", + "//starboard/shared/starboard/media/codec_util.cc", + "//starboard/shared/starboard/media/codec_util.h", + "//starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc", + "//starboard/shared/starboard/media/media_get_audio_configuration_stereo_only.cc", + "//starboard/shared/starboard/media/media_get_audio_output_count_stereo_only.cc", + "//starboard/shared/starboard/media/media_is_audio_supported_aac_and_opus.cc", + "//starboard/shared/starboard/media/media_is_output_protected.cc", + "//starboard/shared/starboard/media/media_set_output_protection.cc", + "//starboard/shared/starboard/media/media_util.cc", + "//starboard/shared/starboard/media/media_util.h", + "//starboard/shared/starboard/media/mime_type.cc", + "//starboard/shared/starboard/media/mime_type.h", + "//starboard/shared/starboard/new.cc", + "//starboard/shared/starboard/player/decoded_audio_internal.cc", + "//starboard/shared/starboard/player/decoded_audio_internal.h", + "//starboard/shared/starboard/player/filter/audio_decoder_internal.h", + "//starboard/shared/starboard/player/filter/audio_frame_tracker.h", + "//starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc", + "//starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h", + "//starboard/shared/starboard/player/filter/audio_renderer_internal.h", + "//starboard/shared/starboard/player/filter/audio_time_stretcher.cc", + "//starboard/shared/starboard/player/filter/audio_time_stretcher.h", + "//starboard/shared/starboard/player/filter/decoded_audio_queue.cc", + "//starboard/shared/starboard/player/filter/decoded_audio_queue.h", + "//starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc", + "//starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h", + "//starboard/shared/starboard/player/filter/player_components.h", + "//starboard/shared/starboard/player/filter/video_decoder_internal.h", + "//starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc", + "//starboard/shared/starboard/player/filter/video_renderer_impl_internal.h", + "//starboard/shared/starboard/player/filter/video_renderer_internal.h", + "//starboard/shared/starboard/player/filter/wsola_internal.cc", + "//starboard/shared/starboard/player/filter/wsola_internal.h", + "//starboard/shared/starboard/player/input_buffer_internal.cc", + "//starboard/shared/starboard/player/input_buffer_internal.h", + "//starboard/shared/starboard/player/job_queue.cc", + "//starboard/shared/starboard/player/job_queue.h", + "//starboard/shared/starboard/player/player_create.cc", + "//starboard/shared/starboard/player/player_destroy.cc", + "//starboard/shared/starboard/player/player_get_current_frame.cc", + "//starboard/shared/starboard/player/player_get_info.cc", + "//starboard/shared/starboard/player/player_internal.cc", + "//starboard/shared/starboard/player/player_internal.h", + "//starboard/shared/starboard/player/player_output_mode_supported.cc", + "//starboard/shared/starboard/player/player_seek.cc", + "//starboard/shared/starboard/player/player_set_bounds.cc", + "//starboard/shared/starboard/player/player_set_pause.cc", + "//starboard/shared/starboard/player/player_set_playback_rate.cc", + "//starboard/shared/starboard/player/player_set_volume.cc", + "//starboard/shared/starboard/player/player_worker.cc", + "//starboard/shared/starboard/player/player_worker.h", + "//starboard/shared/starboard/player/player_write_end_of_stream.cc", + "//starboard/shared/starboard/player/player_write_sample.cc", + "//starboard/shared/starboard/player/video_frame_internal.cc", + "//starboard/shared/starboard/player/video_frame_internal.h", + "//starboard/shared/starboard/queue_application.cc", + "//starboard/shared/starboard/string_concat.cc", + "//starboard/shared/starboard/string_concat_wide.cc", + "//starboard/shared/starboard/string_copy.cc", + "//starboard/shared/starboard/string_copy_wide.cc", + "//starboard/shared/starboard/string_duplicate.cc", + "//starboard/shared/starboard/system_get_random_uint64.cc", + "//starboard/shared/starboard/system_request_pause.cc", + "//starboard/shared/starboard/system_request_stop.cc", + "//starboard/shared/starboard/system_request_suspend.cc", + "//starboard/shared/starboard/system_request_unpause.cc", + "//starboard/shared/starboard/window_set_default_options.cc", + "//starboard/shared/stub/accessibility_get_display_settings.cc", + "//starboard/shared/stub/accessibility_get_text_to_speech_settings.cc", + "//starboard/shared/stub/cryptography_create_transformer.cc", + "//starboard/shared/stub/cryptography_destroy_transformer.cc", + "//starboard/shared/stub/cryptography_get_tag.cc", + "//starboard/shared/stub/cryptography_set_authenticated_data.cc", + "//starboard/shared/stub/cryptography_set_initialization_vector.cc", + "//starboard/shared/stub/cryptography_transform.cc", + "//starboard/shared/stub/drm_close_session.cc", + "//starboard/shared/stub/drm_create_system.cc", + "//starboard/shared/stub/drm_destroy_system.cc", + "//starboard/shared/stub/drm_generate_session_update_request.cc", + "//starboard/shared/stub/drm_system_internal.h", + "//starboard/shared/stub/drm_update_session.cc", + "//starboard/shared/stub/image_decode.cc", + "//starboard/shared/stub/image_is_decode_supported.cc", + "//starboard/shared/stub/media_is_supported.cc", + "//starboard/shared/stub/media_is_transfer_characteristics_supported.cc", + "//starboard/shared/stub/microphone_close.cc", + "//starboard/shared/stub/microphone_create.cc", + "//starboard/shared/stub/microphone_destroy.cc", + "//starboard/shared/stub/microphone_get_available.cc", + "//starboard/shared/stub/microphone_is_sample_rate_supported.cc", + "//starboard/shared/stub/microphone_open.cc", + "//starboard/shared/stub/microphone_read.cc", + "//starboard/shared/stub/system_clear_platform_error.cc", + "//starboard/shared/stub/system_get_total_gpu_memory.cc", + "//starboard/shared/stub/system_get_used_gpu_memory.cc", + "//starboard/shared/stub/system_hide_splash_screen.cc", + "//starboard/shared/stub/system_raise_platform_error.cc", + ] + + if (use_dlmalloc_allocator) { + sources += [ + "//starboard/shared/dlmalloc/memory_allocate_aligned_unchecked.cc", + "//starboard/shared/dlmalloc/memory_allocate_unchecked.cc", + "//starboard/shared/dlmalloc/memory_free.cc", + "//starboard/shared/dlmalloc/memory_free_aligned.cc", + "//starboard/shared/dlmalloc/memory_reallocate_unchecked.cc", + "//starboard/shared/dlmalloc/system_get_used_cpu_memory.cc", + ] + } else { + sources += [ + "//starboard/shared/iso/memory_allocate_unchecked.cc", + "//starboard/shared/iso/memory_free.cc", + "//starboard/shared/iso/memory_reallocate_unchecked.cc", + "//starboard/shared/linux/system_get_used_cpu_memory.cc", + "//starboard/shared/posix/memory_allocate_aligned_unchecked.cc", + "//starboard/shared/posix/memory_free_aligned.cc", + ] + } + + defines = [ + # This must be defined when building Starboard, and must not when + # building Starboard client code. + "STARBOARD_IMPLEMENTATION", + ] + + deps = [ + "//starboard/common", + ":starboard_base_symbolize", + "//third_party/dlmalloc", + "//third_party/libevent", + "//third_party/libvpx", + ] +} + +source_set("starboard_base_symbolize") { + sources = [ + "//base/third_party/symbolize/demangle.cc", + "//base/third_party/symbolize/symbolize.cc", + ] +}
diff --git a/src/starboard/linux/shared/buildconfig.gni b/src/starboard/linux/shared/buildconfig.gni new file mode 100644 index 0000000..9cbc874 --- /dev/null +++ b/src/starboard/linux/shared/buildconfig.gni
@@ -0,0 +1,43 @@ +# Copyright 2017 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. + +import("//starboard/linux/shared/clang.gni") + +############################################################################### +# This file is imported into BUILDCONFIG.gn. As a side effect, any variable +# defined here becomes a global variable in all GN files. +# +# Adding new variables to this file could result in variable name conflicts, so +# keep the number of variables in this file to a minimum! +# +# If you need to define a temporary variable, prefix it with an underscore like +# _this. Prefixing a variable with an underscore makes it a private variable +# that won't bleed into other files. +############################################################################### + +# Target OS and CPU. +# BUILDCONFIG.gn sets target_os and target_cpu to the values of these two +# variables below. Unfortunately, due to GN's restrictions on how variables can +# be changed, we can't directly set target_os and target_cpu here. +target_os_ = "linux" +target_cpu_ = "x64" + +# The target and host toolchain +if (use_clang) { + target_toolchain = "//starboard/build/toolchain/linux:clang_x64" + host_toolchain = "//starboard/build/toolchain/linux:clang_$host_cpu" +} else { + target_toolchain = "//starboard/build/toolchain/linux:x64" + host_toolchain = "//starboard/build/toolchain/linux:$host_cpu" +}
diff --git a/src/starboard/linux/shared/clang.gni b/src/starboard/linux/shared/clang.gni new file mode 100644 index 0000000..a9aa3f4 --- /dev/null +++ b/src/starboard/linux/shared/clang.gni
@@ -0,0 +1,18 @@ +# Copyright 2017 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. + +declare_args() { + # Whether to use Clang. + use_clang = true +}
diff --git a/src/starboard/linux/shared/configuration.gni b/src/starboard/linux/shared/configuration.gni new file mode 100644 index 0000000..99cb78e --- /dev/null +++ b/src/starboard/linux/shared/configuration.gni
@@ -0,0 +1,46 @@ +# Copyright 2017 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. + +# Set to true to build with DIAL support. +enable_in_app_dial = true + +# The source of EGL and GLES headers and libraries. +# Valid values (case and everything sensitive!): +# "none" - No EGL + GLES implementation is available on this platform. +# "system_gles3" - Use the system implementation of EGL + GLES3. The +# headers and libraries must be on the system include and +# link paths. +# "system_gles2" - Use the system implementation of EGL + GLES2. The +# headers and libraries must be on the system include and +# link paths. +# "glimp" - Cobalt's own EGL + GLES2 implementation. This requires a +# valid Glimp implementation for the platform. +# "angle" - A DirectX-to-OpenGL adaptation layer. This requires a valid +# ANGLE implementation for the platform. +# Choosing an unsupported value will result in a GYP error: +# "cobalt/renderer/egl_and_gles/egl_and_gles_<gl_type>.gyp not found" +gl_type = "system_gles3" + +# Use media source extension implementation that is conformed to the +# Candidate Recommandation of July 5th 2016. +cobalt_use_media_source_2016 = true + +# Use ASAN by default when building with Clang. +use_asan_by_default = true + +declare_args() { + # Set to true to enable distributed compilation using Goma. By default we + # use Goma for stub and linux. + use_goma = true +}
diff --git a/src/starboard/linux/shared/dlmalloc.gni b/src/starboard/linux/shared/dlmalloc.gni new file mode 100644 index 0000000..73c1137 --- /dev/null +++ b/src/starboard/linux/shared/dlmalloc.gni
@@ -0,0 +1,19 @@ +# Copyright 2017 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. + +declare_args() { + # Whether to use the dlmalloc allocator instead of the system allocator + use_dlmalloc_allocator = false +} +
diff --git a/src/starboard/linux/shared/launcher.py b/src/starboard/linux/shared/launcher.py index 73e708a..3b476d1 100644 --- a/src/starboard/linux/shared/launcher.py +++ b/src/starboard/linux/shared/launcher.py
@@ -1,4 +1,3 @@ -#!/usr/bin/python # # Copyright 2017 Google Inc. All Rights Reserved. # @@ -15,17 +14,25 @@ # limitations under the License. """Linux implementation of Starboard launcher abstraction.""" -import imp +import importlib import os +import sys + +if "environment" in sys.modules: + environment = sys.modules["environment"] +else: + env_path = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, + os.pardir, "tools")) + if env_path not in sys.path: + sys.path.append(env_path) + environment = importlib.import_module("environment") + + import signal import socket import subprocess -module_path = os.path.abspath( - os.path.join(os.path.dirname(__file__), - os.pardir, os.pardir, "tools", "abstract_launcher.py")) - -abstract_launcher = imp.load_source("abstract_launcher", module_path) +import starboard.tools.abstract_launcher as abstract_launcher class Launcher(abstract_launcher.AbstractLauncher): @@ -57,6 +64,7 @@ proc = subprocess.Popen([self.executable] + self.target_command_line_params) self.pid = proc.pid proc.wait() + return proc.returncode def Kill(self): print "\n***Killing Launcher***\n"
diff --git a/src/starboard/linux/shared/starboard_platform.gypi b/src/starboard/linux/shared/starboard_platform.gypi index f896d17..311618c 100644 --- a/src/starboard/linux/shared/starboard_platform.gypi +++ b/src/starboard/linux/shared/starboard_platform.gypi
@@ -90,6 +90,8 @@ '<(DEPTH)/starboard/shared/libvpx/vpx_video_decoder.cc', '<(DEPTH)/starboard/shared/libvpx/vpx_video_decoder.h', '<(DEPTH)/starboard/shared/linux/byte_swap.cc', + '<(DEPTH)/starboard/shared/linux/dev_input/dev_input.cc', + '<(DEPTH)/starboard/shared/linux/dev_input/dev_input.h', '<(DEPTH)/starboard/shared/linux/get_home_directory.cc', '<(DEPTH)/starboard/shared/linux/memory_get_stack_bounds.cc', '<(DEPTH)/starboard/shared/linux/page_internal.cc', @@ -98,7 +100,6 @@ '<(DEPTH)/starboard/shared/linux/system_get_random_data.cc', '<(DEPTH)/starboard/shared/linux/system_get_stack.cc', '<(DEPTH)/starboard/shared/linux/system_get_total_cpu_memory.cc', - '<(DEPTH)/starboard/shared/linux/system_get_used_cpu_memory.cc', '<(DEPTH)/starboard/shared/linux/system_is_debugger_attached.cc', '<(DEPTH)/starboard/shared/linux/system_symbolize.cc', '<(DEPTH)/starboard/shared/linux/thread_get_id.cc', @@ -326,12 +327,14 @@ '<(DEPTH)/starboard/shared/dlmalloc/memory_free.cc', '<(DEPTH)/starboard/shared/dlmalloc/memory_free_aligned.cc', '<(DEPTH)/starboard/shared/dlmalloc/memory_reallocate_unchecked.cc', + '<(DEPTH)/starboard/shared/dlmalloc/system_get_used_cpu_memory.cc', ], }, { 'starboard_platform_sources': [ '<(DEPTH)/starboard/shared/iso/memory_allocate_unchecked.cc', '<(DEPTH)/starboard/shared/iso/memory_free.cc', '<(DEPTH)/starboard/shared/iso/memory_reallocate_unchecked.cc', + '<(DEPTH)/starboard/shared/linux/system_get_used_cpu_memory.cc', '<(DEPTH)/starboard/shared/posix/memory_allocate_aligned_unchecked.cc', '<(DEPTH)/starboard/shared/posix/memory_free_aligned.cc', ],
diff --git a/src/starboard/linux/shared/system_get_path.cc b/src/starboard/linux/shared/system_get_path.cc index 4ae443b..315903be 100644 --- a/src/starboard/linux/shared/system_get_path.cc +++ b/src/starboard/linux/shared/system_get_path.cc
@@ -36,14 +36,12 @@ home_path, kMaxPathSize)) { return false; } - int result = - SbStringFormatF(out_path, path_size, "%s/.cache/cobalt", home_path); + int result = SbStringFormatF(out_path, path_size, "%s/.cache", home_path); if (result < 0 || result >= path_size) { out_path[0] = '\0'; return false; } - - return true; + return SbDirectoryCreate(out_path); } // Places up to |path_size| - 1 characters of the path to the current @@ -144,7 +142,12 @@ if (!GetCacheDirectory(path, kPathSize)) { return false; } - SbDirectoryCreate(path); + if (SbStringConcat(path, "/cobalt", kPathSize) >= kPathSize) { + return false; + } + if (!SbDirectoryCreate(path)) { + return false; + } break; case kSbSystemPathDebugOutputDirectory: if (!SbSystemGetPath(kSbSystemPathTempDirectory, path, kPathSize)) {
diff --git a/src/starboard/linux/x64directfb/future/gyp_configuration.py b/src/starboard/linux/x64directfb/future/gyp_configuration.py index b31713a..1074bc3 100644 --- a/src/starboard/linux/x64directfb/future/gyp_configuration.py +++ b/src/starboard/linux/x64directfb/future/gyp_configuration.py
@@ -14,15 +14,9 @@ """Starboard Linux X64 DirectFB future platform configuration for gyp_cobalt.""" import logging -import os -import sys # Import the shared Linux platform configuration. -sys.path.append( - os.path.realpath( - os.path.join( - os.path.dirname(__file__), os.pardir, os.pardir, 'shared'))) -import gyp_configuration +from starboard.linux.shared import gyp_configuration def CreatePlatformConfig():
diff --git a/src/starboard/linux/x64directfb/gyp_configuration.py b/src/starboard/linux/x64directfb/gyp_configuration.py index 9933052..7e60294 100644 --- a/src/starboard/linux/x64directfb/gyp_configuration.py +++ b/src/starboard/linux/x64directfb/gyp_configuration.py
@@ -14,13 +14,9 @@ """Starboard Linux X64 DirectFB platform configuration for gyp_cobalt.""" import logging -import os -import sys # Import the shared Linux platform configuration. -sys.path.append(os.path.realpath(os.path.join( - os.path.dirname(__file__), os.pardir, 'shared'))) -import gyp_configuration +from starboard.linux.shared import gyp_configuration def CreatePlatformConfig():
diff --git a/src/starboard/linux/x64x11/BUILD.gn b/src/starboard/linux/x64x11/BUILD.gn new file mode 100644 index 0000000..259502b --- /dev/null +++ b/src/starboard/linux/x64x11/BUILD.gn
@@ -0,0 +1,98 @@ +# Copyright 2017 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. + +import("//starboard/build/delegated_config.gni") + +# ============================================================================= +# DEFAULT COMPILER CONFIGS +# ============================================================================= + +config("compiler_defaults") { + libs = [ + "EGL", + "GLESv2", + "X11", + "Xcomposite", + "Xrender", + ] + + configs = [ "//starboard/linux/shared:compiler_defaults" ] +} + +config("compiler_defaults_debug") { + configs = [ "//starboard/linux/shared:compiler_defaults_debug" ] +} + +config("compiler_defaults_devel") { + configs = [ "//starboard/linux/shared:compiler_defaults_devel" ] +} + +config("compiler_defaults_qa") { + configs = [ "//starboard/linux/shared:compiler_defaults_qa" ] +} + +config("compiler_defaults_gold") { + configs = [ "//starboard/linux/shared:compiler_defaults_gold" ] +} + +# ============================================================================= +# DELEGATED CONFIGS +# ============================================================================= + +delegated_config("pedantic_warnings") { + path = "//starboard/linux/shared" + generate_default = false +} + +delegated_config("optimizations") { + path = "//starboard/linux/shared" + prefixes = [ "no", "debuggable", "full" ] +} + +delegated_config("rtti") { + path = "//starboard/linux/shared" +} + +config("wexit_time_destructors") { + configs = [ "//starboard/linux/shared:wexit_time_destructors" ] +} + +# ============================================================================= +# starboard_platform TARGET +# ============================================================================= + +static_library("starboard_platform") { + sources = [ + "//starboard/linux/x64x11/main.cc", + "//starboard/linux/x64x11/sanitizer_options.cc", + "//starboard/linux/x64x11/system_get_property.cc", + "//starboard/shared/starboard/link_receiver.cc", + "//starboard/shared/x11/application_x11.cc", + "//starboard/shared/x11/window_create.cc", + "//starboard/shared/x11/window_destroy.cc", + "//starboard/shared/x11/window_get_platform_handle.cc", + "//starboard/shared/x11/window_get_size.cc", + "//starboard/shared/x11/window_internal.cc", + ] + + defines = [ + # This must be defined when building Starboard, and must not when + # building Starboard client code. + "STARBOARD_IMPLEMENTATION", + ] + + deps = [ + "//starboard/linux/shared:starboard_platform", + ] +}
diff --git a/src/starboard/linux/x64x11/buildconfig.gni b/src/starboard/linux/x64x11/buildconfig.gni new file mode 100644 index 0000000..4335652 --- /dev/null +++ b/src/starboard/linux/x64x11/buildconfig.gni
@@ -0,0 +1,15 @@ +# Copyright 2017 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. + +import("//starboard/linux/shared/buildconfig.gni")
diff --git a/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py b/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py index 67a704c..58d9f75 100644 --- a/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py +++ b/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.py
@@ -14,20 +14,12 @@ """Starboard Linux X64 X11 Clang 3.6 platform configuration for gyp_cobalt.""" import logging -import os -import sys # Import the shared Linux platform configuration. -sys.path.append( - os.path.realpath( - os.path.join( - os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, - 'shared'))) -# pylint: disable=import-self,g-import-not-at-top -import gyp_configuration as shared_configuration +from starboard.linux.shared import gyp_configuration -class PlatformConfig(shared_configuration.PlatformConfig): +class PlatformConfig(gyp_configuration.PlatformConfig): """Starboard Linux platform configuration.""" def __init__(self, platform, asan_enabled_by_default=True):
diff --git a/src/starboard/linux/x64x11/configuration.gni b/src/starboard/linux/x64x11/configuration.gni new file mode 100644 index 0000000..bb3a238 --- /dev/null +++ b/src/starboard/linux/x64x11/configuration.gni
@@ -0,0 +1,19 @@ +# Copyright 2017 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. + +import("//starboard/linux/shared/configuration.gni") + +# Enable support for the map to mesh filter, which is primarily used to +# implement spherical video playback. +enable_map_to_mesh = true
diff --git a/src/starboard/linux/x64x11/directgles/gyp_configuration.py b/src/starboard/linux/x64x11/directgles/gyp_configuration.py index 4fc899f..ca2ca64 100644 --- a/src/starboard/linux/x64x11/directgles/gyp_configuration.py +++ b/src/starboard/linux/x64x11/directgles/gyp_configuration.py
@@ -14,16 +14,9 @@ """Starboard Linux X64 X11 future platform configuration for gyp_cobalt.""" import logging -import os -import sys # Import the shared Linux platform configuration. -sys.path.append( - os.path.realpath( - os.path.join( - os.path.dirname(__file__), os.pardir, os.pardir, 'shared'))) -# pylint: disable=import-self,g-import-not-at-top -import gyp_configuration +from starboard.linux.shared import gyp_configuration def CreatePlatformConfig():
diff --git a/src/starboard/linux/x64x11/future/gyp_configuration.py b/src/starboard/linux/x64x11/future/gyp_configuration.py index 5f82ad7..3a3e34f 100644 --- a/src/starboard/linux/x64x11/future/gyp_configuration.py +++ b/src/starboard/linux/x64x11/future/gyp_configuration.py
@@ -14,15 +14,9 @@ """Starboard Linux X64 X11 future platform configuration for gyp_cobalt.""" import logging -import os -import sys # Import the shared Linux platform configuration. -sys.path.append( - os.path.realpath( - os.path.join( - os.path.dirname(__file__), os.pardir, os.pardir, 'shared'))) -import gyp_configuration +from starboard.linux.shared import gyp_configuration def CreatePlatformConfig():
diff --git a/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.py b/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.py index bac3a98..3c1702d 100644 --- a/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.py +++ b/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.py
@@ -16,20 +16,15 @@ import logging import os import subprocess -import sys -# Import the shared Linux platform configuration. -sys.path.append( - os.path.realpath( - os.path.join( - os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, - 'shared'))) + # pylint: disable=import-self,g-import-not-at-top -import gyp_configuration as shared_configuration import gyp_utils +# Import the shared Linux platform configuration. +from starboard.linux.shared import gyp_configuration -class PlatformConfig(shared_configuration.PlatformConfig): +class PlatformConfig(gyp_configuration.PlatformConfig): """Starboard Linux platform configuration.""" def __init__(self, platform, asan_enabled_by_default=False):
diff --git a/src/starboard/linux/x64x11/mock/gyp_configuration.gypi b/src/starboard/linux/x64x11/mock/gyp_configuration.gypi index 659c47d..f76e9ea 100644 --- a/src/starboard/linux/x64x11/mock/gyp_configuration.gypi +++ b/src/starboard/linux/x64x11/mock/gyp_configuration.gypi
@@ -29,6 +29,7 @@ 'cobalt_enable_jit': 0, 'cobalt_media_source_2016': 1, + 'cobalt_encrypted_media_extension_enable_key_statuses_update': 0, 'platform_libraries': [ '-lpthread',
diff --git a/src/starboard/log.h b/src/starboard/log.h index 596bc88..bd0edef 100644 --- a/src/starboard/log.h +++ b/src/starboard/log.h
@@ -145,7 +145,7 @@ } #if defined(__cplusplus_winrt) -inline std::ostream& operator<<(std::ostream& out, ::Platform::String ^ str) { +inline std::ostream& operator<<(std::ostream& out, ::Platform::String^ str) { return out << std::wstring(str->Begin(), str->End()); } #endif @@ -156,7 +156,10 @@ const SbLogPriority SB_LOG_FATAL = kSbLogPriorityFatal; const SbLogPriority SB_LOG_0 = SB_LOG_ERROR; -class SB_EXPORT LogMessage { +// TODO: Export this, e.g. by wrapping in straight-C functions which can then be +// SB_EXPORT'd. Using SB_EXPORT here directly causes issues on Windows because +// it uses std classes which also need to be exported. +class LogMessage { public: LogMessage(const char* file, int line, SbLogPriority priority); ~LogMessage();
diff --git a/src/starboard/nplb/BUILD.gn b/src/starboard/nplb/BUILD.gn new file mode 100644 index 0000000..29d0b35 --- /dev/null +++ b/src/starboard/nplb/BUILD.gn
@@ -0,0 +1,297 @@ +# Copyright 2017 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. + +import("//starboard/build/deploy.gni") + +group("all") { + testonly = true + deps = [ + ":nplb", + ":deploy", + ] +} + +test("nplb") { + testonly = true + sources = [ + "//starboard/common/test_main.cc", + "accessibility_get_setting_test.cc", + "align_test.cc", + "atomic_test.cc", + "audio_sink_create_test.cc", + "audio_sink_destroy_test.cc", + "audio_sink_get_max_channels_test.cc", + "audio_sink_get_nearest_supported_sample_frequency_test.cc", + "audio_sink_helpers.cc", + "audio_sink_helpers.h", + "audio_sink_is_audio_frame_storage_type_supported_test.cc", + "audio_sink_is_audio_sample_type_supported_test.cc", + "audio_sink_test.cc", + "blitter_blit_rect_to_rect_test.cc", + "blitter_blit_rect_to_rect_tiled_test.cc", + "blitter_blit_rects_to_rects_test.cc", + "blitter_create_context_test.cc", + "blitter_create_default_device_test.cc", + "blitter_create_pixel_data_test.cc", + "blitter_create_render_target_surface_test.cc", + "blitter_create_surface_from_pixel_data_test.cc", + "blitter_create_swap_chain_from_window_test.cc", + "blitter_destroy_context_test.cc", + "blitter_destroy_device_test.cc", + "blitter_destroy_pixel_data_test.cc", + "blitter_destroy_surface_test.cc", + "blitter_destroy_swap_chain_test.cc", + "blitter_download_surface_pixels_test.cc", + "blitter_fill_rect_test.cc", + "blitter_flip_swap_chain_test.cc", + "blitter_flush_context_test.cc", + "blitter_get_max_contexts_test.cc", + "blitter_get_pixel_data_pitch_in_bytes_test.cc", + "blitter_get_pixel_data_pointer_test.cc", + "blitter_get_render_target_from_surface_test.cc", + "blitter_get_render_target_from_swap_chain_test.cc", + "blitter_get_surface_info_test.cc", + "blitter_helpers.cc", + "blitter_is_pixel_format_supported_by_download_surface_pixels_test.cc", + "blitter_is_pixel_format_supported_by_pixel_data_test.cc", + "blitter_is_pixel_format_supported_by_render_target_surface_test.cc", + "blitter_set_blending_test.cc", + "blitter_set_modulate_blits_with_color_test.cc", + "blitter_set_render_target_test.cc", + "blitter_set_scissor_test.cc", + "byte_swap_test.cc", + "char_is_signed_test.cc", + "character_is_alphanumeric_test.cc", + "character_is_digit_test.cc", + "character_is_hex_digit_test.cc", + "character_is_space_test.cc", + "character_is_upper_test.cc", + "character_to_lower_test.cc", + "character_to_upper_test.cc", + "condition_variable_broadcast_test.cc", + "condition_variable_create_test.cc", + "condition_variable_destroy_test.cc", + "condition_variable_signal_test.cc", + "condition_variable_wait_test.cc", + "condition_variable_wait_timed_test.cc", + "configuration_test.cc", + "cryptography_create_transformer_test.cc", + "cryptography_helpers.cc", + "cryptography_helpers.h", + "cryptography_transform_gcm_test.cc", + "cryptography_transform_test.cc", + "decode_target_create_test.cc", + "decode_target_provider_test.cc", + "directory_can_open_test.cc", + "directory_close_test.cc", + "directory_create_test.cc", + "directory_get_next_test.cc", + "directory_open_test.cc", + "double_absolute_test.cc", + "double_exponent_test.cc", + "double_floor_test.cc", + "double_is_finite_test.cc", + "double_is_nan_test.cc", + "file_can_open_test.cc", + "file_close_test.cc", + "file_get_info_test.cc", + "file_get_path_info_test.cc", + "file_helpers.cc", + "file_mode_string_to_flags_test.cc", + "file_open_test.cc", + "file_read_test.cc", + "file_seek_test.cc", + "file_truncate_test.cc", + "file_write_test.cc", + "flat_map_test.cc", + "include_all.c", + "include_all_too.c", + "log_flush_test.cc", + "log_format_test.cc", + "log_is_tty_test.cc", + "log_raw_dump_stack_test.cc", + "log_raw_test.cc", + "log_test.cc", + "memory_align_to_page_size_test.cc", + "memory_allocate_aligned_test.cc", + "memory_allocate_test.cc", + "memory_compare_test.cc", + "memory_copy_test.cc", + "memory_deallocate_aligned_test.cc", + "memory_deallocate_test.cc", + "memory_find_byte_test.cc", + "memory_get_stack_bounds_test.cc", + "memory_is_zero_test.cc", + "memory_map_test.cc", + "memory_move_test.cc", + "memory_reallocate_test.cc", + "memory_reporter_test.cc", + "memory_set_test.cc", + "microphone_close_test.cc", + "microphone_create_test.cc", + "microphone_destroy_test.cc", + "microphone_get_available_test.cc", + "microphone_is_sample_rate_supported_test.cc", + "microphone_open_test.cc", + "microphone_read_test.cc", + "mutex_acquire_test.cc", + "mutex_acquire_try_test.cc", + "mutex_create_test.cc", + "mutex_destroy_test.cc", + "once_test.cc", + "optional_test.cc", + "player_create_test.cc", + "random_helpers.cc", + "rwlock_test.cc", + "semaphore_test.cc", + "socket_accept_test.cc", + "socket_bind_test.cc", + "socket_clear_last_error_test.cc", + "socket_connect_test.cc", + "socket_create_test.cc", + "socket_destroy_test.cc", + "socket_get_interface_address_test.cc", + "socket_get_last_error_test.cc", + "socket_get_local_address_test.cc", + "socket_get_local_interface_address_test.cc", + "socket_helpers.cc", + "socket_is_connected_and_idle_test.cc", + "socket_is_connected_test.cc", + "socket_join_multicast_group_test.cc", + "socket_listen_test.cc", + "socket_receive_from_test.cc", + "socket_resolve_test.cc", + "socket_send_to_test.cc", + "socket_set_options_test.cc", + "socket_waiter_add_test.cc", + "socket_waiter_create_test.cc", + "socket_waiter_destroy_test.cc", + "socket_waiter_remove_test.cc", + "socket_waiter_wait_test.cc", + "socket_waiter_wait_timed_test.cc", + "socket_waiter_wake_up_test.cc", + "socket_wrapper_test.cc", + "speech_recognizer_cancel_test.cc", + "speech_recognizer_create_test.cc", + "speech_recognizer_destroy_test.cc", + "speech_recognizer_helper.h", + "speech_recognizer_start_test.cc", + "speech_recognizer_stop_test.cc", + "speech_synthesis_basic_test.cc", + "storage_close_record_test.cc", + "storage_delete_record_test.cc", + "storage_get_record_size_test.cc", + "storage_open_record_test.cc", + "storage_read_record_test.cc", + "storage_write_record_test.cc", + "state_machine_test.cc", + "string_compare_all_test.cc", + "string_compare_no_case_n_test.cc", + "string_compare_no_case_test.cc", + "string_compare_test.cc", + "string_compare_wide_test.cc", + "string_concat_test.cc", + "string_concat_wide_test.cc", + "string_copy_test.cc", + "string_copy_wide_test.cc", + "string_duplicate_test.cc", + "string_find_character_test.cc", + "string_find_last_character_test.cc", + "string_find_string_test.cc", + "string_format_test.cc", + "string_format_wide_test.cc", + "string_parse_double_test.cc", + "string_parse_signed_integer_test.cc", + "string_parse_uint64_test.cc", + "string_parse_unsigned_integer_test.cc", + "string_scan_test.cc", + "system_binary_search_test.cc", + "system_clear_last_error_test.cc", + "system_get_error_string_test.cc", + "system_get_last_error_test.cc", + "system_get_locale_id_test.cc", + "system_get_number_of_processors_test.cc", + "system_get_path_test.cc", + "system_get_property_test.cc", + "system_get_random_data_test.cc", + "system_get_random_uint64_test.cc", + "system_get_stack_test.cc", + "system_get_total_cpu_memory_test.cc", + "system_get_total_gpu_memory_test.cc", + "system_get_used_cpu_memory_test.cc", + "system_get_used_gpu_memory_test.cc", + "system_has_capability_test.cc", + "system_hide_splash_screen_test.cc", + "system_is_debugger_attached_test.cc", + "system_sort_test.cc", + "system_symbolize_test.cc", + "thread_create_test.cc", + "thread_detach_test.cc", + "thread_get_current_test.cc", + "thread_get_id_test.cc", + "thread_get_name_test.cc", + "thread_helpers.cc", + "thread_is_equal_test.cc", + "thread_join_test.cc", + "thread_local_value_test.cc", + "thread_set_name_test.cc", + "thread_sleep_test.cc", + "thread_yield_test.cc", + "time_get_monotonic_now_test.cc", + "time_get_now_test.cc", + "time_narrow_test.cc", + "time_zone_get_current_test.cc", + "time_zone_get_dst_name_test.cc", + "time_zone_get_name_test.cc", + "user_get_current_test.cc", + "user_get_property_test.cc", + "user_get_signed_in_test.cc", + "window_create_test.cc", + "window_destroy_test.cc", + "window_get_platform_handle_test.cc", + "window_get_size_test.cc", + ] + # Include private C headers, if present. + private_sources = exec_script("//starboard/tools/find_private_files.py", + [ + rebase_path("//", root_build_dir), + "nplb/include_all_private.c", + ], + "list lines", + [ "." ]) + # Include private tests, if present. + private_sources += exec_script("//starboard/tools/find_private_files.py", + [ + rebase_path("//", root_build_dir), + "nplb/*_test.cc", + ], + "list lines", + [ "." ]) + sources += rebase_path(private_sources, ".", root_build_dir) + + deps = [ + "//starboard", + "//testing/gmock", + "//testing/gtest", + ] +} + +deploy("deploy") { + testonly = true + executable_name = "nplb" + + deps = [ + ":nplb", + ] +}
diff --git a/src/starboard/nplb/align_test.cc b/src/starboard/nplb/align_test.cc new file mode 100644 index 0000000..ce53310 --- /dev/null +++ b/src/starboard/nplb/align_test.cc
@@ -0,0 +1,157 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "starboard/common/scoped_ptr.h" +#include "starboard/configuration.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace starboard { +namespace nplb { +namespace { + +bool IsAligned(void *pointer, size_t alignment) { + return (reinterpret_cast<uintptr_t>(pointer) % alignment) == 0; +} + +size_t GetAlignment(void *pointer) { + for (size_t alignment = static_cast<size_t>(1) << ((sizeof(size_t) * 8) - 1); + alignment != 0; alignment /= 2) { + if (IsAligned(pointer, alignment)) { + return alignment; + } + } + + return 1; +} + +struct AlignedFields { + char unaligned1; + SB_ALIGNAS(2) char by_2; + char unaligned2; + SB_ALIGNAS(4) char by_4; + char unaligned3; + SB_ALIGNAS(8) char by_8; + char unaligned4; + SB_ALIGNAS(16) char by_16; + char unaligned5; + SB_ALIGNAS(32) char by_32; + char unaligned6; + SB_ALIGNAS(64) char by_64; + char unaligned7; + SB_ALIGNAS(128) char by_128; + char unaligned8; + SB_ALIGNAS(256) char by_256; + char unaligned9; +}; + +struct AlignedFieldsOf { + char unaligned1; + SB_ALIGNAS(SB_ALIGNOF(void*)) char by_void_star; + char unaligned2; + SB_ALIGNAS(SB_ALIGNOF(int)) char by_int; + char unaligned3; + SB_ALIGNAS(SB_ALIGNOF(uint64_t)) char by_uint64_t; + char unaligned4; +}; + +TEST(SbAlignTest, AlignAsStructFieldOnStack) { + char unaligned = 0; + EXPECT_NE(1, unaligned); + AlignedFields aligned; + EXPECT_LE(2, GetAlignment(&(aligned.by_2))); + EXPECT_LE(4, GetAlignment(&(aligned.by_4))); + EXPECT_LE(8, GetAlignment(&(aligned.by_8))); + EXPECT_LE(16, GetAlignment(&(aligned.by_16))); + EXPECT_LE(32, GetAlignment(&(aligned.by_32))); + EXPECT_LE(64, GetAlignment(&(aligned.by_64))); + EXPECT_LE(128, GetAlignment(&(aligned.by_128))); + EXPECT_LE(256, GetAlignment(&(aligned.by_256))); +} + +TEST(SbAlignTest, AlignAsStackVariable) { + char unaligned1 = 1; + SB_ALIGNAS(2) char by_2; + char unaligned2 = 2; + EXPECT_NE(unaligned2, unaligned1); // These are to try to keep the stack + // variables around. + SB_ALIGNAS(4) char by_4; + char unaligned3 = 3; + EXPECT_NE(unaligned3, unaligned1); + SB_ALIGNAS(8) char by_8; + char unaligned4 = 4; + EXPECT_NE(unaligned4, unaligned1); + SB_ALIGNAS(16) char by_16; + char unaligned5 = 5; + EXPECT_NE(unaligned5, unaligned1); + + EXPECT_LE(2, GetAlignment(&by_2)); + EXPECT_LE(4, GetAlignment(&by_4)); + EXPECT_LE(8, GetAlignment(&by_8)); + EXPECT_LE(16, GetAlignment(&by_16)); + +#if !SB_HAS_QUIRK(DOES_NOT_STACK_ALIGN_OVER_16_BYTES) + SB_ALIGNAS(32) char by_32; + char unaligned6 = 6; + EXPECT_NE(unaligned6, unaligned1); + SB_ALIGNAS(64) char by_64; + char unaligned7 = 7; + EXPECT_NE(unaligned7, unaligned1); + SB_ALIGNAS(128) char by_128; + char unaligned8 = 8; + EXPECT_NE(unaligned8, unaligned1); + SB_ALIGNAS(256) char by_256; + char unaligned9 = 9; + EXPECT_NE(unaligned9, unaligned1); + + EXPECT_LE(32, GetAlignment(&by_32)); + EXPECT_LE(64, GetAlignment(&by_64)); + EXPECT_LE(128, GetAlignment(&by_128)); + EXPECT_LE(256, GetAlignment(&by_256)); +#endif // !SB_HAS_QUIRK(DOES_NOT_STACK_ALIGN_OVER_16_BYTES) +} + +TEST(SbAlignTest, AlignOf) { + EXPECT_LE(sizeof(uint8_t), SB_ALIGNOF(uint8_t)); + EXPECT_LE(sizeof(uint16_t), SB_ALIGNOF(uint16_t)); + EXPECT_LE(sizeof(uint32_t), SB_ALIGNOF(uint32_t)); + EXPECT_LE(sizeof(uint64_t), SB_ALIGNOF(uint64_t)); + EXPECT_LE(sizeof(uintptr_t), SB_ALIGNOF(uintptr_t)); + EXPECT_LE(sizeof(void*), SB_ALIGNOF(void*)); +} + +TEST(SbAlignTest, AlignAsAlignOfStructFieldOnStack) { + char unaligned = 0; + EXPECT_NE(1, unaligned); + + AlignedFieldsOf aligned; + EXPECT_LE(SB_ALIGNOF(void*), GetAlignment(&(aligned.by_void_star))); + EXPECT_LE(SB_ALIGNOF(int), GetAlignment(&(aligned.by_int))); + EXPECT_LE(SB_ALIGNOF(uint64_t), GetAlignment(&(aligned.by_uint64_t))); +} + +TEST(SbAlignTest, AlignAsAlignOfStackVariable) { + char unaligned = 0; + EXPECT_NE(1, unaligned); + SB_ALIGNAS(SB_ALIGNOF(void*)) char by_void_star; + SB_ALIGNAS(SB_ALIGNOF(int)) char by_int; + SB_ALIGNAS(SB_ALIGNOF(uint64_t)) char by_uint64_t; + + EXPECT_LE(SB_ALIGNOF(void*), GetAlignment(&by_void_star)); + EXPECT_LE(SB_ALIGNOF(int), GetAlignment(&by_int)); + EXPECT_LE(SB_ALIGNOF(uint64_t), GetAlignment(&by_uint64_t)); +} + +} // namespace +} // namespace nplb +} // namespace starboard
diff --git a/src/starboard/nplb/file_helpers.cc b/src/starboard/nplb/file_helpers.cc index f6a9f43..07421a9 100644 --- a/src/starboard/nplb/file_helpers.cc +++ b/src/starboard/nplb/file_helpers.cc
@@ -41,6 +41,13 @@ } // static +std::string ScopedRandomFile::MakeRandomFilename() { + std::ostringstream filename_stream; + filename_stream << "ScopedRandomFile.File_" << SbSystemGetRandomUInt64(); + return filename_stream.str(); +} + +// static void ScopedRandomFile::ExpectPattern(int pattern_offset, void* buffer, int size, @@ -53,22 +60,19 @@ } // static -std::string ScopedRandomFile::MakeRandomFilename() { - char path[kPathSize] = {0}; - bool result = SbSystemGetPath(kSbSystemPathTempDirectory, path, kPathSize); - EXPECT_TRUE(result); - if (!result) { +std::string ScopedRandomFile::MakeRandomFilePath() { + std::ostringstream filename_stream; + filename_stream << GetTempDir(); + if (!filename_stream.tellp()) { return ""; } - std::ostringstream filename_stream; - filename_stream << path << SB_FILE_SEP_CHAR << "ScopedRandomFile.File_" - << SbSystemGetRandomUInt64(); + filename_stream << SB_FILE_SEP_CHAR << MakeRandomFilename(); return filename_stream.str(); } std::string ScopedRandomFile::MakeRandomFile(int length) { - std::string filename = MakeRandomFilename(); + std::string filename = MakeRandomFilePath(); if (filename.empty()) { return filename; }
diff --git a/src/starboard/nplb/file_helpers.h b/src/starboard/nplb/file_helpers.h index ad0c946..0a8ba5b 100644 --- a/src/starboard/nplb/file_helpers.h +++ b/src/starboard/nplb/file_helpers.h
@@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef STARBOARD_NBLP_FILE_HELPERS_H_ -#define STARBOARD_NBLP_FILE_HELPERS_H_ +#ifndef STARBOARD_NPLB_FILE_HELPERS_H_ +#define STARBOARD_NPLB_FILE_HELPERS_H_ #include <string> @@ -44,7 +44,7 @@ } // Will create a file |length| bytes long. - ScopedRandomFile(int length) : size_(length) { + explicit ScopedRandomFile(int length) : size_(length) { filename_ = MakeRandomFile(size_); } @@ -52,18 +52,22 @@ // filename. |create| is whether to create the file or not. ScopedRandomFile(int length, Create create) : size_(length) { filename_ = - (create == kCreate ? MakeRandomFile(size_) : MakeRandomFilename()); + (create == kCreate ? MakeRandomFile(size_) : MakeRandomFilePath()); } // Will either create a file of |kDefaultLength| bytes long, or will just // generate a filename. |create| is whether to create the file or not. - ScopedRandomFile(Create create) : size_(kDefaultLength) { + explicit ScopedRandomFile(Create create) : size_(kDefaultLength) { filename_ = - (create == kCreate ? MakeRandomFile(size_) : MakeRandomFilename()); + (create == kCreate ? MakeRandomFile(size_) : MakeRandomFilePath()); } ~ScopedRandomFile() { SbFileDelete(filename_.c_str()); } + // Creates and returns a random filename (no path), but does not create the + // file. + static std::string MakeRandomFilename(); + // Returns the filename generated for this file. const std::string& filename() const { return filename_; } @@ -83,8 +87,8 @@ // the new file. static std::string MakeRandomFile(int length); - // Creates and returns a random filename, but does not create the file. - static std::string MakeRandomFilename(); + // Creates and returns a path to a random file, but does not create the file. + static std::string MakeRandomFilePath(); std::string filename_; int size_; @@ -93,4 +97,4 @@ } // namespace nplb } // namespace starboard -#endif +#endif // STARBOARD_NPLB_FILE_HELPERS_H_
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp index 6c0c76f..274a67f 100644 --- a/src/starboard/nplb/nplb.gyp +++ b/src/starboard/nplb/nplb.gyp
@@ -24,6 +24,7 @@ 'sources': [ '<(DEPTH)/starboard/common/test_main.cc', 'accessibility_get_setting_test.cc', + 'align_test.cc', 'atomic_test.cc', 'audio_sink_create_test.cc', 'audio_sink_destroy_test.cc', @@ -146,6 +147,7 @@ 'mutex_create_test.cc', 'mutex_destroy_test.cc', 'once_test.cc', + 'optional_test.cc', 'player_create_test.cc', 'random_helpers.cc', 'rwlock_test.cc', @@ -184,6 +186,7 @@ 'speech_recognizer_start_test.cc', 'speech_recognizer_stop_test.cc', 'speech_synthesis_basic_test.cc', + 'state_machine_test.cc', 'storage_close_record_test.cc', 'storage_delete_record_test.cc', 'storage_get_record_size_test.cc',
diff --git a/src/starboard/nplb/optional_test.cc b/src/starboard/nplb/optional_test.cc new file mode 100644 index 0000000..c467d2a --- /dev/null +++ b/src/starboard/nplb/optional_test.cc
@@ -0,0 +1,830 @@ +/* + * Copyright 2014 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <set> +#include <string> +#include <unordered_set> +#include <vector> + +#include "starboard/common/optional.h" + +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::InSequence; + +namespace starboard { +namespace { + +TEST(OptionalTest, EnsureDefaultConstructorGivesDisengagedOptional) { + optional<int> test; + EXPECT_TRUE(!test); +} + +TEST(OptionalTest, EnsureNullOptConstructorGivesDisengagedOptional) { + optional<int> test(nullopt); + EXPECT_TRUE(!test); +} + +TEST(OptionalTest, InitializeConstructor) { + optional<int> test(2); + EXPECT_FALSE(!test); + EXPECT_EQ(2, test.value()); +} + +TEST(OptionalTest, BoolCastOperator) { + optional<int> test; + EXPECT_FALSE(static_cast<bool>(test)); + + test = 5; + EXPECT_TRUE(static_cast<bool>(test)); +} + +TEST(OptionalTest, InitializeAssign) { + optional<int> test = 2; + EXPECT_FALSE(!test); + EXPECT_EQ(2, test.value()); +} + +TEST(OptionalTest, ReassignValue) { + optional<int> test(2); + test = 5; + EXPECT_FALSE(!test); + EXPECT_EQ(5, test.value()); +} + +TEST(OptionalTest, CopyAssignment) { + optional<int> a; + optional<int> b = 2; + optional<int> c = 3; + a = b; + EXPECT_FALSE(!a); + EXPECT_EQ(2, a.value()); + + a = c; + EXPECT_FALSE(!a); + EXPECT_EQ(3, a.value()); +} + +TEST(OptionalTest, ClearAssignment) { + optional<int> test(2); + test = optional<int>(); + EXPECT_FALSE(test); +} + +TEST(OptionalTest, EnsureAssignmentOfNullOptResultsInDisengagement) { + optional<int> test(2); + test = nullopt; + EXPECT_FALSE(test); +} + +TEST(OptionalTest, EnsureAssignmentOfDefaultOptionalResultsInDisengagement) { + optional<int> test(2); + test = optional<int>(); + EXPECT_FALSE(test); +} + +TEST(OptionalTest, CopyConstruction) { + optional<int> test1(2); + optional<int> test2(test1); + + EXPECT_FALSE(!test2); + EXPECT_EQ(2, test2.value()); +} + +TEST(OptionalTest, Swap) { + optional<int> test1(1); + optional<int> test2(2); + + // Swap two engaged optionals. + test1.swap(test2); + EXPECT_FALSE(!test1); + EXPECT_EQ(2, test1.value()); + EXPECT_EQ(1, test2.value()); + + // Swap two optionals where only one is engaged. + test1 = nullopt; + test1.swap(test2); + EXPECT_FALSE(test2); + EXPECT_FALSE(!test1); + EXPECT_EQ(1, test1.value()); + + // Swap two optionals where only one is engaged, except the other way around. + test1.swap(test2); + EXPECT_FALSE(test1); + EXPECT_FALSE(!test2); + EXPECT_EQ(1, test2.value()); + + // Swap two disengaged optionals. + test2 = nullopt; + test1.swap(test2); + EXPECT_FALSE(test1); + EXPECT_FALSE(test2); +} + +TEST(OptionalTest, StdSwap) { + optional<int> test1(1); + optional<int> test2(2); + + // Swap two engaged optionals. + std::swap(test1, test2); + EXPECT_FALSE(!test1); + EXPECT_EQ(2, test1.value()); + EXPECT_EQ(1, test2.value()); + + // Swap two optionals where only one is engaged. + test1 = nullopt; + std::swap(test1, test2); + EXPECT_FALSE(test2); + EXPECT_FALSE(!test1); + EXPECT_EQ(1, test1.value()); + + // Swap two optionals where only one is engaged, except the other way around. + std::swap(test1, test2); + EXPECT_FALSE(test1); + EXPECT_FALSE(!test2); + EXPECT_EQ(1, test2.value()); + + // Swap two disengaged optionals. + test2 = nullopt; + std::swap(test1, test2); + EXPECT_FALSE(test1); + EXPECT_FALSE(test2); +} + +TEST(OptionalTest, SwapWithSelf) { + optional<int> test(1); + + test.swap(test); + EXPECT_EQ(1, test.value()); + + std::swap(test, test); + EXPECT_EQ(1, test.value()); +} + +TEST(OptionalTest, AsteriskDereference) { + optional<int> test(2); + EXPECT_EQ(2, *test); + + *test = 5; + EXPECT_EQ(5, test.value()); +} + +struct TestStruct { + int foobar; +}; + +TEST(OptionalTest, ArrowDereference) { + TestStruct a; + a.foobar = 2; + + optional<TestStruct> test(a); + EXPECT_EQ(2, test->foobar); + + test->foobar = 5; + EXPECT_EQ(5, test.value().foobar); + + // Test const arrow dereference. + const optional<TestStruct> test_const(a); + EXPECT_EQ(2, test_const->foobar); +} + +class NoDefaultTest { + public: + explicit NoDefaultTest(int i) { foobar_ = i; } + int foobar() const { return foobar_; } + + private: + NoDefaultTest(); + + int foobar_; +}; + +TEST(OptionalTest, NoDefaultConstructorIsSupported) { + // First test with an object passed in upon construction + optional<NoDefaultTest> test1(NoDefaultTest(2)); + EXPECT_EQ(2, test1.value().foobar()); + + // Now test with an object assignment after construction + optional<NoDefaultTest> test2; + test2 = NoDefaultTest(5); + EXPECT_EQ(5, test2.value().foobar()); +} + +TEST(OptionalTest, TestEquivalenceComparisons) { + optional<int> test1 = 1; + optional<int> test2 = 2; + optional<int> test3; + optional<int> test4 = 2; + + EXPECT_FALSE(test1 == test2); // NOLINT(readability/check) + EXPECT_FALSE(test2 == test1); // NOLINT(readability/check) + EXPECT_FALSE(test1 == test3); // NOLINT(readability/check) + EXPECT_FALSE(test3 == test1); // NOLINT(readability/check) + EXPECT_FALSE(2 == test1); // NOLINT(readability/check) + EXPECT_FALSE(test1 == 2); // NOLINT(readability/check) + EXPECT_EQ(1, test1); + EXPECT_EQ(test1, 1); + EXPECT_EQ(test4, test2); + EXPECT_EQ(test2, test4); + + // Test nullopt comparisons + EXPECT_TRUE(test3 == nullopt); + EXPECT_TRUE(nullopt == test3); + EXPECT_FALSE(test1 == nullopt); + EXPECT_FALSE(nullopt == test1); +} + +TEST(OptionalTest, TestLessThanComparisons) { + optional<int> test1 = 1; + optional<int> test2 = 2; + optional<int> test3; + optional<int> test4 = 2; + + EXPECT_TRUE(test1 < test2); + EXPECT_FALSE(test2 < test1); + EXPECT_FALSE(test1 < test1); + EXPECT_TRUE(test3 < test1); + EXPECT_FALSE(test1 < test3); + EXPECT_FALSE(test3 < test3); + + EXPECT_TRUE(nullopt < test1); + EXPECT_FALSE(test1 < nullopt); + + EXPECT_TRUE(test1 < 2); // NOLINT(readability/check) + EXPECT_FALSE(2 < test1); // NOLINT(readability/check) +} + +TEST(OptionalTest, EnsureOptionalWorksWithFunnyAlignments) { + struct { + char c; + optional<uint64_t> number; + } foo; + + EXPECT_FALSE(!!foo.number); + foo.number = 1; + EXPECT_TRUE(!!foo.number); + EXPECT_EQ(1, foo.number.value()); +} + +class DestructorCallTester { + public: + DestructorCallTester() {} + DestructorCallTester(const DestructorCallTester&) {} + ~DestructorCallTester() { Die(); } + MOCK_METHOD0(Die, void()); +}; + +TEST(OptionalTest, EnsureDestructorIsCalled) { + { + // Ensure destructor is called upon optional destruction + optional<DestructorCallTester> test(in_place); + EXPECT_CALL(test.value(), Die()); + } + + { + // Ensure destructor is called upon assignment to null + optional<DestructorCallTester> test1(in_place); + optional<DestructorCallTester> test2(in_place); + { + InSequence s; + EXPECT_CALL(test1.value(), Die()); + EXPECT_CALL(test2.value(), Die()); + } + test1 = nullopt; + } +} + +// This class counts all calls to the set of methods declared in the class. +// It can be used to verify that certain methods are indeed called. +class MethodCallCounter { + public: + MethodCallCounter() { + ResetCounts(); + ++default_constructor_calls_; + } + + MethodCallCounter(const MethodCallCounter& other) { + // A very non-standard copy constructor, since this is a test object + // intended to count method calls on this object and only this object. + ResetCounts(); + ++copy_constructor_calls_; + } + + MethodCallCounter(MethodCallCounter&& other) { // NOLINT(build/c++11) + // A very non-standard move constructor, since this is a test object + // intended to count method calls on this object and only this object. + ResetCounts(); + ++move_constructor_calls_; + } + + MethodCallCounter& operator=(const MethodCallCounter& other) { + ++assignment_calls_; + return *this; + } + + // NOLINTNEXTLINE(build/c++11) + MethodCallCounter& operator=(MethodCallCounter&& other) { + ++move_assignment_calls_; + return *this; + } + + int assignment_calls() const { return assignment_calls_; } + int copy_constructor_calls() const { return copy_constructor_calls_; } + int default_constructor_calls() const { return default_constructor_calls_; } + int move_assignment_calls() const { return move_assignment_calls_; } + int move_constructor_calls() const { return move_constructor_calls_; } + + private: + void ResetCounts() { + assignment_calls_ = 0; + copy_constructor_calls_ = 0; + default_constructor_calls_ = 0; + move_assignment_calls_ = 0; + move_constructor_calls_ = 0; + } + + int assignment_calls_; + int copy_constructor_calls_; + int default_constructor_calls_; + int move_assignment_calls_; + int move_constructor_calls_; +}; + +TEST(OptionalTest, CopyConstructorIsCalledByValueCopyConstructor) { + MethodCallCounter original_counter; + optional<MethodCallCounter> test(original_counter); + EXPECT_EQ(0, test->assignment_calls()); + EXPECT_EQ(1, test->copy_constructor_calls()); + EXPECT_EQ(0, test->default_constructor_calls()); + EXPECT_EQ(0, test->move_assignment_calls()); + EXPECT_EQ(0, test->move_constructor_calls()); +} + +TEST(OptionalTest, CopyConstructorIsCalledByOptionalCopyConstructor) { + optional<MethodCallCounter> test1(in_place); + optional<MethodCallCounter> test2(test1); + + EXPECT_EQ(0, test2->assignment_calls()); + EXPECT_EQ(1, test2->copy_constructor_calls()); + EXPECT_EQ(0, test2->default_constructor_calls()); + EXPECT_EQ(0, test2->move_assignment_calls()); + EXPECT_EQ(0, test2->move_constructor_calls()); +} + +TEST(OptionalTest, CopyConstructorIsCalledByOptionalAssignment) { + optional<MethodCallCounter> test1(in_place); + optional<MethodCallCounter> test2; + test2 = test1; + + EXPECT_EQ(0, test2->assignment_calls()); + EXPECT_EQ(1, test2->copy_constructor_calls()); + EXPECT_EQ(0, test2->default_constructor_calls()); + EXPECT_EQ(0, test2->move_assignment_calls()); + EXPECT_EQ(0, test2->move_constructor_calls()); +} + +TEST(OptionalTest, AssignmentIsCalledByValueAssignment) { + MethodCallCounter original_counter; + optional<MethodCallCounter> test(in_place); + test = original_counter; + + EXPECT_EQ(1, test->assignment_calls()); + EXPECT_EQ(0, test->copy_constructor_calls()); + EXPECT_EQ(1, test->default_constructor_calls()); + EXPECT_EQ(0, test->move_assignment_calls()); + EXPECT_EQ(0, test->move_constructor_calls()); +} + +TEST(OptionalTest, AssignmentIsCalledByOptionalAssignment) { + optional<MethodCallCounter> test1(in_place); + optional<MethodCallCounter> test2(in_place); + test2 = test1; + + EXPECT_EQ(1, test2->assignment_calls()); + EXPECT_EQ(0, test2->copy_constructor_calls()); + EXPECT_EQ(1, test2->default_constructor_calls()); + EXPECT_EQ(0, test2->move_assignment_calls()); + EXPECT_EQ(0, test2->move_constructor_calls()); +} + +TEST(OptionalTest, MoveConstructorIsCalledOnOptionalMoveConstructor) { + optional<MethodCallCounter> test( + std::move(optional<MethodCallCounter>(in_place))); + + EXPECT_EQ(0, test->assignment_calls()); + EXPECT_EQ(0, test->copy_constructor_calls()); + EXPECT_EQ(0, test->default_constructor_calls()); + EXPECT_EQ(0, test->move_assignment_calls()); + EXPECT_EQ(1, test->move_constructor_calls()); +} + +TEST(OptionalTest, MoveConstructorIsCalledOnUnengagedOptionalMoveAssignment) { + optional<MethodCallCounter> test; + test = std::move(optional<MethodCallCounter>(in_place)); + + EXPECT_EQ(0, test->assignment_calls()); + EXPECT_EQ(0, test->copy_constructor_calls()); + EXPECT_EQ(0, test->default_constructor_calls()); + EXPECT_EQ(0, test->move_assignment_calls()); + EXPECT_EQ(1, test->move_constructor_calls()); +} + +TEST(OptionalTest, MoveAssignmentIsCalledOnEngagedMoveOptionalAssignment) { + optional<MethodCallCounter> test(in_place); + test = std::move(optional<MethodCallCounter>(in_place)); + + EXPECT_EQ(0, test->assignment_calls()); + EXPECT_EQ(0, test->copy_constructor_calls()); + EXPECT_EQ(1, test->default_constructor_calls()); + EXPECT_EQ(1, test->move_assignment_calls()); + EXPECT_EQ(0, test->move_constructor_calls()); +} + +TEST(OptionalTest, MoveConstructorIsCalledOnUnengagedMoveValueConstructor) { + MethodCallCounter original_counter; + optional<MethodCallCounter> test(std::move(original_counter)); + + EXPECT_EQ(0, test->assignment_calls()); + EXPECT_EQ(0, test->copy_constructor_calls()); + EXPECT_EQ(0, test->default_constructor_calls()); + EXPECT_EQ(0, test->move_assignment_calls()); + EXPECT_EQ(1, test->move_constructor_calls()); +} + +TEST(OptionalTest, MoveConstructorIsCalledOnUnengagedMoveValueAssignment) { + MethodCallCounter original_counter; + optional<MethodCallCounter> test; + test = std::move(original_counter); + + EXPECT_EQ(0, test->assignment_calls()); + EXPECT_EQ(0, test->copy_constructor_calls()); + EXPECT_EQ(0, test->default_constructor_calls()); + EXPECT_EQ(0, test->move_assignment_calls()); + EXPECT_EQ(1, test->move_constructor_calls()); +} + +TEST(OptionalTest, MoveAssignmentIsCalledOnEngagedMoveValueAssignment) { + MethodCallCounter original_counter; + optional<MethodCallCounter> test(in_place); + test = std::move(original_counter); + + EXPECT_EQ(0, test->assignment_calls()); + EXPECT_EQ(0, test->copy_constructor_calls()); + EXPECT_EQ(1, test->default_constructor_calls()); + EXPECT_EQ(1, test->move_assignment_calls()); + EXPECT_EQ(0, test->move_constructor_calls()); +} + +TEST(OptionalTest, EnsureSelfAssignmentIsOkay) { + // Ensure that values are as we expect them to be. + optional<int> test1(5); + + test1 = test1; + + EXPECT_FALSE(!test1); + EXPECT_EQ(5, test1.value()); + + // Ensure that the methods we expect to be called are actually called. + optional<MethodCallCounter> test2(in_place); + + test2 = test2; + + EXPECT_EQ(1, test2->assignment_calls()); + EXPECT_EQ(0, test2->copy_constructor_calls()); + EXPECT_EQ(1, test2->default_constructor_calls()); + EXPECT_EQ(0, test2->move_assignment_calls()); + EXPECT_EQ(0, test2->move_constructor_calls()); +} + +// Helper classes to ensure that we can assign different values to optionals +// so long as the wrapped value can be assigned and constructed from the other. +struct XType { + explicit XType(int number) { number_ = number; } + + int number_; +}; + +struct YType { + explicit YType(int number) { number_ = number; } + + explicit YType(const XType& x_type) { number_ = x_type.number_; } + + YType& operator=(const XType& x_type) { + number_ = x_type.number_; + return *this; + } + + int number_; +}; + +TEST(OptionalTest, CopyConstructorIsCalledByValueAssignmentFromOtherType) { + XType x_type(1); + optional<YType> test; + test = x_type; + EXPECT_FALSE(!test); + EXPECT_EQ(1, test->number_); +} + +TEST(OptionalTest, AssignmentIsCalledByValueAssignmentFromOtherType) { + XType x_type(1); + optional<YType> test(in_place, 2); + test = x_type; + EXPECT_FALSE(!test); + EXPECT_EQ(1, test->number_); +} + +TEST(OptionalTest, TestMakeOptional) { + optional<int> test = make_optional(5); + + EXPECT_FALSE(!test); + EXPECT_EQ(5, test.value()); +} + +TEST(OptionalTest, ValueOrTest) { + optional<int> test; + + EXPECT_EQ(4, test.value_or(4)); + + test = 2; + + EXPECT_EQ(2, test.value_or(4)); +} + +TEST(OptionalTest, ConstOptionalsTest) { + const optional<int> test1(5); + + EXPECT_FALSE(!test1); + EXPECT_EQ(5, test1.value()); + EXPECT_EQ(5, *test1); + + const optional<int> test2(test1); + + EXPECT_FALSE(!test2); + EXPECT_EQ(5, test2.value()); + EXPECT_EQ(5, *test2); + + optional<int> test3; + test3 = test2; + + EXPECT_FALSE(!test3); + EXPECT_EQ(5, test3.value()); + EXPECT_EQ(5, *test3); +} + +TEST(OptionalTest, EmplaceInt) { + optional<int> test; + + test.emplace(5); + EXPECT_FALSE(!test); + EXPECT_EQ(5, test.value()); +} + +TEST(OptionalTest, EmplaceWithDefaultConstructor) { + optional<MethodCallCounter> test; + test.emplace(); + + EXPECT_FALSE(!test); + EXPECT_EQ(0, test->assignment_calls()); + EXPECT_EQ(0, test->copy_constructor_calls()); + EXPECT_EQ(1, test->default_constructor_calls()); + EXPECT_EQ(0, test->move_assignment_calls()); + EXPECT_EQ(0, test->move_constructor_calls()); +} + +class NoDefaultOrCopyConstructor { + public: + NoDefaultOrCopyConstructor(int x, int y) { + x_ = x; + y_ = y; + } + + int x() const { return x_; } + int y() const { return y_; } + + private: + NoDefaultOrCopyConstructor(); + NoDefaultOrCopyConstructor(const NoDefaultOrCopyConstructor&); + + int x_; + int y_; +}; + +TEST(OptionalTest, EmplaceObjectWithNoDefaultOrCopyConstructor) { + optional<NoDefaultOrCopyConstructor> test; + test.emplace(1, 2); + EXPECT_FALSE(!test); + EXPECT_EQ(1, test->x()); + EXPECT_EQ(2, test->y()); +} + +class NonConstPointerInConstructor { + public: + explicit NonConstPointerInConstructor(int* param) { param_ = param; } + + void SetParam(int value) { *param_ = value; } + + private: + int* param_; +}; + +TEST(OptionalTest, EmplaceObjectWithNonConstPointer) { + int value = 0; + optional<NonConstPointerInConstructor> test; + test.emplace(&value); + test->SetParam(5); + EXPECT_EQ(5, value); +} + +TEST(OptionalTest, ForwardingConstructorInt) { + optional<int> test(in_place, 5); + EXPECT_FALSE(!test); + EXPECT_EQ(5, test.value()); +} + +TEST(OptionalTest, ForwardingConstructorWithDefaultConstructor) { + optional<MethodCallCounter> test(in_place); + EXPECT_FALSE(!test); + EXPECT_EQ(1, test->default_constructor_calls()); + EXPECT_EQ(0, test->copy_constructor_calls()); + EXPECT_EQ(0, test->assignment_calls()); +} + +TEST(OptionalTest, ForwardingConstructorObjectWithNoDefaultOrCopyConstructor) { + optional<NoDefaultOrCopyConstructor> test(in_place, 1, 2); + EXPECT_FALSE(!test); + EXPECT_EQ(1, test->x()); + EXPECT_EQ(2, test->y()); +} + +TEST(OptionalTest, ForwardingConstructorObjectWithNonConstPointer) { + int value = 0; + optional<NonConstPointerInConstructor> test(in_place, &value); + test->SetParam(5); + EXPECT_EQ(5, value); +} + +TEST(OptionalTest, OptionalStringTest) { + { + optional<std::string> test; + EXPECT_TRUE(!test); + + test = std::string("foo"); + EXPECT_STREQ("foo", test->c_str()); + } + + { + optional<std::string> test(std::string("foo")); + EXPECT_FALSE(!test); + + EXPECT_STREQ("foo", test->c_str()); + optional<std::string> test2(test); + EXPECT_STREQ("foo", test2->c_str()); + } +} + +TEST(OptionalTest, OptionalStringInSetTest) { + // Optional strings in map test + std::set<optional<std::string>> optional_string_set; + + optional_string_set.insert(std::string("foo")); + optional_string_set.insert(std::string("bar")); + + EXPECT_TRUE(optional_string_set.find(std::string("foo")) != + optional_string_set.end()); + EXPECT_TRUE(optional_string_set.find(std::string("bar")) != + optional_string_set.end()); + EXPECT_FALSE(optional_string_set.find(optional<std::string>()) != + optional_string_set.end()); + + optional_string_set.insert(optional<std::string>()); + + EXPECT_TRUE(optional_string_set.find(std::string("foo")) != + optional_string_set.end()); + EXPECT_TRUE(optional_string_set.find(std::string("bar")) != + optional_string_set.end()); + EXPECT_TRUE(optional_string_set.find(optional<std::string>()) != + optional_string_set.end()); +} + +TEST(OptionalTest, StdVectorOfOptionalsWorksFine) { + std::vector<optional<int>> test_vector; + + test_vector.reserve(test_vector.capacity() + 1); + test_vector.resize(test_vector.capacity()); + + // Make sure all current optionals are disengaged. + for (std::vector<optional<int>>::const_iterator iter = test_vector.begin(); + iter != test_vector.end(); ++iter) { + EXPECT_TRUE(!*iter); + } + EXPECT_TRUE(!test_vector[0]); + + test_vector.clear(); + test_vector.resize(test_vector.capacity() + 1, 5); + for (std::vector<optional<int>>::const_iterator iter = test_vector.begin(); + iter != test_vector.end(); ++iter) { + ASSERT_FALSE(!*iter); + EXPECT_EQ(5, **iter); + } + ASSERT_FALSE(!test_vector[0]); + EXPECT_EQ(5, *test_vector[0]); + + test_vector.push_back(8); + ASSERT_FALSE(!test_vector.back()); + EXPECT_EQ(8, *test_vector.back()); +} + +TEST(OptionalTest, OptionalStringInUnorderedSet) { + std::unordered_set<optional<std::string>> optional_string_set; + + optional_string_set.insert(std::string()); + optional_string_set.insert(std::string("7")); + optional_string_set.insert(std::string("123456")); + + EXPECT_TRUE(optional_string_set.find(std::string("7")) != + optional_string_set.end()); + EXPECT_TRUE(optional_string_set.find(std::string("123456")) != + optional_string_set.end()); + EXPECT_TRUE(optional_string_set.find(std::string()) != + optional_string_set.end()); + EXPECT_FALSE(optional_string_set.find(optional<std::string>()) != + optional_string_set.end()); + + optional_string_set.insert(optional<std::string>()); + + EXPECT_TRUE(optional_string_set.find(std::string("7")) != + optional_string_set.end()); + EXPECT_TRUE(optional_string_set.find(std::string("123456")) != + optional_string_set.end()); + EXPECT_TRUE(optional_string_set.find(std::string()) != + optional_string_set.end()); + EXPECT_TRUE(optional_string_set.find(optional<std::string>()) != + optional_string_set.end()); + + optional_string_set.erase(std::string()); + + EXPECT_FALSE(optional_string_set.find(std::string()) != + optional_string_set.end()); + EXPECT_TRUE(optional_string_set.find(optional<std::string>()) != + optional_string_set.end()); +} + +TEST(OptionalTest, OptionalIntInUnorderedSet) { + std::unordered_set<optional<int>> optional_int_set; + + optional_int_set.insert(0); + optional_int_set.insert(7); + optional_int_set.insert(123456); + + EXPECT_TRUE(optional_int_set.find(7) != optional_int_set.end()); + EXPECT_TRUE(optional_int_set.find(123456) != optional_int_set.end()); + EXPECT_TRUE(optional_int_set.find(0) != optional_int_set.end()); + EXPECT_FALSE(optional_int_set.find(optional<int>()) != + optional_int_set.end()); + + optional_int_set.insert(optional<int>()); + + EXPECT_TRUE(optional_int_set.find(7) != optional_int_set.end()); + EXPECT_TRUE(optional_int_set.find(123456) != optional_int_set.end()); + EXPECT_TRUE(optional_int_set.find(0) != optional_int_set.end()); + EXPECT_TRUE(optional_int_set.find(optional<int>()) != optional_int_set.end()); + + optional_int_set.erase(0); + + EXPECT_FALSE(optional_int_set.find(0) != optional_int_set.end()); + EXPECT_TRUE(optional_int_set.find(optional<int>()) != optional_int_set.end()); +} + +optional<int> ConditionallyMakeOptional(bool should_make, int value) { + if (should_make) { + return optional<int>(value); + } else { + return nullopt; + } +} + +TEST(OptionalTest, OptionalCanBeReturnedFromFunction) { + optional<int> test1 = ConditionallyMakeOptional(true, 5); + ASSERT_FALSE(!test1); + EXPECT_EQ(5, test1.value()); + + optional<int> test2 = ConditionallyMakeOptional(false, 5); + EXPECT_TRUE(!test2); +} + +} // namespace +} // namespace starboard
diff --git a/src/base/state_machine_shell_unittest.cc b/src/starboard/nplb/state_machine_test.cc similarity index 85% rename from src/base/state_machine_shell_unittest.cc rename to src/starboard/nplb/state_machine_test.cc index 0d2bda5..86888c0 100644 --- a/src/base/state_machine_shell_unittest.cc +++ b/src/starboard/nplb/state_machine_test.cc
@@ -2,14 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/state_machine_shell.h" +#include "starboard/common/state_machine.h" -#include <list> #include <iostream> +#include <list> -#include "base/logging.h" +#include "starboard/log.h" #include "testing/gtest/include/gtest/gtest.h" +// Enables some verbose logging for debugging the state machine test and +// implementation. +#define STATE_MACHINE_TEST_DEBUG 0 + +namespace starboard { +namespace { namespace hsm { // Constant to represent no version for TestHsm::Expect. @@ -42,17 +48,13 @@ // An enumeration of things that the HSM does that we can sense and then // assert about. -enum HsmEvent { - kHsmEnter, - kHsmExit, - kHsmHandled -}; +enum HsmEvent { kHsmEnter, kHsmExit, kHsmHandled }; -} // namespace hsm +} // namespace hsm // --- Test Subclass --- -// StateMachineShell is an abstract class, so we must subclass it to test it. +// StateMachine is an abstract class, so we must subclass it to test it. // This class uses the sample test state machine specified by Miro Samek in his // Practical Statecharts book. It covers the interesting transitions and // topologies, so if it's fully exercised, it should represent a @@ -64,24 +66,23 @@ // This version has: // - A new event, I, in state S11, to test reentrant event handling. // - A new event, J, and new state T0, to test the no top state case. -class TestHsm : public base::StateMachineShell<hsm::TestState, hsm::TestEvent> { +class TestHsm : public StateMachine<hsm::TestState, hsm::TestEvent> { public: - // --- Some types to aid sensing --- struct ResultEvent { // The state the HSM was in when it handled the event. - const StateEnumN state; + const optional<hsm::TestState> state; // The data passed into the event, if any. - const void *data; + const void* data; // The state that actually handled the event (could be an ancestor of the // current state. - const StateEnumN event_state; + const optional<hsm::TestState> event_state; // The event that was handled. - const EventEnumN event; + const optional<hsm::TestEvent> event; // The "HSM Event" that occurred causing this to be recorded. const hsm::HsmEvent hsm_event; @@ -104,32 +105,32 @@ std::list<ResultEvent> results; TestHsm() - : base::StateMachineShell<hsm::TestState, hsm::TestEvent>("TestHsm"), + : StateMachine<hsm::TestState, hsm::TestEvent>("TestHsm"), foo_(true), event_i_count_(0) { - if (VLOG_IS_ON(1)) { - EnableLogging(); - } +#if STATE_MACHINE_TEST_DEBUG + EnableLogging(); +#endif } - virtual ~TestHsm() { } + virtual ~TestHsm() {} // Clears the results list, so nothing bleeds between test cases. - void ClearResults() { - results.clear(); - } + void ClearResults() { results.clear(); } // Consumes and validates a ResultEvent from the results list. void Expect(hsm::HsmEvent hsm_event, - StateEnumN event_state = StateEnumN(), - EventEnumN event = EventEnumN(), - StateEnumN current_state = StateEnumN(), - void *data = NULL, + optional<hsm::TestState> event_state = nullopt, + optional<hsm::TestEvent> event = nullopt, + optional<hsm::TestState> current_state = nullopt, + void* data = NULL, uint64_t version = hsm::kNoVersion) { - VLOG(1) << __FUNCTION__ << ": hsm_event=" << hsm_event - << ", event_state=" << GetStateString(event_state) - << ", event=" << GetEventString(event) - << ", current_state=" << GetStateString(current_state) - << ", data=0x" << std::hex << data << ", version=" << version; +#if STATE_MACHINE_TEST_DEBUG + SB_DLOG(INFO) << __FUNCTION__ << ": hsm_event=" << hsm_event + << ", event_state=" << GetStateString(event_state) + << ", event=" << GetEventString(event) + << ", current_state=" << GetStateString(current_state) + << ", data=0x" << std::hex << data << ", version=" << version; +#endif // STATE_MACHINE_TEST_DEBUG EXPECT_FALSE(results.empty()); TestHsm::ResultEvent result = results.front(); @@ -156,10 +157,10 @@ } } - - // --- StateMachineShell Implementation --- + // --- StateMachine Implementation --- protected: - virtual StateEnumN GetUserParentState(hsm::TestState state) const OVERRIDE { + virtual optional<hsm::TestState> GetUserParentState( + hsm::TestState state) const SB_OVERRIDE { switch (state) { case hsm::kStateS1: case hsm::kStateS2: @@ -171,11 +172,12 @@ case hsm::kStateS211: return hsm::kStateS21; default: - return StateEnumN(); + return nullopt; } } - virtual StateEnumN GetUserInitialSubstate(hsm::TestState state) const OVERRIDE { + virtual optional<hsm::TestState> GetUserInitialSubstate( + hsm::TestState state) const SB_OVERRIDE { switch (state) { case hsm::kStateS0: return hsm::kStateS1; @@ -186,15 +188,16 @@ case hsm::kStateS21: return hsm::kStateS211; default: - return StateEnumN(); + return nullopt; } } - virtual hsm::TestState GetUserInitialState() const OVERRIDE { + virtual hsm::TestState GetUserInitialState() const SB_OVERRIDE { return hsm::kStateS0; } - virtual const char *GetUserStateString(hsm::TestState state) const OVERRIDE { + virtual const char* GetUserStateString(hsm::TestState state) const + SB_OVERRIDE { switch (state) { case hsm::kStateS0: return "S0"; @@ -215,7 +218,8 @@ } } - virtual const char *GetUserEventString(hsm::TestEvent event) const OVERRIDE { + virtual const char* GetUserEventString(hsm::TestEvent event) const + SB_OVERRIDE { switch (event) { case hsm::kEventA: return "A"; @@ -244,9 +248,12 @@ virtual Result HandleUserStateEvent(hsm::TestState state, hsm::TestEvent event, - void *data) OVERRIDE { - VLOG(1) << __FUNCTION__ << "(" << GetStateString(state) << ", " - << GetEventString(event) << ", 0x" << std::hex << data << ");"; + void* data) SB_OVERRIDE { +#if STATE_MACHINE_TEST_DEBUG + SB_DLOG(INFO) << __FUNCTION__ << "(" << GetStateString(state) << ", " + << GetEventString(event) << ", 0x" << std::hex << data + << ");"; +#endif // STATE_MACHINE_TEST_DEBUG Result result(kNotHandled); switch (state) { @@ -388,37 +395,41 @@ return result; } - virtual void HandleUserStateEnter(hsm::TestState state) OVERRIDE { - VLOG(1) << __FUNCTION__ << "(" << GetStateString(state) << ", ENTER);"; + virtual void HandleUserStateEnter(hsm::TestState state) SB_OVERRIDE { +#if STATE_MACHINE_TEST_DEBUG + SB_DLOG(INFO) << __FUNCTION__ << "(" << GetStateString(state) + << ", ENTER);"; +#endif // STATE_MACHINE_TEST_DEBUG - AddEvent(state, EventEnumN(), NULL, hsm::kHsmEnter); + AddEvent(state, nullopt, NULL, hsm::kHsmEnter); } - virtual void HandleUserStateExit(hsm::TestState state) OVERRIDE { - VLOG(1) << __FUNCTION__ << "(" << GetStateString(state) << ", EXIT);"; + virtual void HandleUserStateExit(hsm::TestState state) SB_OVERRIDE { +#if STATE_MACHINE_TEST_DEBUG + SB_DLOG(INFO) << __FUNCTION__ << "(" << GetStateString(state) << ", EXIT);"; +#endif // STATE_MACHINE_TEST_DEBUG - AddEvent(state, EventEnumN(), NULL, hsm::kHsmExit); + AddEvent(state, nullopt, NULL, hsm::kHsmExit); } private: // Adds a new record to the result list. void AddEvent(hsm::TestState state, - EventEnumN event, - void *data, + optional<hsm::TestEvent> event, + void* data, hsm::HsmEvent hsm_event) { - ResultEvent result_event = { this->state(), data, state, event, hsm_event, - this->version() }; + ResultEvent result_event = {this->state(), data, state, + event, hsm_event, this->version()}; results.push_back(result_event); } }; - // --- Test Definitions --- // This test validates that a state machine will initialize itself when it // handles its first event, even if the user has not explicitly called // initialize. -TEST(StateMachineShellTest, AutoInit) { +TEST(StateMachineTest, AutoInit) { TestHsm hsm; hsm.ClearResults(); @@ -440,12 +451,11 @@ EXPECT_EQ(hsm::kStateS11, hsm.state()); } - // This test validates that if Handle() is called from within an event handler, // it queues the event rather than trying to Handle the next event // reentrantly. This behavior, or something like it, is required to make the // state machine truly run-to-completion. -TEST(StateMachineShellTest, ReentrantHandle) { +TEST(StateMachineTest, ReentrantHandle) { TestHsm hsm; hsm.Initialize(); EXPECT_EQ(0, hsm.version()); @@ -469,7 +479,7 @@ // state machine behaves as expected. This should cover all normal operation of // the state machine framework, except what is extracted into their own test // cases above. -TEST(StateMachineShellTest, KitNKaboodle) { +TEST(StateMachineTest, KitNKaboodle) { TestHsm hsm; // Test the initial state @@ -713,7 +723,7 @@ // Test that event data gets passed through to the handler hsm.ClearResults(); - void *data = reinterpret_cast<void *>(7); + void* data = reinterpret_cast<void*>(7); hsm.Handle(hsm::kEventC, data); hsm.Expect(hsm::kHsmHandled, hsm::kStateS1, hsm::kEventC, hsm::kStateS11, data); @@ -725,3 +735,6 @@ EXPECT_EQ(0, hsm.results.size()); EXPECT_EQ(hsm::kStateS211, hsm.state()); } + +} // namespace +} // namespace starboard
diff --git a/src/starboard/nplb/storage_delete_record_test.cc b/src/starboard/nplb/storage_delete_record_test.cc index 16ade12..ef0fc73 100644 --- a/src/starboard/nplb/storage_delete_record_test.cc +++ b/src/starboard/nplb/storage_delete_record_test.cc
@@ -14,6 +14,7 @@ // Sunny Day cases tested in the read/write tests. +#include "starboard/nplb/file_helpers.h" #include "starboard/storage.h" #include "starboard/user.h" #include "testing/gtest/include/gtest/gtest.h" @@ -22,10 +23,25 @@ namespace nplb { namespace { +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + +TEST(SbStorageDeleteRecordTest, RainyDayInvalidUserValidName) { + EXPECT_FALSE(SbStorageDeleteRecord( + kSbUserInvalid, ScopedRandomFile::MakeRandomFilename().c_str())); +} + +TEST(SbStorageDeleteRecordTest, RainyDayInvalidUserNullName) { + EXPECT_FALSE(SbStorageDeleteRecord(kSbUserInvalid, NULL)); +} + +#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + TEST(SbStorageDeleteRecordTest, RainyDayInvalidUser) { EXPECT_FALSE(SbStorageDeleteRecord(kSbUserInvalid)); } +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + } // namespace } // namespace nplb } // namespace starboard
diff --git a/src/starboard/nplb/storage_helpers.h b/src/starboard/nplb/storage_helpers.h index efc422e..c587203 100644 --- a/src/starboard/nplb/storage_helpers.h +++ b/src/starboard/nplb/storage_helpers.h
@@ -28,23 +28,49 @@ // Deletes the storage for the current user. static SB_C_INLINE void ClearStorageRecord() { +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + SbStorageDeleteRecord(SbUserGetCurrent(), NULL); +#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION SbStorageDeleteRecord(SbUserGetCurrent()); +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION } +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION +// Deletes the named storage record for the current user. +static SB_C_INLINE void ClearStorageRecord(const char* name) { + SbStorageDeleteRecord(SbUserGetCurrent(), name); +} +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + // Opens the storage record for the current user, validating that it is valid. static SB_C_INLINE SbStorageRecord OpenStorageRecord() { +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + SbStorageRecord record = SbStorageOpenRecord(SbUserGetCurrent(), NULL); +#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION SbStorageRecord record = SbStorageOpenRecord(SbUserGetCurrent()); +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION EXPECT_TRUE(SbStorageIsValidRecord(record)); return record; } +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION +// Opens the named storage record for the current user, validating that it is +// valid. +static SB_C_INLINE SbStorageRecord OpenStorageRecord(const char* name) { + SbStorageRecord record = SbStorageOpenRecord(SbUserGetCurrent(), name); + EXPECT_TRUE(SbStorageIsValidRecord(record)); + return record; +} +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + // Writes a standard pattern of |size| bytes into the given open storage // |record|. static SB_C_INLINE void WriteStorageRecord(SbStorageRecord record, - int64_t size) { + int64_t size, + int64_t pattern_offset = 0) { char* data = new char[size]; for (int64_t i = 0; i < size; ++i) { - data[i] = static_cast<char>(i + 2 % 0xFF); + data[i] = static_cast<char>((i + pattern_offset + 2) % 0xFF); } EXPECT_TRUE(SbStorageWriteRecord(record, data, size)); EXPECT_EQ(size, SbStorageGetRecordSize(record)); @@ -65,15 +91,18 @@ // WriteStorageRecord) to start at |offset| and continue for |length|, and the // rest of the buffer, before and after, should be set to 0. static SB_C_INLINE void CheckStorageBuffer(char* data, - int64_t offset, - int64_t length, - int64_t total) { + int64_t offset, + int64_t length, + int64_t total, + int64_t pattern_offset = 0) { for (int64_t i = 0; i < offset; ++i) { EXPECT_EQ(0, data[i]) << "i = " << i; } for (int64_t i = 0; i < length; ++i) { - EXPECT_EQ(static_cast<char>(i + 2 % 0xFF), data[i + offset]) << "i=" << i; + EXPECT_EQ(static_cast<char>((i + pattern_offset + 2) % 0xFF), + data[i + offset]) + << "i=" << i; } for (int64_t i = length + offset; i < total; ++i) { @@ -86,15 +115,16 @@ // read bytes is |expected_length| and then checks the buffer for the expected // pattern written in WriteStorageRecord over the expected range of the buffer. static SB_C_INLINE void ReadAndCheckStorage(SbStorageRecord record, - int64_t offset, - int64_t expected_length, - int64_t length, - int64_t total) { + int64_t offset, + int64_t expected_length, + int64_t length, + int64_t total, + int64_t pattern_offset = 0) { char* data = new char[total]; SbMemorySet(data, 0, total); EXPECT_EQ(expected_length, SbStorageReadRecord(record, data + offset, length)); - CheckStorageBuffer(data, offset, expected_length, total); + CheckStorageBuffer(data, offset, expected_length, total, pattern_offset); delete[] data; }
diff --git a/src/starboard/nplb/storage_open_record_test.cc b/src/starboard/nplb/storage_open_record_test.cc index ec1e588..c935e4a 100644 --- a/src/starboard/nplb/storage_open_record_test.cc +++ b/src/starboard/nplb/storage_open_record_test.cc
@@ -14,6 +14,7 @@ // Sunny Day cases tested in the read/write tests. +#include "starboard/nplb/file_helpers.h" #include "starboard/storage.h" #include "starboard/user.h" #include "testing/gtest/include/gtest/gtest.h" @@ -22,10 +23,26 @@ namespace nplb { namespace { +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + +TEST(SbStorageOpenRecordTest, RainyDayInvalidUserValidName) { + EXPECT_FALSE(SbStorageIsValidRecord(SbStorageOpenRecord( + kSbUserInvalid, ScopedRandomFile::MakeRandomFilename().c_str()))); +} + +TEST(SbStorageOpenRecordTest, RainyDayInvalidUserNullName) { + EXPECT_FALSE( + SbStorageIsValidRecord(SbStorageOpenRecord(kSbUserInvalid, NULL))); +} + +#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + TEST(SbStorageOpenRecordTest, RainyDayInvalidUser) { EXPECT_FALSE(SbStorageIsValidRecord(SbStorageOpenRecord(kSbUserInvalid))); } +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + } // namespace } // namespace nplb } // namespace starboard
diff --git a/src/starboard/nplb/storage_read_record_test.cc b/src/starboard/nplb/storage_read_record_test.cc index 4f11a0d..336e716 100644 --- a/src/starboard/nplb/storage_read_record_test.cc +++ b/src/starboard/nplb/storage_read_record_test.cc
@@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "starboard/nplb/file_helpers.h" #include "starboard/nplb/storage_helpers.h" #include "starboard/storage.h" #include "starboard/user.h" @@ -22,19 +23,26 @@ namespace { TEST(SbStorageReadRecordTest, SunnyDay) { + int64_t pattern = 0; ClearStorageRecord(); SbStorageRecord record = OpenStorageRecord(); - WriteStorageRecord(record, kStorageSize); + WriteStorageRecord(record, kStorageSize, pattern); ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2, - kStorageSize2); + kStorageSize2, pattern); + pattern = 6; + // Write different data and check again. + WriteStorageRecord(record, kStorageSize, pattern); + ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern); EXPECT_TRUE(SbStorageCloseRecord(record)); // Now we'll open again and make sure it is the same. record = OpenStorageRecord(); ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2, - kStorageSize2); + kStorageSize2, pattern); EXPECT_TRUE(SbStorageCloseRecord(record)); + ClearStorageRecord(); } TEST(SbStorageReadRecordTest, SunnyDaySmallBuffer) { @@ -46,12 +54,118 @@ EXPECT_TRUE(SbStorageCloseRecord(record)); } +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION +TEST(SbStorageReadRecordTest, SunnyDayNamed) { + int64_t pattern = 0; + std::string name = ScopedRandomFile::MakeRandomFilename(); + ClearStorageRecord(name.c_str()); + + SbStorageRecord record = OpenStorageRecord(name.c_str()); + WriteStorageRecord(record, kStorageSize, pattern); + ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern); + // Write different data and check again. + pattern = 6; + WriteStorageRecord(record, kStorageSize, pattern); + ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern); + EXPECT_TRUE(SbStorageCloseRecord(record)); + + // Now we'll open again and make sure it is the same. + record = OpenStorageRecord(name.c_str()); + ReadAndCheckStorage(record, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern); + EXPECT_TRUE(SbStorageCloseRecord(record)); + + ClearStorageRecord(name.c_str()); +} + +TEST(SbStorageReadRecordTest, SunnyDayNamed2) { + int64_t pattern1 = 2; + int64_t pattern2 = 8; + std::string name1 = ScopedRandomFile::MakeRandomFilename(); + std::string name2 = ScopedRandomFile::MakeRandomFilename(); + ClearStorageRecord(name1.c_str()); + ClearStorageRecord(name2.c_str()); + + SbStorageRecord record1 = OpenStorageRecord(name1.c_str()); + SbStorageRecord record2 = OpenStorageRecord(name2.c_str()); + WriteStorageRecord(record1, kStorageSize, pattern1); + WriteStorageRecord(record2, kStorageSize, pattern2); + ReadAndCheckStorage(record1, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern1); + ReadAndCheckStorage(record2, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern2); + EXPECT_TRUE(SbStorageCloseRecord(record1)); + EXPECT_TRUE(SbStorageCloseRecord(record2)); + + // Now we'll open again and make sure they are the same. + record1 = OpenStorageRecord(name1.c_str()); + record2 = OpenStorageRecord(name2.c_str()); + ReadAndCheckStorage(record1, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern1); + ReadAndCheckStorage(record2, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern2); + EXPECT_TRUE(SbStorageCloseRecord(record1)); + EXPECT_TRUE(SbStorageCloseRecord(record2)); + + ClearStorageRecord(name1.c_str()); + ClearStorageRecord(name2.c_str()); +} + +TEST(SbStorageReadRecordTest, SunnyDayNamed3) { + int64_t pattern1 = 3; + int64_t pattern2 = 5; + int64_t pattern3 = 7; + std::string name1 = ScopedRandomFile::MakeRandomFilename(); + std::string name2 = ScopedRandomFile::MakeRandomFilename(); + ClearStorageRecord(name1.c_str()); + ClearStorageRecord(name2.c_str()); + ClearStorageRecord(); + + SbStorageRecord record1 = OpenStorageRecord(name1.c_str()); + SbStorageRecord record2 = OpenStorageRecord(name2.c_str()); + SbStorageRecord record3 = OpenStorageRecord(); + WriteStorageRecord(record1, kStorageSize, pattern1); + WriteStorageRecord(record2, kStorageSize, pattern2); + WriteStorageRecord(record3, kStorageSize, pattern3); + ReadAndCheckStorage(record1, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern1); + ReadAndCheckStorage(record2, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern2); + ReadAndCheckStorage(record3, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern3); + EXPECT_TRUE(SbStorageCloseRecord(record1)); + EXPECT_TRUE(SbStorageCloseRecord(record2)); + EXPECT_TRUE(SbStorageCloseRecord(record3)); + + // Now we'll open again and make sure they are the same. + record1 = OpenStorageRecord(name1.c_str()); + record2 = OpenStorageRecord(name2.c_str()); + record3 = OpenStorageRecord(); + ReadAndCheckStorage(record1, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern1); + ReadAndCheckStorage(record2, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern2); + ReadAndCheckStorage(record3, kStorageOffset, kStorageSize, kStorageSize2, + kStorageSize2, pattern3); + EXPECT_TRUE(SbStorageCloseRecord(record1)); + EXPECT_TRUE(SbStorageCloseRecord(record2)); + EXPECT_TRUE(SbStorageCloseRecord(record3)); + + ClearStorageRecord(name1.c_str()); + ClearStorageRecord(name2.c_str()); + ClearStorageRecord(); +} +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + TEST(SbStorageReadRecordTest, SunnyDayNonexistant) { ClearStorageRecord(); SbStorageRecord record = OpenStorageRecord(); ReadAndCheckStorage(record, kStorageOffset, 0, 0, kStorageSize); EXPECT_TRUE(SbStorageCloseRecord(record)); + ClearStorageRecord(); } TEST(SbStorageReadRecordTest, RainyDayInvalidRecord) {
diff --git a/src/starboard/nplb/system_get_path_test.cc b/src/starboard/nplb/system_get_path_test.cc index ea36035..9d2bb59 100644 --- a/src/starboard/nplb/system_get_path_test.cc +++ b/src/starboard/nplb/system_get_path_test.cc
@@ -14,6 +14,9 @@ #include <string.h> +#include "starboard/memory.h" +#include "starboard/nplb/file_helpers.h" +#include "starboard/string.h" #include "starboard/system.h" #include "testing/gtest/include/gtest/gtest.h" @@ -29,15 +32,15 @@ bool expected_result, int line) { #define LOCAL_CONTEXT "Context : id=" << id << ", line=" << line; - char path[kPathSize] = {0}; - memset(path, 0xCD, kPathSize); + char path[kPathSize]; + SbMemorySet(path, 0xCD, kPathSize); bool result = SbSystemGetPath(id, path, kPathSize); if (expect_result) { EXPECT_EQ(expected_result, result) << LOCAL_CONTEXT; } if (result) { EXPECT_NE('\xCD', path[0]) << LOCAL_CONTEXT; - int len = static_cast<int>(strlen(path)); + int len = static_cast<int>(SbStringGetLength(path)); EXPECT_GT(len, 0) << LOCAL_CONTEXT; } else { EXPECT_EQ('\xCD', path[0]) << LOCAL_CONTEXT; @@ -47,6 +50,7 @@ TEST(SbSystemGetPathTest, ReturnsRequiredPaths) { BasicTest(kSbSystemPathContentDirectory, true, true, __LINE__); + BasicTest(kSbSystemPathCacheDirectory, true, true, __LINE__); } TEST(SbSystemGetPathTest, FailsGracefullyZeroBufferLength) { @@ -75,12 +79,86 @@ BasicTest(kSbSystemPathSourceDirectory, false, false, __LINE__); BasicTest(kSbSystemPathTempDirectory, false, false, __LINE__); BasicTest(kSbSystemPathTestOutputDirectory, false, false, __LINE__); + BasicTest(kSbSystemPathCacheDirectory, false, false, __LINE__); #if SB_API_VERSION >= 4 BasicTest(kSbSystemPathFontDirectory, false, false, __LINE__); BasicTest(kSbSystemPathFontConfigurationDirectory, false, false, __LINE__); #endif // SB_API_VERSION >= 4 } +TEST(SbSystemGetPathTest, CanCreateAndRemoveDirectoryInCache) { + char path[kPathSize]; + SbMemorySet(path, 0xCD, kPathSize); + bool result = SbSystemGetPath(kSbSystemPathCacheDirectory, path, kPathSize); + EXPECT_TRUE(result); + if (result) { + EXPECT_NE('\xCD', path[0]); + // Delete a directory and confirm that it does not exist. + std::string sub_path = + SB_FILE_SEP_STRING + ScopedRandomFile::MakeRandomFilename(); + EXPECT_GT(SbStringConcat(path, sub_path.c_str(), kPathSize), 0); + EXPECT_TRUE(SbFileDelete(path)); + EXPECT_FALSE(SbFileExists(path)); + + // Create the directory and confirm it exists and can be opened. + EXPECT_TRUE(SbDirectoryCreate(path)); + EXPECT_TRUE(SbFileExists(path)); + EXPECT_TRUE(SbDirectoryCanOpen(path)); + SbDirectory directory = SbDirectoryOpen(path, NULL); + EXPECT_TRUE(SbDirectoryIsValid(directory)); + + // Lastly, close and delete the directory. + EXPECT_TRUE(SbDirectoryClose(directory)); + EXPECT_TRUE(SbFileDelete(path)); + EXPECT_FALSE(SbFileExists(path)); + } +} +TEST(SbSystemGetPathTest, CanWriteAndReadCache) { + char path[kPathSize]; + SbMemorySet(path, 0xCD, kPathSize); + bool result = SbSystemGetPath(kSbSystemPathCacheDirectory, path, kPathSize); + EXPECT_TRUE(result); + if (result) { + EXPECT_NE('\xCD', path[0]); + int len = static_cast<int>(SbStringGetLength(path)); + EXPECT_GT(len, 0); + // Delete a file and confirm that it does not exist. + std::string sub_path = + SB_FILE_SEP_STRING + ScopedRandomFile::MakeRandomFilename(); + EXPECT_GT(SbStringConcat(path, sub_path.c_str(), kPathSize), 0); + EXPECT_TRUE(SbFileDelete(path)); + EXPECT_FALSE(SbFileExists(path)); + + // Write to the file and check that we can read from it. + std::string content_to_write = "test content"; + { + starboard::ScopedFile test_file_writer( + path, kSbFileCreateAlways | kSbFileWrite, NULL, NULL); + EXPECT_GT( + test_file_writer.WriteAll(content_to_write.c_str(), + static_cast<int>(content_to_write.size())), + 0); + } + EXPECT_TRUE(SbFileExists(path)); + SbFileInfo info; + EXPECT_TRUE(SbFileGetPathInfo(path, &info)); + const int kFileSize = static_cast<int>(info.size); + EXPECT_GT(kFileSize, 0); + const int kBufferLength = 16 * 1024; + char content_read[kBufferLength] = {0}; + { + starboard::ScopedFile test_file_reader( + path, kSbFileOpenOnly | kSbFileRead, NULL, NULL); + EXPECT_GT(test_file_reader.ReadAll(content_read, kFileSize), 0); + } + EXPECT_EQ(content_read, content_to_write); + + // Lastly, delete the file. + EXPECT_TRUE(SbFileDelete(path)); + EXPECT_FALSE(SbFileExists(path)); + } +} + } // namespace } // namespace nplb } // namespace starboard
diff --git a/src/starboard/raspi/shared/configuration_public.h b/src/starboard/raspi/shared/configuration_public.h index dc0b878..76ea308 100644 --- a/src/starboard/raspi/shared/configuration_public.h +++ b/src/starboard/raspi/shared/configuration_public.h
@@ -396,6 +396,13 @@ // The maximum number of users that can be signed in at the same time. #define SB_USER_MAX_SIGNED_IN 1 +// The Raspberry Pi does not apparently align fields in a heap-allocated struct +// by over 16 bytes. +#define SB_HAS_QUIRK_DOES_NOT_ALIGN_FIELDS_IN_HEAP_OVER_16_BYTES 1 + +// The Raspberry Pi does not apparently align stack variables by over 16 bytes. +#define SB_HAS_QUIRK_DOES_NOT_STACK_ALIGN_OVER_16_BYTES 1 + // --- Timing API ------------------------------------------------------------ // Whether this platform has an API to retrieve how long the current thread
diff --git a/src/starboard/raspi/shared/starboard_platform.gypi b/src/starboard/raspi/shared/starboard_platform.gypi index 1170664..030fec1 100644 --- a/src/starboard/raspi/shared/starboard_platform.gypi +++ b/src/starboard/raspi/shared/starboard_platform.gypi
@@ -79,6 +79,7 @@ '<(DEPTH)/starboard/shared/dlmalloc/memory_map.cc', '<(DEPTH)/starboard/shared/dlmalloc/memory_reallocate_unchecked.cc', '<(DEPTH)/starboard/shared/dlmalloc/memory_unmap.cc', + '<(DEPTH)/starboard/shared/dlmalloc/system_get_used_cpu_memory.cc', '<(DEPTH)/starboard/shared/ffmpeg/ffmpeg_audio_decoder.cc', '<(DEPTH)/starboard/shared/ffmpeg/ffmpeg_audio_decoder.h', '<(DEPTH)/starboard/shared/ffmpeg/ffmpeg_audio_resampler.cc', @@ -138,7 +139,6 @@ '<(DEPTH)/starboard/shared/linux/system_get_random_data.cc', '<(DEPTH)/starboard/shared/linux/system_get_stack.cc', '<(DEPTH)/starboard/shared/linux/system_get_total_cpu_memory.cc', - '<(DEPTH)/starboard/shared/linux/system_get_used_cpu_memory.cc', '<(DEPTH)/starboard/shared/linux/system_is_debugger_attached.cc', '<(DEPTH)/starboard/shared/linux/system_symbolize.cc', '<(DEPTH)/starboard/shared/linux/thread_get_id.cc',
diff --git a/src/starboard/shared/alsa/alsa_audio_sink_type.cc b/src/starboard/shared/alsa/alsa_audio_sink_type.cc index 25688a5..e0cbd79 100644 --- a/src/starboard/shared/alsa/alsa_audio_sink_type.cc +++ b/src/starboard/shared/alsa/alsa_audio_sink_type.cc
@@ -99,6 +99,11 @@ } #endif // SB_API_VERSION >= 4 + void SetVolume(double volume) SB_OVERRIDE { + ScopedLock lock(mutex_); + volume_ = volume; + } + bool is_valid() { return playback_handle_ != NULL; } private: @@ -124,6 +129,7 @@ void* context_; double playback_rate_; + double volume_; std::vector<uint8_t> resample_buffer_; int channels_; @@ -157,6 +163,7 @@ void* context) : type_(type), playback_rate_(1.0), + volume_(1.0), resample_buffer_(channels * kFramesPerRequest * GetSampleSize(sample_type)), channels_(channels), @@ -272,6 +279,7 @@ bool AlsaAudioSink::PlaybackLoop() { SB_DLOG(INFO) << "alsa::AlsaAudioSink enters playback loop"; + // TODO: Also handle |volume_| here. double playback_rate = 1.0; for (;;) { int delayed_frame = AlsaGetBufferedFrames(playback_handle_);
diff --git a/src/starboard/shared/dlmalloc/system_get_used_cpu_memory.cc b/src/starboard/shared/dlmalloc/system_get_used_cpu_memory.cc new file mode 100644 index 0000000..0fe2662 --- /dev/null +++ b/src/starboard/shared/dlmalloc/system_get_used_cpu_memory.cc
@@ -0,0 +1,39 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "starboard/memory.h" + +#include "starboard/shared/dlmalloc/page_internal.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Returns the number of bytes obtained from the system. The total +// number of bytes allocated by malloc, realloc etc., is less than this +// value. Unlike mallinfo, this function returns only a precomputed +// result, so can be called frequently to monitor memory consumption. +// Even if locks are otherwise defined, this function does not use them, +// so results might not be up to date. +// +// See http://gee.cs.oswego.edu/pub/misc/malloc.h for more details. +size_t SB_ALLOCATOR(malloc_footprint)(); + +#ifdef __cplusplus +} // extern "C" +#endif + +int64_t SbSystemGetUsedCPUMemory() { + return static_cast<int64_t>(SB_ALLOCATOR(malloc_footprint)()); +}
diff --git a/src/starboard/shared/linux/dev_input/dev_input.cc b/src/starboard/shared/linux/dev_input/dev_input.cc index bc3202e..d0bd7fe 100644 --- a/src/starboard/shared/linux/dev_input/dev_input.cc +++ b/src/starboard/shared/linux/dev_input/dev_input.cc
@@ -24,6 +24,8 @@ #include <vector> #include <algorithm> +#include <cmath> +#include <map> #include <string> #include "starboard/configuration.h" @@ -44,15 +46,44 @@ using ::starboard::shared::starboard::Application; typedef int FileDescriptor; -const FileDescriptor kInvalidFd = -1; -const int kKeyboardDeviceId = 1; +const FileDescriptor kInvalidFd = -ENODEV; + +enum InputDeviceIds { + kKeyboardDeviceId = 1, + kGamepadDeviceId, +}; + +enum TouchPadPositionState { + kTouchPadPositionNone = 0, + kTouchPadPositionX = 1, + kTouchPadPositionY = 2, + kTouchPadPositionAll = kTouchPadPositionX | kTouchPadPositionY +}; + +struct InputDeviceInfo { + InputDeviceInfo() : fd(-1), touchpad_position_state(kTouchPadPositionNone) {} + + // File descriptor open for the device + FileDescriptor fd; + // Absolute Axis info. + std::map<int, struct input_absinfo> axis_info; + std::map<int, float> axis_value; + int touchpad_position_state; +}; + +bool IsTouchpadPositionKnown(InputDeviceInfo* device_info) { + return device_info->touchpad_position_state == kTouchPadPositionAll; +} // Private implementation of DevInput. class DevInputImpl : public DevInput { public: explicit DevInputImpl(SbWindow window); + DevInputImpl(SbWindow window, FileDescriptor wake_up_fd); ~DevInputImpl() SB_OVERRIDE; + void InitDevInputImpl(SbWindow window); + Event* PollNextSystemEvent() SB_OVERRIDE; Event* WaitForSystemEventWithTimeout(SbTime time) SB_OVERRIDE; void WakeSystemEventWait() SB_OVERRIDE; @@ -61,13 +92,27 @@ // Converts an input_event into a kSbEventInput Application::Event. The caller // is responsible for deleting the returned event. Event* InputToApplicationEvent(const struct input_event& event, + InputDeviceInfo* device_info, int modifiers); + // Converts an input_event containing a key input into a kSbEventInput + // Application::Event. The caller is responsible for deleting the returned + // event. + Event* KeyInputToApplicationEvent(const struct input_event& event, + int modifiers); + + // Converts an input_event containing an axis event into a kSbEventInput + // Application::Event. The caller is responsible for deleting the returned + // event. + Event* AxisInputToApplicationEvent(const struct input_event& event, + InputDeviceInfo* device_info, + int modifiers); + // The window to attribute /dev/input events to. SbWindow window_; // A set of read-only file descriptor of keyboard input devices. - std::vector<FileDescriptor> keyboard_fds_; + std::vector<InputDeviceInfo> input_devices_; // A file descriptor of the write end of a pipe that can be written to from // any thread to wake up this waiter in a thread-safe manner. @@ -76,6 +121,8 @@ // A file descriptor of the read end of a pipe that this waiter will wait on // to allow it to be signalled safely from other threads. FileDescriptor wakeup_read_fd_; + + FileDescriptor wake_up_fd_; }; // Helper class to manage a file descriptor set. @@ -126,16 +173,12 @@ case KEY_PAGEDOWN: return kSbKeyNext; case KEY_LEFT: - case BTN_DPAD_LEFT: return kSbKeyLeft; case KEY_RIGHT: - case BTN_DPAD_RIGHT: return kSbKeyRight; case KEY_DOWN: - case BTN_DPAD_DOWN: return kSbKeyDown; case KEY_UP: - case BTN_DPAD_UP: return kSbKeyUp; case KEY_ESC: return kSbKeyEscape; @@ -374,6 +417,49 @@ return kSbKeyBrightnessDown; case KEY_BRIGHTNESSUP: return kSbKeyBrightnessUp; + + // Gamepad buttons. + // https://www.kernel.org/doc/Documentation/input/gamepad.txt + case BTN_TL: + return kSbKeyGamepadLeftTrigger; + case BTN_TR: + return kSbKeyGamepadRightTrigger; + case BTN_DPAD_DOWN: + return kSbKeyGamepadDPadDown; + case BTN_DPAD_UP: + return kSbKeyGamepadDPadUp; + case BTN_DPAD_LEFT: + return kSbKeyGamepadDPadLeft; + case BTN_DPAD_RIGHT: + return kSbKeyGamepadDPadRight; + // The mapping for the buttons below can vary from controller to controller. + // TODO: Include button mapping for controllers with different layout. + case BTN_B: + return kSbKeyGamepad1; + case BTN_C: + return kSbKeyGamepad2; + case BTN_A: + return kSbKeyGamepad3; + case BTN_X: + return kSbKeyGamepad4; + case BTN_Y: + return kSbKeyGamepadLeftBumper; + case BTN_Z: + return kSbKeyGamepadRightBumper; + case BTN_TL2: + return kSbKeyGamepad5; + case BTN_TR2: + return kSbKeyGamepad6; + case BTN_SELECT: + return kSbKeyGamepadLeftStick; + case BTN_START: + return kSbKeyGamepadRightStick; + case BTN_MODE: + return kSbKeyGamepadSystem; + case BTN_THUMBL: + return kSbKeyGamepad1; + case BTN_THUMBR: + return kSbKeyGamepad1; } SB_DLOG(WARNING) << "Unknown code: 0x" << std::hex << code; return kSbKeyUnknown; @@ -408,21 +494,129 @@ return !!(bitset.at(bit / 8) & (1 << (bit % 8))); } -// Searches for the keyboard /dev/input devices, opens them and returns the file -// descriptors that report keyboard events. -std::vector<FileDescriptor> GetKeyboardFds() { - const char kDevicePath[] = "/dev/input"; - SbDirectory directory = SbDirectoryOpen(kDevicePath, NULL); - std::vector<FileDescriptor> fds; - if (!SbDirectoryIsValid(directory)) { - SB_DLOG(ERROR) << __FUNCTION__ << ": No /dev/input support, " - << "unable to open: " << kDevicePath; - return fds; +bool IsAxisFlat(float median, const struct input_absinfo& axis_info) { + SB_DCHECK((axis_info.flat * 2) <= (axis_info.maximum - axis_info.minimum)); + return (axis_info.flat != 0) && (axis_info.value > median - axis_info.flat) && + (axis_info.value < median + axis_info.flat); +} + +float GetAxisValue(const struct input_absinfo& axis_info) { + float median = + static_cast<float>(axis_info.maximum + axis_info.minimum) / 2.0f; + if (IsAxisFlat(median, axis_info)) + return 0; + float range = static_cast<float>(axis_info.maximum - axis_info.minimum); + float radius = range / 2.0f; + // Scale the axis value to [-1, 1]. + float axis_value = (static_cast<float>(axis_info.value) - median) / radius; + + if (axis_info.flat != 0) { + // Calculate the flat value scaled to [0, 1]. + float flat = static_cast<float>(axis_info.flat) / range; + + int sign = axis_value < 0.0f ? -1 : 1; + // Rescale the range: + // [-1.0f, -flat] to [-1.0f, 0.0f] and [flat, 1.0f] to [0.0f, 1.0f]. + axis_value = (axis_value - sign * flat) / (1 - flat); + } + return axis_value; +} + +void GetInputDeviceAbsoluteAxisInfo(int axis, + const std::vector<uint8_t>& bits, + InputDeviceInfo* info) { + if (IsBitSet(bits, axis)) { + struct input_absinfo axis_info; + int result = ioctl(info->fd, EVIOCGABS(axis), &axis_info); + if (result < 0) { + return; + } + info->axis_info.insert(std::make_pair(axis, axis_info)); + info->axis_value.insert(std::make_pair(axis, GetAxisValue(axis_info))); + } +} + +void GetInputDeviceInfo(InputDeviceInfo* info) { + std::vector<uint8_t> axis_bits(BytesNeededForBitSet(KEY_MAX)); + int result = + ioctl(info->fd, EVIOCGBIT(EV_ABS, axis_bits.size()), axis_bits.data()); + if (result < 0) { + return; + } + + GetInputDeviceAbsoluteAxisInfo(ABS_X, axis_bits, info); + GetInputDeviceAbsoluteAxisInfo(ABS_Y, axis_bits, info); + GetInputDeviceAbsoluteAxisInfo(ABS_Z, axis_bits, info); + GetInputDeviceAbsoluteAxisInfo(ABS_RZ, axis_bits, info); + GetInputDeviceAbsoluteAxisInfo(ABS_RX, axis_bits, info); + GetInputDeviceAbsoluteAxisInfo(ABS_RY, axis_bits, info); + GetInputDeviceAbsoluteAxisInfo(ABS_HAT0X, axis_bits, info); + GetInputDeviceAbsoluteAxisInfo(ABS_HAT0Y, axis_bits, info); + GetInputDeviceAbsoluteAxisInfo(ABS_MT_POSITION_X, axis_bits, info); + GetInputDeviceAbsoluteAxisInfo(ABS_MT_POSITION_Y, axis_bits, info); + GetInputDeviceAbsoluteAxisInfo(ABS_MT_TRACKING_ID, axis_bits, info); + // TODO: Handle multi-touch using ABS_MT_SLOT. +} + +FileDescriptor OpenDeviceIfKeyboardOrGamepad(const char* path) { + FileDescriptor fd = open(path, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + // Open can fail if the application doesn't have permission to access + // the input device directly. + return kInvalidFd; } std::vector<uint8_t> ev_bits(BytesNeededForBitSet(EV_CNT)); std::vector<uint8_t> key_bits(BytesNeededForBitSet(KEY_MAX)); + int result = ioctl(fd, EVIOCGBIT(0, ev_bits.size()), ev_bits.data()); + if (result < 0) { + close(fd); + return kInvalidFd; + } + + bool has_ev_key = IsBitSet(ev_bits, EV_KEY); + if (!has_ev_key) { + close(fd); + return kInvalidFd; + } + + result = ioctl(fd, EVIOCGBIT(EV_KEY, key_bits.size()), key_bits.data()); + if (result < 0) { + close(fd); + return kInvalidFd; + } + + bool has_key_space = IsBitSet(key_bits, KEY_SPACE); + bool has_gamepad_button = IsBitSet(key_bits, BTN_GAMEPAD); + if (!has_key_space && !has_gamepad_button) { + // If it doesn't have a space key or gamepad button, it may be a mouse. + close(fd); + return kInvalidFd; + } + + result = ioctl(fd, EVIOCGRAB, 1); + if (result != 0) { + SB_DLOG(ERROR) << __FUNCTION__ << ": " + << "Unable to get exclusive access to \"" << path << "\"."; + close(fd); + return kInvalidFd; + } + return fd; +} + +// Searches for the keyboard and game controller /dev/input devices, opens them +// and returns the device info with a file descriptor and absolute axis details. +std::vector<InputDeviceInfo> GetInputDevices() { + const char kDevicePath[] = "/dev/input"; + SbDirectory directory = SbDirectoryOpen(kDevicePath, NULL); + std::vector<InputDeviceInfo> input_devices; + if (!SbDirectoryIsValid(directory)) { + SB_DLOG(ERROR) << __FUNCTION__ << ": No /dev/input support, " + << "unable to open: " << kDevicePath; + return input_devices; + } + while (true) { SbDirectoryEntry entry; if (!SbDirectoryGetNext(directory, &entry)) { @@ -438,60 +632,25 @@ continue; } - FileDescriptor fd = open(path.c_str(), O_RDONLY | O_NONBLOCK); - if (fd < 0) { - SB_DLOG(ERROR) << __FUNCTION__ << ": Unable to open \"" << path << "\"."; + FileDescriptor fd = OpenDeviceIfKeyboardOrGamepad(path.c_str()); + if (fd == kInvalidFd) { continue; } + InputDeviceInfo info; + info.fd = fd; + GetInputDeviceInfo(&info); - int result = ioctl(fd, EVIOCGBIT(0, ev_bits.size()), ev_bits.data()); - - if (result < 0) { - close(fd); - continue; - } - - bool has_ev_key = IsBitSet(ev_bits, EV_KEY); - - if (!has_ev_key) { - close(fd); - continue; - } - - result = ioctl(fd, EVIOCGBIT(EV_KEY, key_bits.size()), key_bits.data()); - - if (result < 0) { - close(fd); - continue; - } - - bool has_key_space = IsBitSet(key_bits, KEY_SPACE); - - if (!has_key_space) { - // If it doesn't have a space key, it may be a mouse - close(fd); - continue; - } - - result = ioctl(fd, EVIOCGRAB, 1); - if (result != 0) { - SB_DLOG(ERROR) << __FUNCTION__ << ": " - << "Unable to get exclusive access to \"" << path << "\"."; - close(fd); - continue; - } - - SB_DCHECK(fd != kInvalidFd); - fds.push_back(fd); + SB_DCHECK(info.fd != kInvalidFd); + input_devices.push_back(info); } - if (fds.empty()) { + if (input_devices.empty()) { SB_DLOG(ERROR) << __FUNCTION__ << ": No /dev/input support. " - << "No keyboards available."; + << "No keyboards or game controllers available."; } SbDirectoryClose(directory); - return fds; + return input_devices; } // Returns whether |key_code|'s bit is set in the bitmap |map|, assuming @@ -513,14 +672,14 @@ return 0; } -// Polls the given keyboard file descriptor for an input_event. If there are no +// Polls the given input file descriptor for an input_event. If there are no // bytes available, assumes that there is no input event to read. If it gets a // partial event, it will assume that it will be completed, and spins until it // receives an entire event. -bool PollKeyboardEvent(FileDescriptor fd, - struct input_event* out_event, - int* out_modifiers) { - if (fd == kInvalidFd) { +bool PollInputEvent(InputDeviceInfo* device_info, + struct input_event* out_event, + int* out_modifiers) { + if (device_info->fd == kInvalidFd) { return false; } @@ -531,7 +690,7 @@ size_t remaining = kEventSize; char* buffer = reinterpret_cast<char*>(out_event); while (remaining > 0) { - int bytes_read = read(fd, buffer, remaining); + int bytes_read = read(device_info->fd, buffer, remaining); if (bytes_read <= 0) { if (errno == EAGAIN || bytes_read == 0) { if (remaining == kEventSize) { @@ -544,18 +703,18 @@ } // Some unexpected type of read error occured. - SB_DLOG(ERROR) << __FUNCTION__ << ": Error reading keyboard: " << errno + SB_DLOG(ERROR) << __FUNCTION__ << ": Error reading input: " << errno << " - " << strerror(errno); return false; } - SB_DCHECK(bytes_read <= remaining) << "bytes_read=" << bytes_read - << ", remaining=" << remaining; + SB_DCHECK(bytes_read <= remaining) + << "bytes_read=" << bytes_read << ", remaining=" << remaining; remaining -= bytes_read; buffer += bytes_read; } - if (out_event->type != EV_KEY) { + if ((out_event->type != EV_KEY) && (out_event->type != EV_ABS)) { return false; } @@ -563,7 +722,7 @@ int modifiers = 0; char map[(KEY_MAX / 8) + 1] = {0}; errno = 0; - int result = ioctl(fd, EVIOCGKEY(sizeof(map)), map); + int result = ioctl(device_info->fd, EVIOCGKEY(sizeof(map)), map); if (result != -1) { modifiers |= GetModifier(KEY_LEFTSHIFT, KEY_RIGHTSHIFT, kSbKeyModifiersShift, map); @@ -593,20 +752,35 @@ // Also in starboard/shared/libevent/socket_waiter_internal.cc // TODO: Consider consolidating. -int SetNonBlocking(int fd) { +int SetNonBlocking(FileDescriptor fd) { int flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) + if (flags == -1) { flags = 0; + } return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } DevInputImpl::DevInputImpl(SbWindow window) : window_(window), - keyboard_fds_(GetKeyboardFds()), + input_devices_(GetInputDevices()), wakeup_write_fd_(kInvalidFd), - wakeup_read_fd_(kInvalidFd) { + wakeup_read_fd_(kInvalidFd), + wake_up_fd_(kInvalidFd) { + InitDevInputImpl(window); +} + +DevInputImpl::DevInputImpl(SbWindow window, FileDescriptor wake_up_fd) + : window_(window), + input_devices_(GetInputDevices()), + wakeup_write_fd_(kInvalidFd), + wakeup_read_fd_(kInvalidFd), + wake_up_fd_(wake_up_fd) { + InitDevInputImpl(window); +} + +void DevInputImpl::InitDevInputImpl(SbWindow window) { // Initialize wakeup pipe. - int fds[2] = {kInvalidFd, kInvalidFd}; + FileDescriptor fds[2] = {kInvalidFd, kInvalidFd}; int result = pipe(fds); SB_DCHECK(result == 0) << "result=" << result; @@ -622,9 +796,8 @@ } DevInputImpl::~DevInputImpl() { - for (std::vector<FileDescriptor>::const_iterator it = keyboard_fds_.begin(); - it != keyboard_fds_.end(); ++it) { - close(*it); + for (const auto& device : input_devices_) { + close(device.fd); } CloseFdSafely(&wakeup_write_fd_); CloseFdSafely(&wakeup_read_fd_); @@ -633,13 +806,12 @@ DevInput::Event* DevInputImpl::PollNextSystemEvent() { struct input_event event; int modifiers = 0; - for (std::vector<FileDescriptor>::const_iterator it = keyboard_fds_.begin(); - it != keyboard_fds_.end(); ++it) { - if (!PollKeyboardEvent(*it, &event, &modifiers)) { + for (auto& device : input_devices_) { + if (!PollInputEvent(&device, &event, &modifiers)) { continue; } - return InputToApplicationEvent(event, modifiers); + return InputToApplicationEvent(event, &device, modifiers); } return NULL; } @@ -651,9 +823,13 @@ } FdSet read_set; - for (std::vector<FileDescriptor>::const_iterator it = keyboard_fds_.begin(); - it != keyboard_fds_.end(); ++it) { - read_set.Set(*it); + if (wake_up_fd_ != kInvalidFd) { + read_set.Set(wake_up_fd_); + } + + for (std::vector<InputDeviceInfo>::const_iterator it = input_devices_.begin(); + it != input_devices_.end(); ++it) { + read_set.Set(it->fd); } read_set.Set(wakeup_read_fd_); @@ -693,13 +869,256 @@ } } -DevInput::Event* DevInputImpl::InputToApplicationEvent( - const struct input_event& event, - int modifiers) { - if (event.type != EV_KEY) { +namespace { + +// Creates a key event for an analog button input. +DevInput::Event* CreateAnalogButtonKeyEvent(SbWindow window, + float axis_value, + float previous_axis_value, + SbKey key, + SbKeyLocation location, + int modifiers, + const struct input_event& event) { + SbInputEventType previous_type = + (std::abs(previous_axis_value) > 0.5 ? kSbInputEventTypePress + : kSbInputEventTypeUnpress); + SbInputEventType type = + (std::abs(axis_value) > 0.5 ? kSbInputEventTypePress + : kSbInputEventTypeUnpress); + if (previous_type == type) { + // Key press/unpress state did not change. return NULL; } + SbInputData* data = new SbInputData(); + SbMemorySet(data, 0, sizeof(*data)); + data->window = window; + data->type = type; + data->device_type = kSbInputDeviceTypeGamepad; + data->device_id = kGamepadDeviceId; + data->key = key; + data->key_location = location; + data->key_modifiers = modifiers; + return new DevInput::Event(kSbEventTypeInput, data, + &Application::DeleteDestructor<SbInputData>); +} + +// Creates a move event with key for a stick input. +DevInput::Event* CreateMoveEventWithKey(SbWindow window, + SbKey key, + SbKeyLocation location, + int modifiers, + const SbInputVector& input_vector) { + SbInputData* data = new SbInputData(); + SbMemorySet(data, 0, sizeof(*data)); + + data->window = window; + data->type = kSbInputEventTypeMove; + data->device_type = kSbInputDeviceTypeGamepad; + data->device_id = kGamepadDeviceId; + + data->key = key; + data->key_location = location; + data->key_modifiers = modifiers; + data->position = input_vector; +#if SB_API_VERSION >= SB_POINTER_INPUT_API_VERSION + data->pressure = NAN; + data->size = {NAN, NAN}; + data->tilt = {NAN, NAN}; +#endif + + return new DevInput::Event(kSbEventTypeInput, data, + &Application::DeleteDestructor<SbInputData>); +} + +DevInput::Event* CreateTouchPadEvent(SbWindow window, + SbInputEventType type, + SbKey key, + SbKeyLocation location, + int modifiers, + const SbInputVector& input_vector) { + SbInputData* data = new SbInputData(); + SbMemorySet(data, 0, sizeof(*data)); + + data->window = window; + data->type = type; + data->device_type = kSbInputDeviceTypeTouchPad; + data->device_id = kGamepadDeviceId; + + data->key = key; + data->key_location = location; + data->key_modifiers = modifiers; + data->position = input_vector; +#if SB_API_VERSION >= SB_POINTER_INPUT_API_VERSION + data->pressure = NAN; + data->size = {NAN, NAN}; + data->tilt = {NAN, NAN}; +#endif + + return new DevInput::Event(kSbEventTypeInput, data, + &Application::DeleteDestructor<SbInputData>); +} + +} // namespace + +DevInput::Event* DevInputImpl::AxisInputToApplicationEvent( + const struct input_event& event, + InputDeviceInfo* device_info, + int modifiers) { + SB_DCHECK(event.type == EV_ABS); + SbKey key = kSbKeyUnknown; + float axis_value = 0; + float previous_axis_value = 0; + auto axis_info_it = device_info->axis_info.find(event.code); + if (axis_info_it != device_info->axis_info.end()) { + struct input_absinfo& axis_info = axis_info_it->second; + axis_info.value = event.value; + axis_value = GetAxisValue(axis_info); + float& stored_axis_value = device_info->axis_value[event.code]; + previous_axis_value = stored_axis_value; + if (previous_axis_value == axis_value) { + // If the value is unchanged, don't do anything. + return NULL; + } + stored_axis_value = axis_value; + } + + SbKeyLocation location = kSbKeyLocationUnspecified; + SbInputVector input_vector; + // The mapping for the axis codes can vary from controller to controller. + // TODO: Include axis mapping for controllers with different layout. + switch (event.code) { + case ABS_X: + // Report up and left as positive values. + input_vector.x = -axis_value; + input_vector.y = -device_info->axis_value[ABS_Y]; + key = kSbKeyGamepadLeftStickLeft; + location = kSbKeyLocationLeft; + return CreateMoveEventWithKey(window_, key, location, modifiers, + input_vector); + case ABS_Y: { + // Report up and left as positive values. + input_vector.x = -device_info->axis_value[ABS_X]; + input_vector.y = -axis_value; + key = kSbKeyGamepadLeftStickUp; + location = kSbKeyLocationLeft; + return CreateMoveEventWithKey(window_, key, location, modifiers, + input_vector); + } + case ABS_Z: + // Report up and left as positive values. + input_vector.x = -axis_value; + input_vector.y = -device_info->axis_value[ABS_RZ]; + key = kSbKeyGamepadRightStickLeft; + location = kSbKeyLocationRight; + return CreateMoveEventWithKey(window_, key, location, modifiers, + input_vector); + case ABS_RZ: + // Report up and left as positive values. + input_vector.x = -device_info->axis_value[ABS_Z]; + input_vector.y = -axis_value; + key = kSbKeyGamepadRightStickUp; + location = kSbKeyLocationRight; + return CreateMoveEventWithKey(window_, key, location, modifiers, + input_vector); + case ABS_RX: { + key = kSbKeyGamepadLeftTrigger; + location = kSbKeyLocationLeft; + // For trigger buttons, the range is [0..1]. + float trigger_value = (axis_value + 1) / 2; + float previous_trigger_value = (previous_axis_value + 1) / 2; + return CreateAnalogButtonKeyEvent(window_, trigger_value, + previous_trigger_value, key, location, + modifiers, event); + } + case ABS_RY: { + key = kSbKeyGamepadRightTrigger; + location = kSbKeyLocationRight; + // For trigger buttons, the range is [0..1]. + float trigger_value = (axis_value + 1) / 2; + float previous_trigger_value = (previous_axis_value + 1) / 2; + return CreateAnalogButtonKeyEvent(window_, trigger_value, + previous_trigger_value, key, location, + modifiers, event); + } + case ABS_HAT0X: { + float axis_value_for_key = + std::abs(axis_value) > 0.5f ? axis_value : previous_axis_value; + key = (axis_value_for_key < 0) ? kSbKeyGamepadDPadLeft + : kSbKeyGamepadDPadRight; + return CreateAnalogButtonKeyEvent(window_, axis_value, + previous_axis_value, key, location, + modifiers, event); + } + case ABS_HAT0Y: { + float axis_value_for_key = + std::abs(axis_value) > 0.5f ? axis_value : previous_axis_value; + key = (axis_value_for_key < 0) ? kSbKeyGamepadDPadUp + : kSbKeyGamepadDPadDown; + return CreateAnalogButtonKeyEvent(window_, axis_value, + previous_axis_value, key, location, + modifiers, event); + } + case ABS_MT_TRACKING_ID: + if (event.value == -1) { + bool touchpad_position_is_known = IsTouchpadPositionKnown(device_info); + device_info->touchpad_position_state = kTouchPadPositionNone; + if (touchpad_position_is_known) { + // Touch point is released, report last known position as unpress. + input_vector.x = (device_info->axis_value[ABS_MT_POSITION_X] + 1 / 2); + input_vector.y = (device_info->axis_value[ABS_MT_POSITION_Y] + 1 / 2); + return CreateTouchPadEvent(window_, kSbInputEventTypeUnpress, key, + location, modifiers, input_vector); + } + } + return NULL; + case ABS_MT_POSITION_X: { + // If all positions were known before this event, then this event is a + // move. + SbInputEventType type = IsTouchpadPositionKnown(device_info) + ? kSbInputEventTypeMove + : kSbInputEventTypePress; + device_info->touchpad_position_state |= kTouchPadPositionX; + if (IsTouchpadPositionKnown(device_info)) { + // For touchpads, the range is [0..1]. + input_vector.x = (axis_value + 1) / 2; + input_vector.y = (device_info->axis_value[ABS_MT_POSITION_Y] + 1) / 2; + return CreateTouchPadEvent(window_, type, key, location, modifiers, + input_vector); + } + // Not all axis positions are known yet. + return NULL; + } + case ABS_MT_POSITION_Y: { + // If all positions were known before this event, then this event is a + // move. + SbInputEventType type = IsTouchpadPositionKnown(device_info) + ? kSbInputEventTypeMove + : kSbInputEventTypePress; + device_info->touchpad_position_state |= kTouchPadPositionY; + if (IsTouchpadPositionKnown(device_info)) { + // For touchpads, the range is [0..1]. + input_vector.x = (device_info->axis_value[ABS_MT_POSITION_X] + 1) / 2; + input_vector.y = (axis_value + 1) / 2; + return CreateTouchPadEvent(window_, type, key, location, modifiers, + input_vector); + } + // Not all axis positions are known yet. + return NULL; + } + default: + // Ignored event codes. + return NULL; + } + + SB_NOTREACHED(); + return NULL; +} + +DevInput::Event* DevInputImpl::KeyInputToApplicationEvent( + const struct input_event& event, + int modifiers) { + SB_DCHECK(event.type == EV_KEY); SB_DCHECK(event.value <= 2); SbInputData* data = new SbInputData(); SbMemorySet(data, 0, sizeof(*data)); @@ -715,6 +1134,21 @@ &Application::DeleteDestructor<SbInputData>); } +DevInput::Event* DevInputImpl::InputToApplicationEvent( + const struct input_event& event, + InputDeviceInfo* device_info, + int modifiers) { + // EV_ABS events are axis values: Sticks, dpad, and touchpad. + // https://www.kernel.org/doc/Documentation/input/event-codes.txt + switch (event.type) { + case EV_ABS: + return AxisInputToApplicationEvent(event, device_info, modifiers); + case EV_KEY: + return KeyInputToApplicationEvent(event, modifiers); + } + return NULL; +} + } // namespace // static @@ -722,6 +1156,11 @@ return new DevInputImpl(window); } +// static +DevInput* DevInput::Create(SbWindow window, int wake_up_fd) { + return new DevInputImpl(window, wake_up_fd); +} + } // namespace dev_input } // namespace shared } // namespace starboard
diff --git a/src/starboard/shared/linux/dev_input/dev_input.h b/src/starboard/shared/linux/dev_input/dev_input.h index aa8577a..11b94c4 100644 --- a/src/starboard/shared/linux/dev_input/dev_input.h +++ b/src/starboard/shared/linux/dev_input/dev_input.h
@@ -48,6 +48,11 @@ // Creates an instance of DevInput for the given window. static DevInput* Create(SbWindow window); + // Creates an instance of DevInput for the given window. + // The wake_up_fd will be used in WaitForSystemEventWithTimeout() to return + // early when input is available on it. + static DevInput* Create(SbWindow window, int wake_up_fd); + protected: DevInput() {} };
diff --git a/src/starboard/shared/msvc/uwp/toolchain.py b/src/starboard/shared/msvc/uwp/msvc_toolchain.py similarity index 100% rename from src/starboard/shared/msvc/uwp/toolchain.py rename to src/starboard/shared/msvc/uwp/msvc_toolchain.py
diff --git a/src/starboard/shared/starboard/audio_sink/audio_sink_internal.h b/src/starboard/shared/starboard/audio_sink/audio_sink_internal.h index cf40ad5..4aaeef1 100644 --- a/src/starboard/shared/starboard/audio_sink/audio_sink_internal.h +++ b/src/starboard/shared/starboard/audio_sink/audio_sink_internal.h
@@ -42,6 +42,9 @@ #if SB_API_VERSION >= 4 virtual void SetPlaybackRate(double playback_rate) = 0; #endif // SB_API_VERSION >= 4 + + virtual void SetVolume(double volume) = 0; + virtual bool IsType(Type* type) = 0; // The following two functions will be called during application startup and
diff --git a/src/starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc b/src/starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc index 597820a..f6ccd09 100644 --- a/src/starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc +++ b/src/starboard/shared/starboard/audio_sink/stub_audio_sink_type.cc
@@ -44,6 +44,10 @@ } #endif // SB_API_VERSION >= 4 + void SetVolume(double volume) SB_OVERRIDE { + SB_UNREFERENCED_PARAMETER(volume); + } + private: static void* ThreadEntryPoint(void* context); void AudioThreadFunc();
diff --git a/src/starboard/shared/starboard/file_storage/storage_delete_record.cc b/src/starboard/shared/starboard/file_storage/storage_delete_record.cc index 891fbbb..c5c7fe3 100644 --- a/src/starboard/shared/starboard/file_storage/storage_delete_record.cc +++ b/src/starboard/shared/starboard/file_storage/storage_delete_record.cc
@@ -18,14 +18,23 @@ #include "starboard/shared/starboard/file_storage/storage_internal.h" #include "starboard/user.h" -bool SbStorageDeleteRecord(SbUser user) { +bool SbStorageDeleteRecord(SbUser user +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + , + const char* name +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + ) { if (!SbUserIsValid(user)) { return false; } +#if SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION + const char* name = NULL; +#endif // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION + char path[SB_FILE_MAX_PATH]; bool success = starboard::shared::starboard::GetUserStorageFilePath( - user, path, SB_ARRAY_SIZE_INT(path)); + user, name, path, SB_ARRAY_SIZE_INT(path)); if (!success) { return false; }
diff --git a/src/starboard/shared/starboard/file_storage/storage_internal.h b/src/starboard/shared/starboard/file_storage/storage_internal.h index 6bb3362..a56cd34 100644 --- a/src/starboard/shared/starboard/file_storage/storage_internal.h +++ b/src/starboard/shared/starboard/file_storage/storage_internal.h
@@ -18,6 +18,8 @@ #ifndef STARBOARD_SHARED_STARBOARD_FILE_STORAGE_STORAGE_INTERNAL_H_ #define STARBOARD_SHARED_STARBOARD_FILE_STORAGE_STORAGE_INTERNAL_H_ +#include <string> + #include "starboard/file.h" #include "starboard/shared/internal_only.h" #include "starboard/storage.h" @@ -27,6 +29,9 @@ struct SbStorageRecordPrivate { SbUser user; SbFile file; +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + std::string name; +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION }; namespace starboard { @@ -34,6 +39,7 @@ namespace starboard { // Gets the path to the storage file for the given user. static SB_C_INLINE bool GetUserStorageFilePath(SbUser user, + const char* name, char* out_path, int path_size) { bool success = SbUserGetProperty(user, kSbUserPropertyHomeDirectory, out_path, @@ -42,7 +48,12 @@ return false; } - SbStringConcat(out_path, "/.starboard.storage", path_size); + SbStringConcat(out_path, "/.starboard", path_size); + if (name && SbStringGetLength(name) > 0) { + SbStringConcat(out_path, ".", path_size); + SbStringConcat(out_path, name, path_size); + } + SbStringConcat(out_path, ".storage", path_size); return true; } } // namespace starboard
diff --git a/src/starboard/shared/starboard/file_storage/storage_open_record.cc b/src/starboard/shared/starboard/file_storage/storage_open_record.cc index 5be40f4..aaea393 100644 --- a/src/starboard/shared/starboard/file_storage/storage_open_record.cc +++ b/src/starboard/shared/starboard/file_storage/storage_open_record.cc
@@ -19,14 +19,23 @@ #include "starboard/shared/starboard/file_storage/storage_internal.h" #include "starboard/user.h" -SbStorageRecord SbStorageOpenRecord(SbUser user) { +SbStorageRecord SbStorageOpenRecord(SbUser user +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + , + const char* name +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + ) { if (!SbUserIsValid(user)) { return kSbStorageInvalidRecord; } +#if SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION + const char* name = NULL; +#endif // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION + char path[SB_FILE_MAX_PATH]; bool success = starboard::shared::starboard::GetUserStorageFilePath( - user, path, SB_ARRAY_SIZE_INT(path)); + user, name, path, SB_ARRAY_SIZE_INT(path)); if (!success) { return kSbStorageInvalidRecord; } @@ -43,5 +52,10 @@ SB_DCHECK(SbStorageIsValidRecord(result)); result->user = user; result->file = file; +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + if (name) { + result->name = name; + } +#endif return result; }
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc index dbaa49e..9e63967 100644 --- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc +++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
@@ -71,6 +71,7 @@ sink_sample_type_(GetSinkAudioSampleType()), bytes_per_frame_(media::GetBytesPerSample(sink_sample_type_) * channels_), playback_rate_(1.0), + volume_(1.0), paused_(true), seeking_(false), seeking_to_pts_(0), @@ -178,6 +179,14 @@ } #endif // SB_API_VERSION >= 4 +void AudioRendererImpl::SetVolume(double volume) { + SB_DCHECK(BelongsToCurrentThread()); + volume_ = volume; + if (audio_sink_) { + audio_sink_->SetVolume(volume_); + } +} + void AudioRendererImpl::Seek(SbMediaTime seek_to_pts) { SB_DCHECK(BelongsToCurrentThread()); SB_DCHECK(seek_to_pts >= 0); @@ -287,6 +296,7 @@ // support play/pause. audio_sink_->SetPlaybackRate(playback_rate_ > 0.0 ? 1.0 : 0.0); #endif // SB_API_VERSION >= 4 + audio_sink_->SetVolume(volume_); } void AudioRendererImpl::UpdateSourceStatus(int* frames_in_buffer,
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h index d9278da..a469037 100644 --- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h +++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
@@ -60,6 +60,7 @@ #if SB_API_VERSION >= 4 void SetPlaybackRate(double playback_rate) SB_OVERRIDE; #endif // SB_API_VERSION >= 4 + void SetVolume(double volume) SB_OVERRIDE; void Seek(SbMediaTime seek_to_pts) SB_OVERRIDE; bool IsEndOfStreamWritten() const SB_OVERRIDE { @@ -117,6 +118,7 @@ scoped_ptr<AudioResampler> resampler_; AudioTimeStretcher time_stretcher_; double playback_rate_; + double volume_; atomic_bool paused_; atomic_bool seeking_;
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h index 1c192c1..a6ca64b 100644 --- a/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h +++ b/src/starboard/shared/starboard/player/filter/audio_renderer_internal.h
@@ -38,6 +38,7 @@ #if SB_API_VERSION >= 4 virtual void SetPlaybackRate(double playback_rate) = 0; #endif // SB_API_VERSION >= 4 + virtual void SetVolume(double volume) = 0; virtual void Seek(SbMediaTime seek_to_pts) = 0; virtual bool IsEndOfStreamWritten() const = 0; virtual bool IsEndOfStreamPlayed() const = 0;
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc index 76b6e53..c373d90 100644 --- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc +++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.cc
@@ -62,7 +62,11 @@ audio_codec_(audio_codec), drm_system_(drm_system), audio_header_(audio_header), - paused_(false) + paused_(false), +#if SB_API_VERSION >= 4 + playback_rate_(1.0), +#endif // SB_API_VERSION >= 4 + volume_(1.0) #if SB_API_VERSION >= 4 , output_mode_(output_mode), @@ -87,12 +91,12 @@ bounds_ = PlayerWorker::Bounds(); } -bool FilterBasedPlayerWorkerHandler::IsPunchoutMode() const { -#if SB_API_VERSION >= 4 - return (output_mode_ == kSbPlayerOutputModePunchOut); -#else - return true; -#endif // SB_API_VERSION >= 4 +bool FilterBasedPlayerWorkerHandler::IsPunchoutMode() const { +#if SB_API_VERSION >= 4 + return (output_mode_ == kSbPlayerOutputModePunchOut); +#else + return true; +#endif // SB_API_VERSION >= 4 } bool FilterBasedPlayerWorkerHandler::Init( @@ -144,6 +148,11 @@ ::starboard::ScopedLock lock(video_renderer_existence_mutex_); media_components->GetRenderers(&audio_renderer_, &video_renderer_); +#if SB_API_VERSION >= 4 + audio_renderer_->SetPlaybackRate(playback_rate_); +#endif // SB_API_VERSION >= 4 + audio_renderer_->SetVolume(volume_); + job_queue_->Schedule(update_closure_, kUpdateInterval); return true; @@ -276,15 +285,26 @@ bool FilterBasedPlayerWorkerHandler::SetPlaybackRate(double playback_rate) { SB_DCHECK(job_queue_->BelongsToCurrentThread()); + playback_rate_ = playback_rate; + if (!audio_renderer_) { return false; } - audio_renderer_->SetPlaybackRate(playback_rate); + audio_renderer_->SetPlaybackRate(playback_rate_); return true; } #endif // SB_API_VERSION >= 4 +void FilterBasedPlayerWorkerHandler::SetVolume(double volume) { + SB_DCHECK(job_queue_->BelongsToCurrentThread()); + + volume_ = volume; + if (audio_renderer_) { + audio_renderer_->SetVolume(volume_); + } +} + bool FilterBasedPlayerWorkerHandler::SetBounds( const PlayerWorker::Bounds& bounds) { SB_DCHECK(job_queue_->BelongsToCurrentThread()); @@ -328,9 +348,9 @@ player_worker_->UpdateDroppedVideoFrames( video_renderer_->GetDroppedFrames()); - if (IsPunchoutMode()) { - shared::starboard::Application::Get()->HandleFrame( - player_, frame, bounds_.x, bounds_.y, bounds_.width, bounds_.height); + if (IsPunchoutMode()) { + shared::starboard::Application::Get()->HandleFrame( + player_, frame, bounds_.x, bounds_.y, bounds_.width, bounds_.height); } (*player_worker_.*update_media_time_cb_)(audio_renderer_->GetCurrentTime()); @@ -355,10 +375,10 @@ } video_renderer.reset(); - if (IsPunchoutMode()) { - // Clear the video frame as we terminate. - shared::starboard::Application::Get()->HandleFrame( - player_, VideoFrame::CreateEOSFrame(), 0, 0, 0, 0); + if (IsPunchoutMode()) { + // Clear the video frame as we terminate. + shared::starboard::Application::Get()->HandleFrame( + player_, VideoFrame::CreateEOSFrame(), 0, 0, 0, 0); } }
diff --git a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h index 8715ab9..20655ca 100644 --- a/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h +++ b/src/starboard/shared/starboard/player/filter/filter_based_player_worker_handler.h
@@ -68,6 +68,7 @@ #if SB_API_VERSION >= 4 bool SetPlaybackRate(double playback_rate) SB_OVERRIDE; #endif // SB_API_VERSION >= 4 + void SetVolume(double volume) SB_OVERRIDE; bool SetBounds(const PlayerWorker::Bounds& bounds) SB_OVERRIDE; void Stop() SB_OVERRIDE; @@ -98,6 +99,10 @@ scoped_ptr<VideoRenderer> video_renderer_; bool paused_; +#if SB_API_VERSION >= 4 + double playback_rate_; +#endif // SB_API_VERSION >= 4 + double volume_; PlayerWorker::Bounds bounds_; Closure update_closure_;
diff --git a/src/starboard/shared/starboard/player/player_internal.cc b/src/starboard/shared/starboard/player/player_internal.cc index 20268ea..3b46a5d 100644 --- a/src/starboard/shared/starboard/player/player_internal.cc +++ b/src/starboard/shared/starboard/player/player_internal.cc
@@ -133,8 +133,8 @@ #endif // SB_API_VERSION >= 4 void SbPlayerPrivate::SetVolume(double volume) { - SB_UNREFERENCED_PARAMETER(volume); - SB_NOTIMPLEMENTED(); + volume_ = volume; + worker_->SetVolume(volume_); } void SbPlayerPrivate::UpdateMediaTime(SbMediaTime media_time, int ticket) {
diff --git a/src/starboard/shared/starboard/player/player_worker.cc b/src/starboard/shared/starboard/player/player_worker.cc index 38a0a25..24e834c 100644 --- a/src/starboard/shared/starboard/player/player_worker.cc +++ b/src/starboard/shared/starboard/player/player_worker.cc
@@ -270,6 +270,11 @@ } #endif // SB_API_VERSION >= 4 +void PlayerWorker::DoSetVolume(double volume) { + SB_DCHECK(job_queue_->BelongsToCurrentThread()); + handler_->SetVolume(volume); +} + void PlayerWorker::DoStop() { SB_DCHECK(job_queue_->BelongsToCurrentThread());
diff --git a/src/starboard/shared/starboard/player/player_worker.h b/src/starboard/shared/starboard/player/player_worker.h index a1d9333..84be839 100644 --- a/src/starboard/shared/starboard/player/player_worker.h +++ b/src/starboard/shared/starboard/player/player_worker.h
@@ -83,6 +83,8 @@ #if SB_API_VERSION >= 4 virtual bool SetPlaybackRate(double playback_rate) = 0; #endif // SB_API_VERSION >= 4 + virtual void SetVolume(double volume) = 0; + virtual bool SetBounds(const Bounds& bounds) = 0; // Once this function returns, all processing on the Handler and related @@ -147,6 +149,10 @@ } #endif // SB_API_VERSION >= 4 + void SetVolume(double volume) { + job_queue_->Schedule(Bind(&PlayerWorker::DoSetVolume, this, volume)); + } + void UpdateDroppedVideoFrames(int dropped_video_frames) { host_->UpdateDroppedVideoFrames(dropped_video_frames); } @@ -177,6 +183,7 @@ #if SB_API_VERSION >= 4 void DoSetPlaybackRate(double rate); #endif // SB_API_VERSION >= 4 + void DoSetVolume(double volume); void DoStop(); void UpdateDecoderState(SbMediaType type, SbPlayerDecoderState state);
diff --git a/src/starboard/shared/stub/drm_create_system.cc b/src/starboard/shared/stub/drm_create_system.cc index a9a1c84..64139a9 100644 --- a/src/starboard/shared/stub/drm_create_system.cc +++ b/src/starboard/shared/stub/drm_create_system.cc
@@ -14,6 +14,24 @@ #include "starboard/drm.h" +#if SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + +SbDrmSystem SbDrmCreateSystem( + const char* key_system, + void* context, + SbDrmSessionUpdateRequestFunc update_request_callback, + SbDrmSessionUpdatedFunc session_updated_callback, + SbDrmSessionKeyStatusesChangedFunc key_statuses_changed_callback) { + SB_UNREFERENCED_PARAMETER(context); + SB_UNREFERENCED_PARAMETER(key_system); + SB_UNREFERENCED_PARAMETER(update_request_callback); + SB_UNREFERENCED_PARAMETER(session_updated_callback); + SB_UNREFERENCED_PARAMETER(key_statuses_changed_callback); + return kSbDrmSystemInvalid; +} + +#else // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION + SbDrmSystem SbDrmCreateSystem( const char* key_system, void* context, @@ -25,3 +43,5 @@ SB_UNREFERENCED_PARAMETER(session_updated_callback); return kSbDrmSystemInvalid; } + +#endif // SB_API_VERSION >= SB_DRM_KEY_STATUSES_UPDATE_SUPPORT_API_VERSION
diff --git a/src/starboard/shared/stub/storage_delete_record.cc b/src/starboard/shared/stub/storage_delete_record.cc index ba13cd1..a669054 100644 --- a/src/starboard/shared/stub/storage_delete_record.cc +++ b/src/starboard/shared/stub/storage_delete_record.cc
@@ -14,6 +14,11 @@ #include "starboard/storage.h" -bool SbStorageDeleteRecord(SbUser /*user*/) { +bool SbStorageDeleteRecord(SbUser /*user*/ +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + , + const char* /*name*/ +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + ) { return false; }
diff --git a/src/starboard/shared/stub/storage_open_record.cc b/src/starboard/shared/stub/storage_open_record.cc index bcd5f3d..b0f503e 100644 --- a/src/starboard/shared/stub/storage_open_record.cc +++ b/src/starboard/shared/stub/storage_open_record.cc
@@ -14,6 +14,11 @@ #include "starboard/storage.h" -SbStorageRecord SbStorageOpenRecord(SbUser /*user*/) { +SbStorageRecord SbStorageOpenRecord(SbUser /*user*/ +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + , + const char* /*name*/ +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + ) { return kSbStorageInvalidRecord; }
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/shared/test_webapi_extension/my_new_enum.idl similarity index 76% copy from src/starboard/win/lib/atomic_public.h copy to src/starboard/shared/test_webapi_extension/my_new_enum.idl index be4e805..1a6f73c 100644 --- a/src/starboard/win/lib/atomic_public.h +++ b/src/starboard/shared/test_webapi_extension/my_new_enum.idl
@@ -12,9 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ -#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ - -#include "starboard/shared/win32/atomic_public.h" - -#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +enum MyNewEnum { + "apples", + "oranges", + "peaches" +};
diff --git a/src/starboard/shared/test_webapi_extension/my_new_interface.cc b/src/starboard/shared/test_webapi_extension/my_new_interface.cc new file mode 100644 index 0000000..18af5b4 --- /dev/null +++ b/src/starboard/shared/test_webapi_extension/my_new_interface.cc
@@ -0,0 +1,29 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "starboard/shared/test_webapi_extension/my_new_interface.h" + +namespace cobalt { +namespace webapi_extension { + +MyNewInterface::MyNewInterface(const scoped_refptr<dom::Window>& window) { + UNREFERENCED_PARAMETER(window); + // Provide an initial value for the enum. + enum_value_ = kMyNewEnumApples; +} + +MyNewInterface::~MyNewInterface() OVERRIDE {} + +} // namespace webapi_extension +} // namespace cobalt
diff --git a/src/starboard/shared/test_webapi_extension/my_new_interface.h b/src/starboard/shared/test_webapi_extension/my_new_interface.h new file mode 100644 index 0000000..eb30d4e --- /dev/null +++ b/src/starboard/shared/test_webapi_extension/my_new_interface.h
@@ -0,0 +1,55 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef STARBOARD_SHARED_TEST_WEBAPI_EXTENSION_MY_NEW_INTERFACE_H_ +#define STARBOARD_SHARED_TEST_WEBAPI_EXTENSION_MY_NEW_INTERFACE_H_ + +#include <string> + +#include "cobalt/dom/window.h" +#include "cobalt/script/wrappable.h" +#include "starboard/shared/test_webapi_extension/my_new_enum.h" + +namespace cobalt { +namespace webapi_extension { + +class MyNewInterface : public script::Wrappable { + public: + explicit MyNewInterface(const scoped_refptr<dom::Window>& window); + + const std::string& foo() const { return foo_; } + void set_foo(const std::string& value) { foo_ = value; } + + void SetMyNewEnum(MyNewEnum value) { enum_value_ = value; } + MyNewEnum GetMyNewEnum() const { return enum_value_; } + + // All types derived from script::Wrappable must have this annotation. + DEFINE_WRAPPABLE_TYPE(MyNewInterface); + + private: + // Since script::Wrappable inherits from base::RefCounted<>, we make the + // destructor private. + ~MyNewInterface() OVERRIDE; + + std::string foo_; + + MyNewEnum enum_value_; + + DISALLOW_COPY_AND_ASSIGN(MyNewInterface); +}; + +} // namespace webapi_extension +} // namespace cobalt + +#endif // STARBOARD_SHARED_TEST_WEBAPI_EXTENSION_MY_NEW_INTERFACE_H_
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/shared/test_webapi_extension/my_new_interface.idl similarity index 76% copy from src/starboard/win/lib/atomic_public.h copy to src/starboard/shared/test_webapi_extension/my_new_interface.idl index be4e805..3e64764 100644 --- a/src/starboard/win/lib/atomic_public.h +++ b/src/starboard/shared/test_webapi_extension/my_new_interface.idl
@@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ -#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +interface MyNewInterface { + attribute DOMString foo; -#include "starboard/shared/win32/atomic_public.h" - -#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ + void SetMyNewEnum(MyNewEnum value); + MyNewEnum GetMyNewEnum(); +};
diff --git a/src/starboard/shared/test_webapi_extension/test_webapi_extension.gypi b/src/starboard/shared/test_webapi_extension/test_webapi_extension.gypi new file mode 100644 index 0000000..74de31a --- /dev/null +++ b/src/starboard/shared/test_webapi_extension/test_webapi_extension.gypi
@@ -0,0 +1,29 @@ +# Copyright 2017 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 file can be included from a platform's gyp_configuration.gypi file to +# setup the test custom webapi_extension defined in this directory to be +# injected into that platform. +{ + 'variables': { + 'cobalt_webapi_extension_source_idl_files': [ + 'my_new_interface.idl' + ], + 'cobalt_webapi_extension_generated_header_idl_files': [ + 'my_new_enum.idl' + ], + 'cobalt_webapi_extension_gyp_target': + '<(DEPTH)/starboard/shared/test_webapi_extension/webapi_extension.gyp:cobalt_test_webapi_extension', + }, +} \ No newline at end of file
diff --git a/src/starboard/shared/test_webapi_extension/webapi_extension.cc b/src/starboard/shared/test_webapi_extension/webapi_extension.cc new file mode 100644 index 0000000..06bb89c --- /dev/null +++ b/src/starboard/shared/test_webapi_extension/webapi_extension.cc
@@ -0,0 +1,38 @@ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "cobalt/browser/webapi_extension.h" + +#include "base/compiler_specific.h" +#include "cobalt/script/global_environment.h" +#include "starboard/shared/test_webapi_extension/my_new_interface.h" + +namespace cobalt { +namespace browser { + +base::optional<std::string> GetWebAPIExtensionObjectPropertyName() { + return std::string("myInterface"); +} + +scoped_refptr<script::Wrappable> CreateWebAPIExtensionObject( + const scoped_refptr<dom::Window>& window, + script::GlobalEnvironment* global_environment) { + UNREFERENCED_PARAMETER(global_environment); + + return scoped_refptr<script::Wrappable>( + new webapi_extension::MyNewInterface(window)); +} + +} // namespace browser +} // namespace cobalt
diff --git a/src/starboard/shared/test_webapi_extension/webapi_extension.gyp b/src/starboard/shared/test_webapi_extension/webapi_extension.gyp new file mode 100644 index 0000000..5c238e0 --- /dev/null +++ b/src/starboard/shared/test_webapi_extension/webapi_extension.gyp
@@ -0,0 +1,35 @@ +# Copyright 2017 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. +{ + 'targets': [ + { + 'target_name': 'cobalt_test_webapi_extension', + 'type': 'static_library', + + # List of all source files and header files needed to support the IDL + # definitions. + 'sources': [ + 'my_new_interface.h', + 'my_new_interface.cc', + 'webapi_extension.cc', + ], + + 'dependencies': [ + '<(DEPTH)/cobalt/dom/dom.gyp:dom', + '<(DEPTH)/cobalt/script/script.gyp:script', + '<(DEPTH)/base/base.gyp:base', + ], + }, + ], +}
diff --git a/src/starboard/shared/uwp/cobalt/xhr_modify_headers.cc b/src/starboard/shared/uwp/cobalt/xhr_modify_headers.cc index eaf8bd3..6f71b80 100644 --- a/src/starboard/shared/uwp/cobalt/xhr_modify_headers.cc +++ b/src/starboard/shared/uwp/cobalt/xhr_modify_headers.cc
@@ -98,7 +98,7 @@ WebTokenRequestResult^ RequestToken(WebTokenRequest^ request) { using starboard::shared::uwp::WaitForResult; - IAsyncOperation<WebTokenRequestResult ^> ^ request_operation = nullptr; + IAsyncOperation<WebTokenRequestResult^>^ request_operation = nullptr; base::WaitableEvent request_operation_set(false, false); // Ensure WebAuthenticationCoreManager::RequestTokenAsync is called on the // UI thread, since documentation states that "This method cannot be called
diff --git a/src/starboard/shared/uwp/starboard_platform.gypi b/src/starboard/shared/uwp/starboard_platform.gypi index ee1b5bd..85f0f72 100644 --- a/src/starboard/shared/uwp/starboard_platform.gypi +++ b/src/starboard/shared/uwp/starboard_platform.gypi
@@ -22,6 +22,8 @@ 'system_clear_platform_error.cc', 'system_get_device_type.cc', 'system_get_property.cc', + 'system_get_total_cpu_memory.cc', + 'system_get_used_cpu_memory.cc', 'system_raise_platform_error.cc', 'window_create.cc', 'window_destroy.cc',
diff --git a/src/starboard/shared/uwp/system_get_device_type.cc b/src/starboard/shared/uwp/system_get_device_type.cc index 81179ca..33ce323 100644 --- a/src/starboard/shared/uwp/system_get_device_type.cc +++ b/src/starboard/shared/uwp/system_get_device_type.cc
@@ -23,7 +23,7 @@ using Windows::System::Profile::AnalyticsVersionInfo; SbSystemDeviceType SbSystemGetDeviceType() { - AnalyticsVersionInfo ^ version_info = AnalyticsInfo::VersionInfo; + AnalyticsVersionInfo^ version_info = AnalyticsInfo::VersionInfo; std::string family = starboard::shared::win32::platformStringToString( version_info->DeviceFamily);
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/shared/uwp/system_get_total_cpu_memory.cc similarity index 76% copy from src/starboard/win/lib/atomic_public.h copy to src/starboard/shared/uwp/system_get_total_cpu_memory.cc index be4e805..293fd7d 100644 --- a/src/starboard/win/lib/atomic_public.h +++ b/src/starboard/shared/uwp/system_get_total_cpu_memory.cc
@@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ -#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +#include "starboard/system.h" -#include "starboard/shared/win32/atomic_public.h" +using Windows::System::MemoryManager; -#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +int64_t SbSystemGetTotalCPUMemory() { + return static_cast<int64_t>(MemoryManager::AppMemoryUsageLimit); +}
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/shared/uwp/system_get_used_cpu_memory.cc similarity index 76% copy from src/starboard/win/lib/atomic_public.h copy to src/starboard/shared/uwp/system_get_used_cpu_memory.cc index be4e805..adc9c0d 100644 --- a/src/starboard/win/lib/atomic_public.h +++ b/src/starboard/shared/uwp/system_get_used_cpu_memory.cc
@@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ -#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +#include "starboard/system.h" -#include "starboard/shared/win32/atomic_public.h" +using Windows::System::MemoryManager; -#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +int64_t SbSystemGetUsedCPUMemory() { + return static_cast<int64_t>(MemoryManager::AppMemoryUsage); +}
diff --git a/src/starboard/shared/win32/audio_decoder.cc b/src/starboard/shared/win32/audio_decoder.cc index d6749f2..879202c 100644 --- a/src/starboard/shared/win32/audio_decoder.cc +++ b/src/starboard/shared/win32/audio_decoder.cc
@@ -56,19 +56,24 @@ }; AudioDecoder::AudioDecoder(SbMediaAudioCodec audio_codec, - const SbMediaAudioHeader& audio_header) - : sample_type_(kSbMediaAudioSampleTypeFloat32), - stream_ended_(false), - audio_codec_(audio_codec), - audio_header_(audio_header) { + const SbMediaAudioHeader& audio_header, + SbDrmSystem drm_system) + : audio_codec_(audio_codec), + audio_header_(audio_header), + drm_system_(drm_system), + sample_type_(kSbMediaAudioSampleTypeFloat32), + stream_ended_(false) { SB_DCHECK(audio_codec == kSbMediaAudioCodecAac); decoder_impl_ = AbstractWin32AudioDecoder::Create( - audio_codec_, GetStorageType(), GetSampleType(), audio_header_); + audio_codec_, GetStorageType(), GetSampleType(), audio_header_, + drm_system_); decoder_thread_.reset(new AudioDecoderThread(decoder_impl_.get(), this)); callback_scheduler_.reset(new CallbackScheduler()); } AudioDecoder::~AudioDecoder() { + SB_DCHECK(thread_checker_.CalledOnValidThread()); + decoder_thread_.reset(nullptr); decoder_impl_.reset(nullptr); callback_scheduler_.reset(nullptr); @@ -76,7 +81,9 @@ void AudioDecoder::Decode(const scoped_refptr<InputBuffer>& input_buffer, const Closure& consumed_cb) { + SB_DCHECK(thread_checker_.CalledOnValidThread()); SB_DCHECK(input_buffer); + callback_scheduler_->SetCallbackOnce(consumed_cb); callback_scheduler_->OnCallbackSignaled(); const bool can_take_more_data = decoder_thread_->QueueInput(input_buffer); @@ -91,22 +98,29 @@ } void AudioDecoder::WriteEndOfStream() { + SB_DCHECK(thread_checker_.CalledOnValidThread()); + ::starboard::ScopedLock lock(mutex_); stream_ended_ = true; decoder_thread_->QueueEndOfStream(); } scoped_refptr<AudioDecoder::DecodedAudio> AudioDecoder::Read() { + SB_DCHECK(thread_checker_.CalledOnValidThread()); + DecodedAudioPtr data = decoded_data_.PopFront(); SB_DCHECK(data); return data; } void AudioDecoder::Reset() { + SB_DCHECK(thread_checker_.CalledOnValidThread()); + decoder_thread_.reset(nullptr); decoder_impl_.reset(nullptr); decoder_impl_ = AbstractWin32AudioDecoder::Create( - audio_codec_, GetStorageType(), GetSampleType(), audio_header_); + audio_codec_, GetStorageType(), GetSampleType(), audio_header_, + drm_system_); decoder_thread_.reset(new AudioDecoderThread(decoder_impl_.get(), this)); decoded_data_.Clear(); stream_ended_ = false; @@ -114,14 +128,20 @@ } SbMediaAudioSampleType AudioDecoder::GetSampleType() const { + SB_DCHECK(thread_checker_.CalledOnValidThread()); + return sample_type_; } int AudioDecoder::GetSamplesPerSecond() const { + SB_DCHECK(thread_checker_.CalledOnValidThread()); + return audio_header_.samples_per_second; } void AudioDecoder::Initialize(const Closure& output_cb) { + SB_DCHECK(thread_checker_.CalledOnValidThread()); + SB_DCHECK(output_cb.is_valid()); SB_DCHECK(!output_cb_.is_valid()); output_cb_ = output_cb;
diff --git a/src/starboard/shared/win32/audio_decoder.h b/src/starboard/shared/win32/audio_decoder.h index f036287..5bd335c 100644 --- a/src/starboard/shared/win32/audio_decoder.h +++ b/src/starboard/shared/win32/audio_decoder.h
@@ -18,11 +18,13 @@ #include "starboard/common/ref_counted.h" #include "starboard/common/scoped_ptr.h" #include "starboard/configuration.h" +#include "starboard/drm.h" #include "starboard/media.h" #include "starboard/shared/internal_only.h" #include "starboard/shared/starboard/player/decoded_audio_internal.h" #include "starboard/shared/starboard/player/filter/audio_decoder_internal.h" #include "starboard/shared/starboard/player/job_queue.h" +#include "starboard/shared/starboard/thread_checker.h" #include "starboard/shared/win32/atomic_queue.h" #include "starboard/shared/win32/audio_decoder_thread.h" #include "starboard/shared/win32/media_common.h" @@ -32,16 +34,14 @@ namespace shared { namespace win32 { -using JobQueue = ::starboard::shared::starboard::player::JobQueue; -using JobOwner = JobQueue::JobOwner; - class AudioDecoder : public ::starboard::shared::starboard::player::filter::AudioDecoder, - private JobOwner, + private ::starboard::shared::starboard::player::JobQueue::JobOwner, private AudioDecodedCallback { public: AudioDecoder(SbMediaAudioCodec audio_codec, - const SbMediaAudioHeader& audio_header); + const SbMediaAudioHeader& audio_header, + SbDrmSystem drm_system); ~AudioDecoder() SB_OVERRIDE; void Decode(const scoped_refptr<InputBuffer>& input_buffer, @@ -60,9 +60,13 @@ private: class CallbackScheduler; - SbMediaAudioHeader audio_header_; - SbMediaAudioSampleType sample_type_; + + ::starboard::shared::starboard::ThreadChecker thread_checker_; + SbMediaAudioCodec audio_codec_; + SbMediaAudioHeader audio_header_; + SbDrmSystem drm_system_; + SbMediaAudioSampleType sample_type_; bool stream_ended_; AtomicQueue<DecodedAudioPtr> decoded_data_; @@ -71,7 +75,7 @@ scoped_ptr<AudioDecoderThread> decoder_thread_; Closure output_cb_; - ::starboard::Mutex mutex_; + Mutex mutex_; }; } // namespace win32
diff --git a/src/starboard/shared/win32/audio_sink.cc b/src/starboard/shared/win32/audio_sink.cc index c5d8de2..5967211 100644 --- a/src/starboard/shared/win32/audio_sink.cc +++ b/src/starboard/shared/win32/audio_sink.cc
@@ -72,6 +72,10 @@ ScopedLock lock(mutex_); playback_rate_ = playback_rate; } + void SetVolume(double volume) SB_OVERRIDE { + ScopedLock lock(mutex_); + volume_ = volume; + } private: static void* ThreadEntryPoint(void* context); @@ -99,6 +103,7 @@ ::starboard::Mutex mutex_; bool destroying_; double playback_rate_; + double volume_; }; XAudioAudioSink::XAudioAudioSink( @@ -118,7 +123,8 @@ frame_buffers_size_in_frames_(frame_buffers_size_in_frames), wfx_(wfx), destroying_(false), - playback_rate_(1.0) { + playback_rate_(1.0), + volume_(1.0) { // TODO: Check MaxFrequencyRatio CHECK_HRESULT_OK( type_->x_audio2_->CreateSourceVoice(&source_voice_, &wfx, 0, @@ -187,6 +193,7 @@ int frames_in_buffer, offset_in_frames; bool is_playing, is_eos_reached; bool is_playback_rate_zero; + // TODO: Support |volume_| here as well... { ScopedLock lock(mutex_); is_playback_rate_zero = playback_rate_ == 0.0;
diff --git a/src/starboard/shared/win32/decode_target_internal.cc b/src/starboard/shared/win32/decode_target_internal.cc index 70b8e32..8188621 100644 --- a/src/starboard/shared/win32/decode_target_internal.cc +++ b/src/starboard/shared/win32/decode_target_internal.cc
@@ -26,6 +26,7 @@ #include "third_party/angle/include/EGL/egl.h" #include "third_party/angle/include/EGL/eglext.h" #include "third_party/angle/include/GLES2/gl2.h" +#include "third_party/angle/include/GLES2/gl2ext.h" using Microsoft::WRL::ComPtr; using starboard::shared::win32::VideoFramePtr; @@ -73,24 +74,24 @@ SbDecodeTargetInfoPlane* planeY = &(info.planes[kSbDecodeTargetPlaneY]); SbDecodeTargetInfoPlane* planeUV = &(info.planes[kSbDecodeTargetPlaneUV]); - planeY->width = texture_desc.Width; - planeY->height = texture_desc.Height; + planeY->width = info.width; + planeY->height = info.height; planeY->content_region.left = 0; - planeY->content_region.top = 0; - planeY->content_region.right = texture_desc.Width; - planeY->content_region.bottom = texture_desc.Height; + planeY->content_region.top = info.height; + planeY->content_region.right = frame->width(); + planeY->content_region.bottom = info.height - frame->height(); - planeUV->width = texture_desc.Width / 2; - planeUV->height = texture_desc.Height / 2; - planeUV->content_region.left = 0; - planeUV->content_region.top = 0; - planeUV->content_region.right = texture_desc.Width / 2; - planeUV->content_region.bottom = texture_desc.Height / 2; + planeUV->width = info.width / 2; + planeUV->height = info.height / 2; + planeUV->content_region.left = planeY->content_region.left / 2; + planeUV->content_region.top = planeY->content_region.top / 2; + planeUV->content_region.right = planeY->content_region.right / 2; + planeUV->content_region.bottom = planeY->content_region.bottom / 2; EGLint luma_texture_attributes[] = {EGL_WIDTH, - static_cast<EGLint>(texture_desc.Width), + static_cast<EGLint>(info.width), EGL_HEIGHT, - static_cast<EGLint>(texture_desc.Height), + static_cast<EGLint>(info.height), EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, EGL_TEXTURE_FORMAT, @@ -119,16 +120,16 @@ dxgi_buffer.GetAddressOf()); SB_DCHECK(SUCCEEDED(hr)); - EGLSurface surface = eglCreatePbufferFromClientBuffer( - display, EGL_D3D_TEXTURE_ANGLE, d3texture.Get(), config, - luma_texture_attributes); + surface[0] = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE, + d3texture.Get(), config, + luma_texture_attributes); - SB_DCHECK(surface != EGL_NO_SURFACE); + SB_DCHECK(surface[0] != EGL_NO_SURFACE); glBindTexture(GL_TEXTURE_2D, gl_textures[0]); SB_DCHECK(glGetError() == GL_NO_ERROR); - ok = eglBindTexImage(display, surface, EGL_BACK_BUFFER); + ok = eglBindTexImage(display, surface[0], EGL_BACK_BUFFER); SB_DCHECK(ok); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -136,6 +137,7 @@ planeY->texture = gl_textures[0]; planeY->gl_texture_target = GL_TEXTURE_2D; + planeY->gl_texture_format = GL_RED_EXT; // This tells ANGLE that the texture it creates should draw // the chroma channel on R8G8. @@ -145,24 +147,24 @@ EGLint chroma_texture_attributes[] = { EGL_WIDTH, - static_cast<EGLint>(texture_desc.Width) / 2, + static_cast<EGLint>(info.width) / 2, EGL_HEIGHT, - static_cast<EGLint>(texture_desc.Height) / 2, + static_cast<EGLint>(info.height) / 2, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_NONE}; - surface = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE, - d3texture.Get(), config, - chroma_texture_attributes); + surface[1] = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE, + d3texture.Get(), config, + chroma_texture_attributes); - SB_DCHECK(surface != EGL_NO_SURFACE); + SB_DCHECK(surface[1] != EGL_NO_SURFACE); glBindTexture(GL_TEXTURE_2D, gl_textures[1]); SB_DCHECK(glGetError() == GL_NO_ERROR); - ok = eglBindTexImage(display, surface, EGL_BACK_BUFFER); + ok = eglBindTexImage(display, surface[1], EGL_BACK_BUFFER); SB_DCHECK(ok); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -170,6 +172,7 @@ planeUV->texture = gl_textures[1]; planeUV->gl_texture_target = GL_TEXTURE_2D; + planeUV->gl_texture_format = GL_RG_EXT; hr = d3texture->SetPrivateData(kCobaltDxgiBuffer, 0, nullptr); SB_DCHECK(SUCCEEDED(hr)); @@ -178,6 +181,14 @@ SbDecodeTargetPrivate::~SbDecodeTargetPrivate() { glDeleteTextures(1, &(info.planes[kSbDecodeTargetPlaneY].texture)); glDeleteTextures(1, &(info.planes[kSbDecodeTargetPlaneUV].texture)); + + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + + eglReleaseTexImage(display, surface[0], EGL_BACK_BUFFER); + eglDestroySurface(display, surface[0]); + + eglReleaseTexImage(display, surface[1], EGL_BACK_BUFFER); + eglDestroySurface(display, surface[1]); } void SbDecodeTargetRelease(SbDecodeTarget decode_target) {
diff --git a/src/starboard/shared/win32/decode_target_internal.h b/src/starboard/shared/win32/decode_target_internal.h index 6204200..81aa66e 100644 --- a/src/starboard/shared/win32/decode_target_internal.h +++ b/src/starboard/shared/win32/decode_target_internal.h
@@ -23,6 +23,9 @@ // Publicly accessible information about the decode target. SbDecodeTargetInfo info; ::starboard::shared::win32::VideoFramePtr frame; + // EGLSurface is defined as void* in "third_party/angle/include/EGL/egl.h". + // Use void* directly here to avoid `egl.h` being included broadly. + void* surface[2]; explicit SbDecodeTargetPrivate(starboard::shared::win32::VideoFramePtr frame); ~SbDecodeTargetPrivate(); };
diff --git a/src/starboard/shared/win32/gyp_configuration.py b/src/starboard/shared/win32/gyp_configuration.py index 0bf0e26..93f92f1 100644 --- a/src/starboard/shared/win32/gyp_configuration.py +++ b/src/starboard/shared/win32/gyp_configuration.py
@@ -85,5 +85,5 @@ def GetToolchain(self): sys.path.append( os.path.join(STARBOARD_ROOT, 'shared', 'msvc', 'uwp')) - from toolchain import MSVCUWPToolchain # pylint: disable=g-import-not-at-top,g-bad-import-order + from msvc_toolchain import MSVCUWPToolchain # pylint: disable=g-import-not-at-top,g-bad-import-order return MSVCUWPToolchain()
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/shared/win32/media_is_output_protected.cc similarity index 76% copy from src/starboard/win/lib/atomic_public.h copy to src/starboard/shared/win32/media_is_output_protected.cc index be4e805..73d2f07 100644 --- a/src/starboard/win/lib/atomic_public.h +++ b/src/starboard/shared/win32/media_is_output_protected.cc
@@ -1,20 +1,21 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ -#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ - -#include "starboard/shared/win32/atomic_public.h" - -#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +// Copyright 2017 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "starboard/media.h" + +bool SbMediaIsOutputProtected() { + // Pretend that HDCP is always on. + // TODO: Fix this with proper HDCP query. + return true; +}
diff --git a/src/starboard/shared/win32/player_components_impl.cc b/src/starboard/shared/win32/player_components_impl.cc index cc86d10..fa2c4af 100644 --- a/src/starboard/shared/win32/player_components_impl.cc +++ b/src/starboard/shared/win32/player_components_impl.cc
@@ -35,9 +35,13 @@ using VideoRendererImpl = ::starboard::shared::win32::VideoRendererImpl; AudioDecoderImpl* audio_decoder = new AudioDecoderImpl( - audio_parameters.audio_codec, audio_parameters.audio_header); + audio_parameters.audio_codec, audio_parameters.audio_header, + audio_parameters.drm_system); - VideoDecoderImpl* video_decoder = new VideoDecoderImpl(video_parameters); + VideoDecoderImpl* video_decoder = new VideoDecoderImpl( + video_parameters.video_codec, video_parameters.output_mode, + video_parameters.decode_target_graphics_context_provider, + video_parameters.drm_system); AudioRendererImpl* audio_renderer = new AudioRendererImpl(scoped_ptr<AudioDecoder>(audio_decoder).Pass(),
diff --git a/src/starboard/shared/win32/video_decoder.cc b/src/starboard/shared/win32/video_decoder.cc index 40fd85d..0a08c9a 100644 --- a/src/starboard/shared/win32/video_decoder.cc +++ b/src/starboard/shared/win32/video_decoder.cc
@@ -24,17 +24,24 @@ namespace shared { namespace win32 { -VideoDecoder::VideoDecoder(const VideoParameters& params) - : video_codec_(params.video_codec), +VideoDecoder::VideoDecoder(SbMediaVideoCodec video_codec, + SbPlayerOutputMode output_mode, + SbDecodeTargetGraphicsContextProvider* + decode_target_graphics_context_provider, + SbDrmSystem drm_system) + : video_codec_(video_codec), + drm_system_(drm_system), host_(NULL), - output_mode_(params.output_mode), + output_mode_(output_mode), decode_target_graphics_context_provider_( - params.decode_target_graphics_context_provider) { - impl_ = AbstractWin32VideoDecoder::Create(video_codec_); + decode_target_graphics_context_provider) { + impl_ = AbstractWin32VideoDecoder::Create(video_codec_, drm_system_); video_decoder_thread_.reset(new VideoDecoderThread(impl_.get(), this)); } VideoDecoder::~VideoDecoder() { + SB_DCHECK(thread_checker_.CalledOnValidThread()); + video_decoder_thread_.reset(nullptr); impl_.reset(nullptr); } @@ -71,7 +78,7 @@ SB_DCHECK(host_); video_decoder_thread_.reset(nullptr); impl_.reset(nullptr); - impl_ = AbstractWin32VideoDecoder::Create(video_codec_); + impl_ = AbstractWin32VideoDecoder::Create(video_codec_, drm_system_); video_decoder_thread_.reset(new VideoDecoderThread(impl_.get(), this)); } @@ -83,7 +90,7 @@ } void VideoDecoder::OnVideoDecoded(VideoFramePtr data) { - Status sts = data->IsEndOfStream() ? kBufferFull : kNeedMoreInput; + Status sts = (data && data->IsEndOfStream()) ? kBufferFull : kNeedMoreInput; host_->OnDecoderStatusUpdate(sts, data); }
diff --git a/src/starboard/shared/win32/video_decoder.h b/src/starboard/shared/win32/video_decoder.h index 1fd2bfa..5d3734b 100644 --- a/src/starboard/shared/win32/video_decoder.h +++ b/src/starboard/shared/win32/video_decoder.h
@@ -18,6 +18,7 @@ #include "starboard/common/ref_counted.h" #include "starboard/common/scoped_ptr.h" #include "starboard/configuration.h" +#include "starboard/drm.h" #include "starboard/shared/starboard/player/filter/player_components.h" #include "starboard/shared/starboard/player/filter/video_decoder_internal.h" #include "starboard/shared/starboard/player/input_buffer_internal.h" @@ -38,7 +39,11 @@ private ::starboard::shared::starboard::player::JobQueue::JobOwner, private VideoDecodedCallback { public: - explicit VideoDecoder(const VideoParameters& params); + VideoDecoder(SbMediaVideoCodec video_codec, + SbPlayerOutputMode output_mode, + SbDecodeTargetGraphicsContextProvider* + decode_target_graphics_context_provider, + SbDrmSystem drm_system); ~VideoDecoder() SB_OVERRIDE; void SetHost(Host* host) SB_OVERRIDE; @@ -53,22 +58,23 @@ void OnVideoDecoded(VideoFramePtr data) SB_OVERRIDE; private: + ::starboard::shared::starboard::ThreadChecker thread_checker_; + // These variables will be initialized inside ctor or SetHost() and will not // be changed during the life time of this class. const SbMediaVideoCodec video_codec_; + SbDrmSystem drm_system_; Host* host_; // Decode-to-texture related state. - SbPlayerOutputMode output_mode_; - - SbDecodeTargetGraphicsContextProvider* + const SbPlayerOutputMode output_mode_; + SbDecodeTargetGraphicsContextProvider* const decode_target_graphics_context_provider_; scoped_ptr<AbstractWin32VideoDecoder> impl_; AtomicQueue<VideoFramePtr> decoded_data_; - ::starboard::Mutex mutex_; + Mutex mutex_; scoped_ptr<VideoDecoderThread> video_decoder_thread_; - ::starboard::shared::starboard::ThreadChecker thread_checker_; }; } // namespace win32
diff --git a/src/starboard/shared/win32/video_decoder_thread.cc b/src/starboard/shared/win32/video_decoder_thread.cc index 64a7b2e..d2f8ba2 100644 --- a/src/starboard/shared/win32/video_decoder_thread.cc +++ b/src/starboard/shared/win32/video_decoder_thread.cc
@@ -102,6 +102,7 @@ if (number_written > 0) { processing_elements_.fetch_sub(static_cast<int32_t>(number_written)); work_done = true; + callback_->OnVideoDecoded(NULL); } while (VideoFramePtr decoded_datum =
diff --git a/src/starboard/shared/win32/win32_audio_decoder.cc b/src/starboard/shared/win32/win32_audio_decoder.cc index 0b85f30..4142764 100644 --- a/src/starboard/shared/win32/win32_audio_decoder.cc +++ b/src/starboard/shared/win32/win32_audio_decoder.cc
@@ -103,18 +103,19 @@ }; class AbstractWin32AudioDecoderImpl : public AbstractWin32AudioDecoder, - public MediaBufferConsumerInterface { + public MediaBufferConsumerInterface { public: AbstractWin32AudioDecoderImpl(SbMediaAudioCodec codec, - SbMediaAudioFrameStorageType audio_frame_fmt, - SbMediaAudioSampleType sample_type, - const SbMediaAudioHeader& audio_header) + SbMediaAudioFrameStorageType audio_frame_fmt, + SbMediaAudioSampleType sample_type, + const SbMediaAudioHeader& audio_header, + SbDrmSystem drm_system) : codec_(codec), audio_frame_fmt_(audio_frame_fmt), sample_type_(sample_type), audio_header_(audio_header) { MediaBufferConsumerInterface* media_cb = this; - impl_.reset(new DecoderImpl("audio", media_cb)); + impl_.reset(new DecoderImpl("audio", media_cb, drm_system)); EnsureAudioDecoderCreated(); } @@ -151,6 +152,8 @@ media_buffer->Unlock(); } + void OnNewOutputType(const ComPtr<IMFMediaType>& /*type*/) override {} + ComPtr<IMFMediaType> Configure(IMFTransform* decoder) { ComPtr<IMFMediaType> input_type; HRESULT hr = MFCreateMediaType(&input_type); @@ -209,7 +212,6 @@ SB_DCHECK(decoder); impl_->set_decoder(decoder); - impl_->ActivateDecryptor(media_type); // TODO: MFWinAudioFormat_PCM? ComPtr<IMFMediaType> output_type = @@ -234,17 +236,40 @@ const int size = buff.size(); const int64_t media_timestamp = buff.pts(); - // These parameters are used for decryption. But these are not used right - // now and so remain empty. std::vector<uint8_t> key_id; std::vector<uint8_t> iv; std::vector<Subsample> subsamples; + const SbDrmSampleInfo* drm_info = buff.drm_info(); + + if (drm_info != NULL && drm_info->initialization_vector_size != 0) { + key_id.assign(drm_info->identifier, + drm_info->identifier + drm_info->identifier_size); + iv.assign(drm_info->initialization_vector, + drm_info->initialization_vector + + drm_info->initialization_vector_size); + subsamples.reserve(drm_info->subsample_count); + for (int32_t i = 0; i < drm_info->subsample_count; ++i) { + Subsample subsample = { + static_cast<uint32_t>( + drm_info->subsample_mapping[i].clear_byte_count), + static_cast<uint32_t>( + drm_info->subsample_mapping[i].encrypted_byte_count)}; + subsamples.push_back(subsample); + } + } + const std::int64_t win32_time_stamp = ConvertToWin32Time(media_timestamp); // Adjust the offset for 7 bytes to remove the ADTS header. - const uint8_t* audio_start = static_cast<const uint8_t*>(data) + 7; - const int audio_size = size - 7; + const int kADTSHeaderSize = 7; + const uint8_t* audio_start = + static_cast<const uint8_t*>(data) + kADTSHeaderSize; + const int audio_size = size - kADTSHeaderSize; + if (!subsamples.empty()) { + SB_DCHECK(subsamples[0].clear_bytes == kADTSHeaderSize); + subsamples[0].clear_bytes = 0; + } const bool write_ok = impl_->TryWriteInputBuffer( audio_start, audio_size, win32_time_stamp, key_id, iv, subsamples); @@ -282,10 +307,11 @@ SbMediaAudioCodec code, SbMediaAudioFrameStorageType audio_frame_fmt, SbMediaAudioSampleType sample_type, - const SbMediaAudioHeader& audio_header) { - return scoped_ptr<AbstractWin32AudioDecoder>(new - AbstractWin32AudioDecoderImpl(code, audio_frame_fmt, sample_type, - audio_header)); + const SbMediaAudioHeader& audio_header, + SbDrmSystem drm_system) { + return scoped_ptr<AbstractWin32AudioDecoder>( + new AbstractWin32AudioDecoderImpl(code, audio_frame_fmt, sample_type, + audio_header, drm_system)); } } // namespace win32
diff --git a/src/starboard/shared/win32/win32_audio_decoder.h b/src/starboard/shared/win32/win32_audio_decoder.h index 4cc5f27..3bfe78c 100644 --- a/src/starboard/shared/win32/win32_audio_decoder.h +++ b/src/starboard/shared/win32/win32_audio_decoder.h
@@ -18,6 +18,7 @@ #include <vector> #include "starboard/common/scoped_ptr.h" +#include "starboard/drm.h" #include "starboard/media.h" #include "starboard/shared/starboard/player/decoded_audio_internal.h" #include "starboard/shared/starboard/player/video_frame_internal.h" @@ -35,7 +36,8 @@ SbMediaAudioCodec codec, SbMediaAudioFrameStorageType audio_frame_fmt, SbMediaAudioSampleType sample_type, - const SbMediaAudioHeader& audio_header); + const SbMediaAudioHeader& audio_header, + SbDrmSystem drm_system); virtual ~AbstractWin32AudioDecoder() {} // INPUT:
diff --git a/src/starboard/shared/win32/win32_decoder_impl.cc b/src/starboard/shared/win32/win32_decoder_impl.cc index b06fcdc..b41b418 100644 --- a/src/starboard/shared/win32/win32_decoder_impl.cc +++ b/src/starboard/shared/win32/win32_decoder_impl.cc
@@ -117,11 +117,15 @@ } // namespace DecoderImpl::DecoderImpl(const std::string& type, - MediaBufferConsumerInterface* media_buffer_consumer) + MediaBufferConsumerInterface* media_buffer_consumer, + SbDrmSystem drm_system) : type_(type), media_buffer_consumer_(media_buffer_consumer), discontinuity_(false) { SB_DCHECK(media_buffer_consumer_); + drm_system_ = + static_cast<::starboard::xb1::shared::playready::SbDrmSystemPlayready*>( + drm_system); } DecoderImpl::~DecoderImpl() { @@ -137,13 +141,29 @@ return decoder; } -void DecoderImpl::ActivateDecryptor(ComPtr<IMFMediaType> input_type) { +void DecoderImpl::ActivateDecryptor() { + SB_DCHECK(decoder_); + if (!decryptor_) { return; } - HRESULT hr = decryptor_->SetInputType(kStreamId, input_type.Get(), - 0); // MFT_SET_TYPE_TEST_FLAGS. + ComPtr<IMFMediaType> decryptor_input_type; + + HRESULT hr = decoder_->GetInputCurrentType( + kStreamId, decryptor_input_type.GetAddressOf()); + CheckResult(hr); + + GUID original_sub_type; + { + ComPtr<IMFMediaType> output_type; + hr = decoder_->GetOutputCurrentType(kStreamId, output_type.GetAddressOf()); + CheckResult(hr); + output_type->GetGUID(MF_MT_SUBTYPE, &original_sub_type); + } + + const DWORD kFlags = 0; + hr = decryptor_->SetInputType(kStreamId, decryptor_input_type.Get(), kFlags); CheckResult(hr); // Ensure that the decryptor and the decoder agrees on the protection of @@ -158,7 +178,6 @@ BYTE* crypt_seed = NULL; DWORD crypt_seed_size = 0; ComPtr<IMFMediaType> decoder_input_type; - ComPtr<IMFMediaType> decoder_output_type; hr = decryptor_.As(&decryption_sample_protection); CheckResult(hr); @@ -211,6 +230,21 @@ // Start the decryptor, note that this should be better abstracted. SendMFTMessage(decryptor_.Get(), MFT_MESSAGE_NOTIFY_BEGIN_STREAMING); SendMFTMessage(decryptor_.Get(), MFT_MESSAGE_NOTIFY_START_OF_STREAM); + + for (int index = 0;; ++index) { + ComPtr<IMFMediaType> output_type; + hr = decoder_->GetOutputAvailableType(0, index, &output_type); + if (SUCCEEDED(hr)) { + GUID sub_type; + output_type->GetGUID(MF_MT_SUBTYPE, &sub_type); + if (IsEqualGUID(sub_type, original_sub_type)) { + hr = decoder_->SetOutputType(0, output_type.Get(), 0); + CheckResult(hr); + break; + } + } + output_type.Reset(); + } } bool DecoderImpl::TryWriteInputBuffer( @@ -236,6 +270,19 @@ // Better check the key id size is 16 and iv size is 8 or 16. bool encrypted = !key_id.empty() && !iv.empty(); if (encrypted) { + if (!decryptor_) { + scoped_refptr<::starboard::xb1::shared::playready::PlayreadyLicense> + license = drm_system_->GetLicense(key_id.data(), + static_cast<int>(key_id.size())); + if (license && license->usable()) { + decryptor_ = license->decryptor(); + ActivateDecryptor(); + } + } + if (!decryptor_) { + SB_NOTREACHED(); + return false; + } size_t iv_size = iv.size(); const char kEightZeros[8] = {0}; if (iv_size == 16 && SbMemoryCompare(iv.data() + 8, kEightZeros, 8) == 0) { @@ -315,27 +362,33 @@ bool DecoderImpl::DeliverOneOutputOnAllTransforms() { SB_DCHECK(decoder_); - bool delivered = false; if (decryptor_) { - if (ComPtr<IMFSample> sample = DeliverOutputOnTransform(decryptor_)) { - HRESULT hr = decoder_->ProcessInput(kStreamId, sample.Get(), 0); + if (!cached_decryptor_output_) { + cached_decryptor_output_ = DeliverOutputOnTransform(decryptor_); + } + while (cached_decryptor_output_) { + HRESULT hr = + decoder_->ProcessInput(kStreamId, cached_decryptor_output_.Get(), 0); if (hr == MF_E_NOTACCEPTING) { - // The protocol says that when ProcessInput() returns MF_E_NOTACCEPTING, - // there must be some output available. Retrieve the output and the next - // ProcessInput() should succeed. - ComPtr<IMFSample> sample_inner = DeliverOutputOnTransform(decoder_); - if (sample_inner) { - DeliverDecodedSample(sample_inner); - delivered = true; - } - hr = decoder_->ProcessInput(kStreamId, sample.Get(), 0); + break; + } else { CheckResult(hr); - return delivered; + cached_decryptor_output_ = DeliverOutputOnTransform(decryptor_); } - CheckResult(hr); - delivered = true; + } + if (cached_decryptor_output_) { + // The protocol says that when ProcessInput() returns MF_E_NOTACCEPTING, + // there must be some output available. Retrieve the output and the next + // ProcessInput() should succeed. + ComPtr<IMFSample> decoder_output = DeliverOutputOnTransform(decoder_); + if (decoder_output) { + DeliverDecodedSample(decoder_output); + } + return decoder_output != NULL; } } + + bool delivered = false; if (ComPtr<IMFSample> sample = DeliverOutputOnTransform(decoder_)) { DeliverDecodedSample(sample); delivered = true; @@ -371,18 +424,6 @@ HRESULT hr = transform->GetOutputStreamInfo(kStreamId, &output_stream_info); CheckResult(hr); - // Each media sample (IMFSample interface) of output data from the MFT - // contains complete, unbroken units of data. The definition of a unit - // of data depends on the media type: For uncompressed video, a video - // frame; for compressed data, a compressed packet; for uncompressed audio, - // a single audio frame. - // - // For uncompressed audio formats, this flag is always implied. (It is valid - // to set the flag, but not required.) An uncompressed audio frame should - // never span more than one media sample. - SB_DCHECK((output_stream_info.dwFlags & MFT_OUTPUT_STREAM_WHOLE_SAMPLES) != - 0); - if (StreamAllocatesMemory(output_stream_info.dwFlags)) { // Try to let the IMFTransform allocate the memory if possible. return; @@ -431,9 +472,21 @@ hr = transform->SetOutputType(kStreamId, media_type.Get(), 0); CheckResult(hr); - return NULL; - } else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT || - output_data_buffer.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE) { + + media_buffer_consumer_->OnNewOutputType(media_type); + + hr = transform->ProcessOutput(kFlags, kNumberOfBuffers, &output_data_buffer, + &status); + + SB_DCHECK(!output_data_buffer.pEvents); + + output = output_data_buffer.pSample; + ReleaseIfNotNull(&output_data_buffer.pEvents); + ReleaseIfNotNull(&output_data_buffer.pSample); + } + + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT || + output_data_buffer.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE) { return NULL; }
diff --git a/src/starboard/shared/win32/win32_decoder_impl.h b/src/starboard/shared/win32/win32_decoder_impl.h index 38374ff..cef0d5d 100644 --- a/src/starboard/shared/win32/win32_decoder_impl.h +++ b/src/starboard/shared/win32/win32_decoder_impl.h
@@ -25,10 +25,14 @@ #include <vector> #include "starboard/common/scoped_ptr.h" +#include "starboard/drm.h" #include "starboard/media.h" #include "starboard/shared/win32/media_common.h" #include "starboard/types.h" +// TODO: Win32 code shouldn't depend on Xb1 code. Refactor this. +#include "starboard/xb1/shared/playready/drm_system_playready.h" + namespace starboard { namespace shared { namespace win32 { @@ -38,6 +42,8 @@ virtual void Consume(Microsoft::WRL::ComPtr<IMFMediaBuffer> media_buffer, int64_t win32_timestamp) = 0; + virtual void OnNewOutputType(const ComPtr<IMFMediaType>& type) = 0; + protected: ~MediaBufferConsumerInterface() {} }; @@ -50,12 +56,13 @@ class DecoderImpl { public: DecoderImpl(const std::string& type, - MediaBufferConsumerInterface* media_buffer_consumer); + MediaBufferConsumerInterface* media_buffer_consumer, + SbDrmSystem drm_system); ~DecoderImpl(); static Microsoft::WRL::ComPtr<IMFTransform> CreateDecoder(CLSID clsid); - void ActivateDecryptor(Microsoft::WRL::ComPtr<IMFMediaType> input_type); + void ActivateDecryptor(); bool TryWriteInputBuffer(const void* data, int size, std::int64_t win32_timestamp, @@ -84,9 +91,11 @@ const std::string type_; // For debugging purpose. // This is the target for the all completed media buffers. MediaBufferConsumerInterface* media_buffer_consumer_; + ::starboard::xb1::shared::playready::SbDrmSystemPlayready* drm_system_; bool discontinuity_; Microsoft::WRL::ComPtr<IMFTransform> decryptor_; + Microsoft::WRL::ComPtr<IMFSample> cached_decryptor_output_; Microsoft::WRL::ComPtr<IMFTransform> decoder_; };
diff --git a/src/starboard/shared/win32/win32_video_decoder.cc b/src/starboard/shared/win32/win32_video_decoder.cc index 93bc487..667b2e5 100644 --- a/src/starboard/shared/win32/win32_video_decoder.cc +++ b/src/starboard/shared/win32/win32_video_decoder.cc
@@ -36,31 +36,22 @@ // This magic number is taken directly from sample from MS. Can be further // tuned in case if there is playback issues. const int kSampleAllocatorFramesMax = 5; +// This is the minimum allocated frames in the output ring buffer. Can be +// further tuned to save memory. Note that use a value that is too small leads +// to hang when calling ProcessOutput(). +const int kMinimumOutputSampleCount = 10; // CLSID_CMSVideoDecoderMFT {62CE7E72-4C71-4D20-B15D-452831A87D9D} const GUID CLSID_VideoDecoder = {0x62CE7E72, 0x4C71, 0x4d20, 0xB1, 0x5D, 0x45, 0x28, 0x31, 0xA8, 0x7D, 0x9D}; -ComPtr<ID3D11Texture2D> GetTexture2D(ComPtr<IMFMediaBuffer> media_buffer) { - ComPtr<IMFDXGIBuffer> dxgi_buffer; - HRESULT hr = media_buffer.As(&dxgi_buffer); - CheckResult(hr); - SB_DCHECK(dxgi_buffer.Get()); - - ComPtr<ID3D11Texture2D> dx_texture; - hr = dxgi_buffer->GetResource(IID_PPV_ARGS(&dx_texture)); - CheckResult(hr); - return dx_texture; -} - class VideoFrameFactory { public: static VideoFramePtr Construct(SbMediaTime timestamp, - ComPtr<IMFMediaBuffer> media_buffer) { - ComPtr<ID3D11Texture2D> texture = GetTexture2D(media_buffer); - D3D11_TEXTURE2D_DESC tex_desc; - texture->GetDesc(&tex_desc); - VideoFramePtr out(new VideoFrame(tex_desc.Width, tex_desc.Height, + ComPtr<IMFMediaBuffer> media_buffer, + uint32_t width, + uint32_t height) { + VideoFramePtr out(new VideoFrame(width, height, timestamp, media_buffer.Detach(), nullptr, DeleteTextureFn)); frames_in_flight_.increment(); @@ -84,10 +75,10 @@ class AbstractWin32VideoDecoderImpl : public AbstractWin32VideoDecoder, public MediaBufferConsumerInterface { public: - explicit AbstractWin32VideoDecoderImpl(SbMediaVideoCodec codec) + AbstractWin32VideoDecoderImpl(SbMediaVideoCodec codec, SbDrmSystem drm_system) : codec_(codec), surface_width_(0), surface_height_(0) { MediaBufferConsumerInterface* media_cb = this; - impl_.reset(new DecoderImpl("video", media_cb)); + impl_.reset(new DecoderImpl("video", media_cb, drm_system)); EnsureVideoDecoderCreated(); } @@ -95,10 +86,32 @@ int64_t win32_timestamp) { const SbMediaTime media_timestamp = ConvertToMediaTime(win32_timestamp); VideoFramePtr frame_output = - VideoFrameFactory::Construct(media_timestamp, media_buffer); + VideoFrameFactory::Construct(media_timestamp, media_buffer, + surface_width_, surface_height_); output_queue_.PushBack(frame_output); } + void OnNewOutputType(const ComPtr<IMFMediaType>& type) override { + MFVideoArea aperture; + HRESULT hr = type->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, + reinterpret_cast<UINT8*>(&aperture), sizeof(MFVideoArea), nullptr); + if (SUCCEEDED(hr)) { + // TODO: consider offset as well + surface_width_ = aperture.Area.cx; + surface_height_ = aperture.Area.cy; + return; + } + + uint32_t width; + uint32_t height; + hr = MFGetAttributeSize(type.Get(), MF_MT_FRAME_SIZE, + &width, &height); + if (SUCCEEDED(hr)) { + surface_width_ = width; + surface_height_ = height; + } + } + ComPtr<IMFMediaType> Configure(IMFTransform* decoder) { ComPtr<IMFMediaType> input_type; HRESULT hr = MFCreateMediaType(&input_type); @@ -160,8 +173,6 @@ SB_DCHECK(1 == input_stream_count); SB_DCHECK(1 == output_stream_count); - impl_->ActivateDecryptor(media_type); - ComPtr<IMFMediaType> output_type = FindMediaType(MFVideoFormat_YV12, decoder.Get()); @@ -174,6 +185,10 @@ hr = decoder->GetAttributes(attributes.GetAddressOf()); CheckResult(hr); + hr = attributes->SetUINT32(MF_SA_MINIMUM_OUTPUT_SAMPLE_COUNT, + kMinimumOutputSampleCount); + CheckResult(hr); + UINT32 value = 0; hr = attributes->GetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, &value); SB_DCHECK(hr == S_OK || hr == MF_E_ATTRIBUTENOTFOUND); @@ -225,19 +240,35 @@ return false; // Wait for more data. } - // This would be used for decrypting content. - // For now this is empty. std::vector<uint8_t> key_id; std::vector<uint8_t> iv; + std::vector<Subsample> subsamples; - std::vector<Subsample> empty_subsample; + // TODO: Merge this with similar code in the audio decoder. + const SbDrmSampleInfo* drm_info = buff->drm_info(); + + if (drm_info != NULL && drm_info->initialization_vector_size != 0) { + key_id.assign(drm_info->identifier, + drm_info->identifier + drm_info->identifier_size); + iv.assign(drm_info->initialization_vector, + drm_info->initialization_vector + + drm_info->initialization_vector_size); + subsamples.reserve(drm_info->subsample_count); + for (int32_t i = 0; i < drm_info->subsample_count; ++i) { + Subsample subsample = { + static_cast<uint32_t>( + drm_info->subsample_mapping[i].clear_byte_count), + static_cast<uint32_t>( + drm_info->subsample_mapping[i].encrypted_byte_count)}; + subsamples.push_back(subsample); + } + } const SbMediaTime media_timestamp = buff->pts(); const int64_t win32_timestamp = ConvertToWin32Time(media_timestamp); const bool write_ok = impl_->TryWriteInputBuffer( - buff->data(), buff->size(), win32_timestamp, - key_id, iv, empty_subsample); + buff->data(), buff->size(), win32_timestamp, key_id, iv, subsamples); return write_ok; } @@ -271,12 +302,14 @@ uint32_t surface_height_; HardwareDecoderContext dx_decoder_ctx_; }; + } // anonymous namespace. scoped_ptr<AbstractWin32VideoDecoder> AbstractWin32VideoDecoder::Create( - SbMediaVideoCodec codec) { + SbMediaVideoCodec codec, + SbDrmSystem drm_system) { return scoped_ptr<AbstractWin32VideoDecoder>( - new AbstractWin32VideoDecoderImpl(codec)); + new AbstractWin32VideoDecoderImpl(codec, drm_system)); } } // namespace win32
diff --git a/src/starboard/shared/win32/win32_video_decoder.h b/src/starboard/shared/win32/win32_video_decoder.h index 84ff7b7..a32158b 100644 --- a/src/starboard/shared/win32/win32_video_decoder.h +++ b/src/starboard/shared/win32/win32_video_decoder.h
@@ -20,6 +20,7 @@ #include "starboard/common/ref_counted.h" #include "starboard/common/scoped_ptr.h" +#include "starboard/drm.h" #include "starboard/media.h" #include "starboard/shared/starboard/player/decoded_audio_internal.h" #include "starboard/shared/starboard/player/video_frame_internal.h" @@ -33,7 +34,8 @@ // VideoDecoder for Win32. class AbstractWin32VideoDecoder { public: - static scoped_ptr<AbstractWin32VideoDecoder> Create(SbMediaVideoCodec codec); + static scoped_ptr<AbstractWin32VideoDecoder> Create(SbMediaVideoCodec codec, + SbDrmSystem drm_system); virtual ~AbstractWin32VideoDecoder() {} virtual bool TryWrite(const scoped_refptr<InputBuffer>& buff) = 0;
diff --git a/src/starboard/shared/x11/application_x11.cc b/src/starboard/shared/x11/application_x11.cc index 19fb1f2..c4a5cb6 100644 --- a/src/starboard/shared/x11/application_x11.cc +++ b/src/starboard/shared/x11/application_x11.cc
@@ -43,6 +43,9 @@ namespace starboard { namespace shared { namespace x11 { + +using ::starboard::shared::dev_input::DevInput; + namespace { enum { @@ -647,28 +650,6 @@ } #endif -bool XNextEventTimed(Display* display, XEvent* out_event, SbTime duration) { - if (XPending(display) == 0) { - if (duration <= SbTime()) { - return false; - } - - int fd = ConnectionNumber(display); - fd_set read_set; - FD_ZERO(&read_set); - FD_SET(fd, &read_set); - struct timeval tv; - SbTime clamped_duration = std::max(duration, SbTime()); - ToTimevalDuration(clamped_duration, &tv); - if (select(fd + 1, &read_set, NULL, NULL, &tv) == 0) { - return false; - } - } - - XNextEvent(display, out_event); - return true; -} - void XSendAtom(Window window, Atom atom) { // XLib is not thread-safe. Since we may be coming from another thread, we // have to open another connection to the display to inject the wake-up event. @@ -732,6 +713,10 @@ SbWindow window = new SbWindowPrivate(display_, options); windows_.push_back(window); + if (!dev_input_) { + // evdev input will be sent to the first created window only. + dev_input_.reset(DevInput::Create(window, ConnectionNumber(display_))); + } return window; } @@ -745,6 +730,12 @@ std::find(windows_.begin(), windows_.end(), window); SB_DCHECK(iterator != windows_.end()); windows_.erase(iterator); + + if (windows_.empty()) { + SB_DCHECK(dev_input_); + dev_input_.reset(); + } + delete window; if (windows_.empty()) { StopX(); @@ -849,23 +840,29 @@ ApplicationX11::WaitForSystemEventWithTimeout(SbTime time) { SB_DCHECK(display_); - XEvent x_event; - shared::starboard::Application::Event* pending_event = GetPendingEvent(); if (pending_event) { return pending_event; } - if (XNextEventTimed(display_, &x_event, time)) { + SB_DCHECK(dev_input_); + shared::starboard::Application::Event* evdev_event = + dev_input_->WaitForSystemEventWithTimeout(time); + + if (!evdev_event && XPending(display_) != 0) { + XEvent x_event; + XNextEvent(display_, &x_event); return XEventToEvent(&x_event); - } else { - return NULL; } + + return evdev_event; } void ApplicationX11::WakeSystemEventWait() { SB_DCHECK(!windows_.empty()); XSendAtom((*windows_.begin())->window, wake_up_atom_); + SB_DCHECK(dev_input_); + dev_input_->WakeSystemEventWait(); } bool ApplicationX11::EnsureX() { @@ -879,7 +876,7 @@ XSetErrorHandler(ErrorHandler); display_ = XOpenDisplay(NULL); if (!display_) { - const char *display_environment = getenv("DISPLAY"); + const char* display_environment = getenv("DISPLAY"); if (display_environment == NULL) { SB_LOG(ERROR) << "Unable to open display, DISPLAY not set."; } else {
diff --git a/src/starboard/shared/x11/application_x11.h b/src/starboard/shared/x11/application_x11.h index a0235b1..cadfc90 100644 --- a/src/starboard/shared/x11/application_x11.h +++ b/src/starboard/shared/x11/application_x11.h
@@ -20,9 +20,11 @@ #include <queue> #include <vector> +#include "base/memory/scoped_ptr.h" #include "starboard/configuration.h" #include "starboard/player.h" #include "starboard/shared/internal_only.h" +#include "starboard/shared/linux/dev_input/dev_input.h" #include "starboard/shared/starboard/application.h" #include "starboard/shared/starboard/queue_application.h" #include "starboard/types.h" @@ -117,6 +119,9 @@ // Indicates whether a key press event that requires a matching release has // been dispatched. bool paste_buffer_key_release_pending_; + + // The /dev/input input handler. Only set when there is an open window. + scoped_ptr<::starboard::shared::dev_input::DevInput> dev_input_; }; } // namespace x11
diff --git a/src/starboard/storage.h b/src/starboard/storage.h index 37ccc10..33ba547 100644 --- a/src/starboard/storage.h +++ b/src/starboard/storage.h
@@ -51,13 +51,34 @@ return record != kSbStorageInvalidRecord; } -// Opens and returns a SbStorageRecord for |user|, blocking I/O on the calling -// thread until it returns. If |user| is not a valid |SbUser|, the function -// returns |kSbStorageInvalidRecord|. +#if SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION + +// Opens and returns the default SbStorageRecord for |user|, blocking I/O on the +// calling thread until the open is completed. If |user| is not a valid +// |SbUser|, the function returns |kSbStorageInvalidRecord|. Will return an +// |SbStorageRecord| of size zero if the record does not yet exist. Opening an +// already-open |SbStorageRecord| has undefined behavior. // -// |user|: The user for which the storage record is opened. +// |user|: The user for which the storage record will be opened. SB_EXPORT SbStorageRecord SbStorageOpenRecord(SbUser user); +#else // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION + +// Opens and returns the SbStorageRecord for |user| named |name|, blocking I/O +// on the calling thread until the open is completed. If |user| is not a valid +// |SbUser|, the function returns |kSbStorageInvalidRecord|. Will return an +// |SbStorageRecord| of size zero if the record does not yet exist. Opening an +// already-open |SbStorageRecord| has undefined behavior. +// +// If |name| is NULL, opens the default storage record for the user, like what +// would have been saved with the previous version of SbStorageOpenRecord. +// +// |user|: The user for which the storage record will be opened. +// |name|: The filesystem-safe name of the record to open. +SB_EXPORT SbStorageRecord SbStorageOpenRecord(SbUser user, const char* name); + +#endif // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION + // Closes |record|, synchronously ensuring that all written data is flushed. // This function performs blocking I/O on the calling thread. // @@ -91,9 +112,15 @@ // Replaces the data in |record| with |data_size| bytes from |data|. This // function always deletes any previous data in that record. The return value -// indicates whether the write succeeded. This function makes a best-effort -// to read the entire record, and it performs performs blocking I/O on the -// calling thread until the entire record is read or an error is encountered. +// indicates whether the write succeeded. This function makes a best-effort to +// write the entire record, and it may perform blocking I/O on the calling +// thread until the entire record is written or an error is encountered. +// +// While |SbStorageWriteRecord()| may defer the persistence, +// |SbStorageReadRecord()| is expected to work as expected immediately +// afterwards, even without a call to |SbStorageCloseRecord()|. The data should +// be persisted after a short time, even if there is an unexpected process +// termination before |SbStorageCloseRecord()| is called. // // |record|: The record to be written to. // |data|: The data to write to the record. @@ -104,21 +131,43 @@ const char* data, int64_t data_size); -// Deletes the |SbStorageRecord| for the specified user. The return value +#if SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION + +// Deletes the default |SbStorageRecord| for the |user|. The return value // indicates whether the record existed and was successfully deleted. If the // record did not exist or could not be deleted, the function returns |false|. // // This function must not be called while the user's storage record is open. // This function performs blocking I/O on the calling thread. // -// |user|: The user for whom the record is deleted. +// |user|: The user for whom the record will be deleted. SB_EXPORT bool SbStorageDeleteRecord(SbUser user); +#else // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION + +// Deletes the |SbStorageRecord| for |user| named |name|. The return value +// indicates whether the record existed and was successfully deleted. If the +// record did not exist or could not be deleted, the function returns |false|. +// +// If |name| is NULL, deletes the default storage record for the user, like what +// would have been deleted with the previous version of SbStorageDeleteRecord. +// +// This function must not be called while the user's storage record is open. +// This function performs blocking I/O on the calling thread. +// +// |user|: The user for whom the record will be deleted. +// |name|: The filesystem-safe name of the record to open. +SB_EXPORT bool SbStorageDeleteRecord(SbUser user, const char* name); + +#endif // SB_API_VERSION < SB_STORAGE_NAMES_API_VERSION + #ifdef __cplusplus } // extern "C" #endif #ifdef __cplusplus +#include <string> + namespace starboard { // Inline scoped wrapper for SbStorageRecord. @@ -126,18 +175,28 @@ public: StorageRecord() : user_(SbUserGetCurrent()), record_(kSbStorageInvalidRecord) { - if (SbUserIsValid(user_)) { - record_ = SbStorageOpenRecord(user_); - } + Initialize(); } explicit StorageRecord(SbUser user) : user_(user), record_(kSbStorageInvalidRecord) { - if (SbUserIsValid(user_)) { - record_ = SbStorageOpenRecord(user_); - } + Initialize(); } +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + explicit StorageRecord(const char* name) + : user_(SbUserGetCurrent()), + name_(name), + record_(kSbStorageInvalidRecord) { + Initialize(); + } + + StorageRecord(SbUser user, const char* name) + : user_(user), name_(name), record_(kSbStorageInvalidRecord) { + Initialize(); + } +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + ~StorageRecord() { Close(); } bool IsValid() { return SbStorageIsValidRecord(record_); } int64_t GetSize() { return SbStorageGetRecordSize(record_); } @@ -160,11 +219,36 @@ bool Delete() { Close(); +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + if (!name_.empty()) { + return SbStorageDeleteRecord(user_, name_.c_str()); + } else { + return SbStorageDeleteRecord(user_, NULL); + } +#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION return SbStorageDeleteRecord(user_); +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION } private: + void Initialize() { + if (SbUserIsValid(user_)) { +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + if (!name_.empty()) { + record_ = SbStorageOpenRecord(user_, name_.c_str()); + } else { + record_ = SbStorageOpenRecord(user_, NULL); + } +#else // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + record_ = SbStorageOpenRecord(user_); +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + } + } + SbUser user_; +#if SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION + std::string name_; +#endif // SB_API_VERSION >= SB_STORAGE_NAMES_API_VERSION SbStorageRecord record_; };
diff --git a/src/starboard/stub/BUILD.gn b/src/starboard/stub/BUILD.gn new file mode 100644 index 0000000..18ad876 --- /dev/null +++ b/src/starboard/stub/BUILD.gn
@@ -0,0 +1,428 @@ +# Copyright 2017 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. + +import("//starboard/build/config/fastbuild.gni") +import("//starboard/build/delegated_config.gni") + +# ============================================================================= +# DEFAULT COMPILER CONFIGS +# ============================================================================= + +config("compiler_defaults") { + cflags = [ + # We'll pretend not to be Linux, but Starboard instead. + "-U__linux__", + "-Werror", + "-fcolor-diagnostics", + # Default visibility to hidden, to enable dead stripping. + "-fvisibility=hidden", + # Warn for implicit type conversions that may change a value. + "-Wconversion", + "-Wno-c++11-compat", + # This (rightfully) complains about "override", which we use heavily. + "-Wno-c++11-extensions", + # Warns on switches on enums that cover all enum values but also contain a + # default: branch. Chrome is full of that. + "-Wno-covered-switch-default", + # protobuf uses hash_map. + "-Wno-deprecated", + "-fno-exceptions", + # Don't warn about the "struct foo f = {0};" initialization pattern. + "-Wno-missing-field-initializers", + # Do not warn for implicit sign conversions. + "-Wno-sign-conversion", + "-fno-strict-aliasing", # See http://crbug.com/32204 + # TODO(pkasting): In C++11 this is legal, so this should be removed when we + # change to that. (This is also why we don't bother fixing all these cases + # today.) + "-Wno-unnamed-type-template-args", + # Triggered by the COMPILE_ASSERT macro. + "-Wno-unused-local-typedef", + # Do not warn if a function or variable cannot be implicitly + # instantiated. + "-Wno-undefined-var-template", + ] + + defines = [ + "__STDC_FORMAT_MACROS", + ] + + cflags_cc = [ + "-std=gnu++11", + ] +} + +config("compiler_defaults_debug") { + cflags = [] + if (!cobalt_use_fastbuild) { + cflags += [ "-g" ] + } +} + +config("compiler_defaults_devel") { + cflags = [] + if (!cobalt_use_fastbuild) { + cflags += [ "-g" ] + } +} + +config("compiler_defaults_qa") { + cflags = [ + "-gline-tables-only", + ] +} + +config("compiler_defaults_gold") { + cflags = [ + "-gline-tables-only", + ] +} + +# ============================================================================= +# DELEGATED CONFIGS +# ============================================================================= + +config("pedantic_warnings") { + cflags = [ + "-Wall", + "-Wextra", + "-Wunreachable-code", + ] +} + +config("no_pedantic_warnings") { + cflags = [ + # "this" pointer cannot be NULL...pointer may be assumed + # to always convert to true. + "-Wno-undefined-bool-conversion", + # Skia doesn't use overrides. + "-Wno-inconsistent-missing-override", + # Do not warn about unused function params. + "-Wno-unused-parameter", + # Do not warn for implicit type conversions that may change a value. + "-Wno-conversion", + # shifting a negative signed value is undefined + "-Wno-shift-negative-value", + # Width of bit-field exceeds width of its type- value will be truncated + "-Wno-bitfield-width", + ] +} + + +delegated_config("optimizations") { + path = "//starboard/build/toolchain/linux/config" + prefixes = [ "no", "debuggable", "full" ] + generate_default = false +} + +config("default_optimizations") { + if (cobalt_config == "debug") { + configs = [ ":no_optimizations" ] + } else { + configs = [ ":debuggable_optimizations" ] + } +} + + +delegated_config("rtti") { + path = "//starboard/build/toolchain/linux/config" + generate_default = false +} + +config("default_rtti") { + if (cobalt_config == "debug" || cobalt_config == "devel") { + configs = [ ":rtti" ] + } else { + configs = [ ":no_rtti" ] + } +} + + +config("wexit_time_destructors") { + configs = [ "//starboard/build/toolchain/linux/config:wexit_time_destructors" ] +} + +# ============================================================================= +# starboard_platform TARGET +# ============================================================================= + +static_library("starboard_platform") { + sources = [ + "//starboard/shared/starboard/application.cc", + "//starboard/shared/starboard/command_line.cc", + "//starboard/shared/starboard/command_line.h", + "//starboard/shared/starboard/event_cancel.cc", + "//starboard/shared/starboard/event_schedule.cc", + "//starboard/shared/starboard/file_mode_string_to_flags.cc", + "//starboard/shared/starboard/log_message.cc", + "//starboard/shared/starboard/player/filter/stub_player_components_impl.cc", + "//starboard/shared/starboard/queue_application.cc", + "//starboard/shared/stub/accessibility_get_display_settings.cc", + "//starboard/shared/stub/accessibility_get_text_to_speech_settings.cc", + "//starboard/shared/stub/atomic_public.h", + "//starboard/shared/stub/audio_sink_create.cc", + "//starboard/shared/stub/audio_sink_destroy.cc", + "//starboard/shared/stub/audio_sink_get_max_channels.cc", + "//starboard/shared/stub/audio_sink_get_nearest_supported_sample_frequency.cc", + "//starboard/shared/stub/audio_sink_is_audio_frame_storage_type_supported.cc", + "//starboard/shared/stub/audio_sink_is_audio_sample_type_supported.cc", + "//starboard/shared/stub/audio_sink_is_valid.cc", + "//starboard/shared/stub/byte_swap.cc", + "//starboard/shared/stub/character_is_alphanumeric.cc", + "//starboard/shared/stub/character_is_digit.cc", + "//starboard/shared/stub/character_is_hex_digit.cc", + "//starboard/shared/stub/character_is_space.cc", + "//starboard/shared/stub/character_is_upper.cc", + "//starboard/shared/stub/character_to_lower.cc", + "//starboard/shared/stub/character_to_upper.cc", + "//starboard/shared/stub/condition_variable_broadcast.cc", + "//starboard/shared/stub/condition_variable_create.cc", + "//starboard/shared/stub/condition_variable_destroy.cc", + "//starboard/shared/stub/condition_variable_signal.cc", + "//starboard/shared/stub/condition_variable_wait.cc", + "//starboard/shared/stub/condition_variable_wait_timed.cc", + "//starboard/shared/stub/cryptography_create_transformer.cc", + "//starboard/shared/stub/cryptography_destroy_transformer.cc", + "//starboard/shared/stub/cryptography_get_tag.cc", + "//starboard/shared/stub/cryptography_set_authenticated_data.cc", + "//starboard/shared/stub/cryptography_set_initialization_vector.cc", + "//starboard/shared/stub/cryptography_transform.cc", + "//starboard/shared/stub/directory_can_open.cc", + "//starboard/shared/stub/directory_close.cc", + "//starboard/shared/stub/directory_create.cc", + "//starboard/shared/stub/directory_get_next.cc", + "//starboard/shared/stub/directory_open.cc", + "//starboard/shared/stub/double_absolute.cc", + "//starboard/shared/stub/double_exponent.cc", + "//starboard/shared/stub/double_floor.cc", + "//starboard/shared/stub/double_is_finite.cc", + "//starboard/shared/stub/double_is_nan.cc", + "//starboard/shared/stub/drm_close_session.cc", + "//starboard/shared/stub/drm_create_system.cc", + "//starboard/shared/stub/drm_destroy_system.cc", + "//starboard/shared/stub/drm_generate_session_update_request.cc", + "//starboard/shared/stub/drm_system_internal.h", + "//starboard/shared/stub/drm_update_session.cc", + "//starboard/shared/stub/file_can_open.cc", + "//starboard/shared/stub/file_close.cc", + "//starboard/shared/stub/file_delete.cc", + "//starboard/shared/stub/file_exists.cc", + "//starboard/shared/stub/file_flush.cc", + "//starboard/shared/stub/file_get_info.cc", + "//starboard/shared/stub/file_get_path_info.cc", + "//starboard/shared/stub/file_open.cc", + "//starboard/shared/stub/file_read.cc", + "//starboard/shared/stub/file_seek.cc", + "//starboard/shared/stub/file_truncate.cc", + "//starboard/shared/stub/file_write.cc", + "//starboard/shared/stub/log.cc", + "//starboard/shared/stub/log_flush.cc", + "//starboard/shared/stub/log_format.cc", + "//starboard/shared/stub/log_is_tty.cc", + "//starboard/shared/stub/log_raw.cc", + "//starboard/shared/stub/log_raw_dump_stack.cc", + "//starboard/shared/stub/log_raw_format.cc", + "//starboard/shared/stub/media_can_play_mime_and_key_system.cc", + "//starboard/shared/stub/media_get_audio_configuration.cc", + "//starboard/shared/stub/media_get_audio_output_count.cc", + "//starboard/shared/stub/media_is_audio_supported.cc", + "//starboard/shared/stub/media_is_output_protected.cc", + "//starboard/shared/stub/media_is_supported.cc", + "//starboard/shared/stub/media_is_transfer_characteristics_supported.cc", + "//starboard/shared/stub/media_is_video_supported.cc", + "//starboard/shared/stub/media_set_output_protection.cc", + "//starboard/shared/stub/memory_allocate_aligned_unchecked.cc", + "//starboard/shared/stub/memory_allocate_unchecked.cc", + "//starboard/shared/stub/memory_compare.cc", + "//starboard/shared/stub/memory_copy.cc", + "//starboard/shared/stub/memory_find_byte.cc", + "//starboard/shared/stub/memory_flush.cc", + "//starboard/shared/stub/memory_free.cc", + "//starboard/shared/stub/memory_free_aligned.cc", + "//starboard/shared/stub/memory_get_stack_bounds.cc", + "//starboard/shared/stub/memory_map.cc", + "//starboard/shared/stub/memory_move.cc", + "//starboard/shared/stub/memory_reallocate_unchecked.cc", + "//starboard/shared/stub/memory_set.cc", + "//starboard/shared/stub/memory_unmap.cc", + "//starboard/shared/stub/microphone_close.cc", + "//starboard/shared/stub/microphone_create.cc", + "//starboard/shared/stub/microphone_destroy.cc", + "//starboard/shared/stub/microphone_get_available.cc", + "//starboard/shared/stub/microphone_is_sample_rate_supported.cc", + "//starboard/shared/stub/microphone_open.cc", + "//starboard/shared/stub/microphone_read.cc", + "//starboard/shared/stub/mutex_acquire.cc", + "//starboard/shared/stub/mutex_acquire_try.cc", + "//starboard/shared/stub/mutex_create.cc", + "//starboard/shared/stub/mutex_destroy.cc", + "//starboard/shared/stub/mutex_release.cc", + "//starboard/shared/stub/once.cc", + "//starboard/shared/stub/player_create.cc", + "//starboard/shared/stub/player_destroy.cc", + "//starboard/shared/stub/player_get_current_frame.cc", + "//starboard/shared/stub/player_get_info.cc", + "//starboard/shared/stub/player_output_mode_supported.cc", + "//starboard/shared/stub/player_seek.cc", + "//starboard/shared/stub/player_set_bounds.cc", + "//starboard/shared/stub/player_set_pause.cc", + "//starboard/shared/stub/player_set_playback_rate.cc", + "//starboard/shared/stub/player_set_volume.cc", + "//starboard/shared/stub/player_write_end_of_stream.cc", + "//starboard/shared/stub/player_write_sample.cc", + "//starboard/shared/stub/socket_accept.cc", + "//starboard/shared/stub/socket_bind.cc", + "//starboard/shared/stub/socket_clear_last_error.cc", + "//starboard/shared/stub/socket_connect.cc", + "//starboard/shared/stub/socket_create.cc", + "//starboard/shared/stub/socket_destroy.cc", + "//starboard/shared/stub/socket_free_resolution.cc", + "//starboard/shared/stub/socket_get_interface_address.cc", + "//starboard/shared/stub/socket_get_last_error.cc", + "//starboard/shared/stub/socket_get_local_address.cc", + "//starboard/shared/stub/socket_get_local_interface_address.cc", + "//starboard/shared/stub/socket_is_connected.cc", + "//starboard/shared/stub/socket_is_connected_and_idle.cc", + "//starboard/shared/stub/socket_join_multicast_group.cc", + "//starboard/shared/stub/socket_listen.cc", + "//starboard/shared/stub/socket_receive_from.cc", + "//starboard/shared/stub/socket_resolve.cc", + "//starboard/shared/stub/socket_send_to.cc", + "//starboard/shared/stub/socket_set_broadcast.cc", + "//starboard/shared/stub/socket_set_receive_buffer_size.cc", + "//starboard/shared/stub/socket_set_reuse_address.cc", + "//starboard/shared/stub/socket_set_send_buffer_size.cc", + "//starboard/shared/stub/socket_set_tcp_keep_alive.cc", + "//starboard/shared/stub/socket_set_tcp_no_delay.cc", + "//starboard/shared/stub/socket_set_tcp_window_scaling.cc", + "//starboard/shared/stub/socket_waiter_add.cc", + "//starboard/shared/stub/socket_waiter_create.cc", + "//starboard/shared/stub/socket_waiter_destroy.cc", + "//starboard/shared/stub/socket_waiter_remove.cc", + "//starboard/shared/stub/socket_waiter_wait.cc", + "//starboard/shared/stub/socket_waiter_wait_timed.cc", + "//starboard/shared/stub/socket_waiter_wake_up.cc", + "//starboard/shared/stub/speech_recognizer_cancel.cc", + "//starboard/shared/stub/speech_recognizer_create.cc", + "//starboard/shared/stub/speech_recognizer_destroy.cc", + "//starboard/shared/stub/speech_recognizer_start.cc", + "//starboard/shared/stub/speech_recognizer_stop.cc", + "//starboard/shared/stub/speech_synthesis_cancel.cc", + "//starboard/shared/stub/speech_synthesis_set_language.cc", + "//starboard/shared/stub/speech_synthesis_speak.cc", + "//starboard/shared/stub/storage_close_record.cc", + "//starboard/shared/stub/storage_delete_record.cc", + "//starboard/shared/stub/storage_get_record_size.cc", + "//starboard/shared/stub/storage_open_record.cc", + "//starboard/shared/stub/storage_read_record.cc", + "//starboard/shared/stub/storage_write_record.cc", + "//starboard/shared/stub/string_compare.cc", + "//starboard/shared/stub/string_compare_all.cc", + "//starboard/shared/stub/string_compare_no_case.cc", + "//starboard/shared/stub/string_compare_no_case_n.cc", + "//starboard/shared/stub/string_compare_wide.cc", + "//starboard/shared/stub/string_concat.cc", + "//starboard/shared/stub/string_concat_wide.cc", + "//starboard/shared/stub/string_copy.cc", + "//starboard/shared/stub/string_copy_wide.cc", + "//starboard/shared/stub/string_duplicate.cc", + "//starboard/shared/stub/string_find_character.cc", + "//starboard/shared/stub/string_find_last_character.cc", + "//starboard/shared/stub/string_find_string.cc", + "//starboard/shared/stub/string_format.cc", + "//starboard/shared/stub/string_format_wide.cc", + "//starboard/shared/stub/string_get_length.cc", + "//starboard/shared/stub/string_get_length_wide.cc", + "//starboard/shared/stub/string_parse_double.cc", + "//starboard/shared/stub/string_parse_signed_integer.cc", + "//starboard/shared/stub/string_parse_uint64.cc", + "//starboard/shared/stub/string_parse_unsigned_integer.cc", + "//starboard/shared/stub/string_scan.cc", + "//starboard/shared/stub/system_binary_search.cc", + "//starboard/shared/stub/system_break_into_debugger.cc", + "//starboard/shared/stub/system_clear_last_error.cc", + "//starboard/shared/stub/system_clear_platform_error.cc", + "//starboard/shared/stub/system_get_connection_type.cc", + "//starboard/shared/stub/system_get_device_type.cc", + "//starboard/shared/stub/system_get_error_string.cc", + "//starboard/shared/stub/system_get_last_error.cc", + "//starboard/shared/stub/system_get_locale_id.cc", + "//starboard/shared/stub/system_get_number_of_processors.cc", + "//starboard/shared/stub/system_get_path.cc", + "//starboard/shared/stub/system_get_property.cc", + "//starboard/shared/stub/system_get_random_data.cc", + "//starboard/shared/stub/system_get_random_uint64.cc", + "//starboard/shared/stub/system_get_stack.cc", + "//starboard/shared/stub/system_get_total_cpu_memory.cc", + "//starboard/shared/stub/system_get_total_gpu_memory.cc", + "//starboard/shared/stub/system_get_used_cpu_memory.cc", + "//starboard/shared/stub/system_get_used_gpu_memory.cc", + "//starboard/shared/stub/system_has_capability.cc", + "//starboard/shared/stub/system_hide_splash_screen.cc", + "//starboard/shared/stub/system_is_debugger_attached.cc", + "//starboard/shared/stub/system_raise_platform_error.cc", + "//starboard/shared/stub/system_request_pause.cc", + "//starboard/shared/stub/system_request_stop.cc", + "//starboard/shared/stub/system_request_suspend.cc", + "//starboard/shared/stub/system_request_unpause.cc", + "//starboard/shared/stub/system_sort.cc", + "//starboard/shared/stub/system_symbolize.cc", + "//starboard/shared/stub/thread_create.cc", + "//starboard/shared/stub/thread_create_local_key.cc", + "//starboard/shared/stub/thread_destroy_local_key.cc", + "//starboard/shared/stub/thread_detach.cc", + "//starboard/shared/stub/thread_get_current.cc", + "//starboard/shared/stub/thread_get_id.cc", + "//starboard/shared/stub/thread_get_local_value.cc", + "//starboard/shared/stub/thread_get_name.cc", + "//starboard/shared/stub/thread_is_equal.cc", + "//starboard/shared/stub/thread_join.cc", + "//starboard/shared/stub/thread_set_local_value.cc", + "//starboard/shared/stub/thread_set_name.cc", + "//starboard/shared/stub/thread_sleep.cc", + "//starboard/shared/stub/thread_types_public.h", + "//starboard/shared/stub/thread_yield.cc", + "//starboard/shared/stub/time_get_monotonic_now.cc", + "//starboard/shared/stub/time_get_monotonic_thread_now.cc", + "//starboard/shared/stub/time_get_now.cc", + "//starboard/shared/stub/time_zone_get_current.cc", + "//starboard/shared/stub/time_zone_get_dst_name.cc", + "//starboard/shared/stub/time_zone_get_name.cc", + "//starboard/shared/stub/user_get_current.cc", + "//starboard/shared/stub/user_get_property.cc", + "//starboard/shared/stub/user_get_signed_in.cc", + "//starboard/shared/stub/window_create.cc", + "//starboard/shared/stub/window_destroy.cc", + "//starboard/shared/stub/window_get_platform_handle.cc", + "//starboard/shared/stub/window_get_size.cc", + "//starboard/shared/stub/window_set_default_options.cc", + "application_stub.cc", + "application_stub.h", + "atomic_public.h", + "main.cc", + "thread_types_public.h", + ] + + # Include private stubs, if present. + private_sources = exec_script("//starboard/tools/find_private_files.py", + [ + rebase_path("//", root_build_dir), + "shared/stub/*.cc", + ], + "list lines", + [ "//starboard/private/shared/stub" ]) + sources += rebase_path(private_sources, ".", root_build_dir) + + defines = [ "STARBOARD_IMPLEMENTATION" ] +}
diff --git a/src/starboard/stub/buildconfig.gni b/src/starboard/stub/buildconfig.gni new file mode 100644 index 0000000..8e4bdee --- /dev/null +++ b/src/starboard/stub/buildconfig.gni
@@ -0,0 +1,36 @@ +# Copyright 2017 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 file is imported into BUILDCONFIG.gn. As a side effect, any variable +# defined here becomes a global variable in all GN files. +# +# Adding new variables to this file could result in variable name conflicts, so +# keep the number of variables in this file to a minimum! +# +# If you need to define a temporary variable, prefix it with an underscore like +# _this. Prefixing a variable with an underscore makes it a private variable +# that won't bleed into other files. +############################################################################### + +# Target OS and CPU. +# BUILDCONFIG.gn sets target_os and target_cpu to the values of these two +# variables below. Unfortunately, due to GN's restrictions on how variables can +# be changed, we can't directly set target_os and target_cpu here. +target_os_ = "linux" +target_cpu_ = "x64" + +# The target and host toolchain +target_toolchain = "//starboard/build/toolchain/linux:clang_x64" +host_toolchain = "//starboard/build/toolchain/linux:clang_$host_cpu"
diff --git a/src/starboard/stub/configuration.gni b/src/starboard/stub/configuration.gni new file mode 100644 index 0000000..55a886e --- /dev/null +++ b/src/starboard/stub/configuration.gni
@@ -0,0 +1,29 @@ +# Copyright 2017 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. + +# Use a stub rasterizer and graphical setup +rasterizer_type = "stub" + +# No GL drivers available +gl_type = "none" + +# Use media source extension implementation that is conformed to the +# Candidate Recommandation of July 5th 2016. +cobalt_use_media_source_2016 = true + +declare_args() { + # Set to true to enable distributed compilation using Goma. By default we + # use Goma for stub and linux. + use_goma = true +}
diff --git a/src/starboard/tools/abstract_launcher.py b/src/starboard/tools/abstract_launcher.py index 65bc1ea..a840cde 100644 --- a/src/starboard/tools/abstract_launcher.py +++ b/src/starboard/tools/abstract_launcher.py
@@ -1,4 +1,5 @@ -#!/usr/bin/python +# +# Copyright 2017 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. @@ -10,59 +11,25 @@ # 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.""" +# limitations under the License. """Abstraction for running Cobalt development tools.""" -import abc -import imp +import importlib import os -import re import sys -platform_module = imp.load_source( - "platform", os.path.abspath( - os.path.join(os.path.dirname(__file__), "platform.py"))) +if "environment" in sys.modules: + environment = sys.modules["environment"] +else: + env_path = os.path.abspath(os.path.dirname(__file__)) + if env_path not in sys.path: + sys.path.append(env_path) + environment = importlib.import_module("environment") -def _GetAllPlatforms(path): - """Retrieves information about all available Cobalt ports. +import abc - Args: - path: Root path that will be crawled to find ports. - - Returns: - Dict mapping available cobalt ports to their respective location in - the filesystem. - """ - platform_dict = {} - for port in platform_module.PlatformInfo.EnumeratePorts(path): - port_name = re.search(".*starboard-(.*)", port.port_name).group(1) - platform_dict[port_name] = port.path - return platform_dict - - -def _GetProjectRoot(): - """Gets the root of this project. - - Returns: - Path to the root of this project - - Raises: - RuntimeError: There is no root. - """ - current_path = os.path.normpath(os.path.dirname(__file__)) - while not os.access(os.path.join(current_path, ".gclient"), os.R_OK): - next_path = os.path.dirname(current_path) - if next_path == current_path: - current_path = None - break - current_path = next_path - client_root = current_path - - if not client_root: - raise RuntimeError("No project root declared.") - - return client_root +import starboard.tools.platform as platform_module def _GetLauncherForPlatform(platform_path): @@ -74,23 +41,9 @@ Returns: The module containing the platform's launcher implementation. """ - - # Necessary because gyp_configuration modules use relative imports. - # "cobalt/build" needs to be in sys.path to keep the imports working - sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), - os.pardir, os.pardir, - "cobalt", "build"))) - - # Necessary because the gyp_configuration for linux-x64x11 imports - # directly from "starboard/". All of this import logic will eventually be - # moved to a configuration system. - sys.path.append(os.path.abspath(os.path.join( - os.path.dirname(__file__), os.pardir, os.pardir))) - - module_path = os.path.abspath(os.path.join(platform_path, - "gyp_configuration.py")) - - gyp_module = imp.load_source("platform_module", module_path) + if platform_path not in sys.path: + sys.path.append(platform_path) + gyp_module = importlib.import_module("gyp_configuration") return gyp_module.CreatePlatformConfig().GetLauncher() @@ -112,8 +65,7 @@ """ # Creates launcher for provided platform if the platform has a valid port - client_root = _GetProjectRoot() - platform_dict = _GetAllPlatforms(client_root) + platform_dict = platform_module.GetAllPorts() if platform in platform_dict: platform_path = platform_dict[platform] launcher_module = _GetLauncherForPlatform(platform_path) @@ -140,7 +92,11 @@ @abc.abstractmethod def Run(self): - """Runs the launcher's executable. Must be implemented in subclasses.""" + """Runs the launcher's executable. Must be implemented in subclasses. + + Returns: + The return code from the launcher's executable. + """ pass @abc.abstractmethod
diff --git a/src/starboard/tools/environment.py b/src/starboard/tools/environment.py new file mode 100644 index 0000000..e792803 --- /dev/null +++ b/src/starboard/tools/environment.py
@@ -0,0 +1,94 @@ +# +# Copyright 2017 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.""" +"""Sets up a Starboard environment for use by the host application. + +Applications that use Starboard should contain a Python file, called +"starboard_configuration.py", somewhere in the ancestor path of their +"starboard" directory. + +The file should contain a variable, called PORT_ROOTS. Assign to it a +list of paths to directories in which Starboard ports are located. +Each path should be represented as a list of directory names whose locations +are relative to the configuration file. Example: + +PORT_ROOTS = [ + ["some_directory", "starboard"] + ["somewhere_else", "starboard"] +] + +IF YOU ARE GOING TO USE STARBOARD FILES OUTSIDE OF STARBOARD, YOU NEED TO IMPORT +THIS MODULE FIRST. Otherwise, sys.path will not be configured properly, none of +your code will work, and you'll be sad. +""" + +import importlib +import os +import sys + +PATHS = [ + # Necessary because the gyp_configuration for linux-x64x11 imports + # directly from "starboard/". + os.path.abspath(os.path.join( + os.path.dirname(__file__), os.pardir, os.pardir)), + + # Necessary because gyp_configuration modules use relative imports. + # "cobalt/build" needs to be in sys.path to keep the imports working + os.path.abspath(os.path.join( + os.path.dirname(__file__), os.pardir, os.pardir, + "cobalt", "build")) +] + +# This module should only add the above paths to sys.path when they are not +# present in the list already. +for new_path in PATHS: + if new_path not in sys.path: + sys.path.append(new_path) + + +def _GetStarboardConfigPath(): + """Gets the path to the "starboard_configuration.py" file from the host app. + + Returns: + Path to the "starboard_configuration.py" file from the host app + + Raises: + RuntimeError: There is no configuration file. + """ + current_path = os.path.normpath(os.path.dirname(__file__)) + while not os.path.exists(os.path.join(current_path, + "starboard_configuration.py")): + next_path = os.path.dirname(current_path) + if next_path == current_path: + current_path = None + break + current_path = next_path + config_path = current_path + + if not config_path: + raise RuntimeError("No starboard configuration declared.") + + return config_path + + +def GetStarboardPortRoots(): + """Gets paths to the host app's Starboard port directories.""" + config_path = _GetStarboardConfigPath() + sys.path.append(config_path) + config_module = importlib.import_module("starboard_configuration") + port_roots = config_module.PORT_ROOTS + port_root_paths = [os.path.abspath(os.path.join( + config_path, os.sep.join(root))) for root in port_roots] + return port_root_paths +
diff --git a/src/starboard/tools/platform.py b/src/starboard/tools/platform.py index 7c760f8..76e3438 100644 --- a/src/starboard/tools/platform.py +++ b/src/starboard/tools/platform.py
@@ -16,8 +16,19 @@ """Functionality to enumerate and represent starboard ports.""" import importlib -import logging import os +import sys + +if "environment" in sys.modules: + environment = sys.modules["environment"] +else: + env_path = os.path.abspath(os.path.dirname(__file__)) + if env_path not in sys.path: + sys.path.append(env_path) + environment = importlib.import_module("environment") + + +import logging import re @@ -61,11 +72,37 @@ return re.sub(r'[^a-zA-Z0-9_]', r'-', directory[start:]) +def _GetAllPlatforms(port_root_paths): + """Retrieves information about all available Cobalt ports. + + Args: + port_root_paths: List of paths that will be crawled to find ports. + + Returns: + Dict mapping each available port to its location in the filesystem. + """ + platform_dict = {} + for path in port_root_paths: + for port in PlatformInfo.EnumeratePorts(path): + platform_dict[port.port_name] = port.path + return platform_dict + + +def GetAllPorts(): + """Gets all available starboard ports from the host app. + + Returns: + Dictionary mapping port names to their path in the filesystem. + """ + port_root_paths = environment.GetStarboardPortRoots() + return _GetAllPlatforms(port_root_paths) + + class PlatformInfo(object): """Information about a specific starboard port.""" @classmethod - def EnumeratePorts(cls, root_path, exclusion_set = None): + def EnumeratePorts(cls, root_path, exclusion_set=None): """Generator that iterates over starboard ports found under |path|.""" if not exclusion_set: exclusion_set = set()
diff --git a/src/starboard/win/lib/gyp_configuration.gypi b/src/starboard/win/lib/gyp_configuration.gypi index 0dec384..e491c37 100644 --- a/src/starboard/win/lib/gyp_configuration.gypi +++ b/src/starboard/win/lib/gyp_configuration.gypi
@@ -16,6 +16,16 @@ 'variables': { 'javascript_engine': 'mozjs', 'cobalt_enable_jit': 0, + # TODO: In theory, there are tools that can combine static libraries into + # thick static libraries with all their transitive dependencies. Using + # shared_library here can have unexpected consequences. Explore building + # this into a thick static library instead. + 'final_executable_type': 'shared_library', + 'default_renderer_options_dependency': '<(DEPTH)/cobalt/renderer/rasterizer/lib/lib.gyp:external_rasterizer', + 'sb_enable_lib': 1, + 'angle_build_winrt': 0, + 'winrt': 0, + 'enable_d3d11_feature_level_11': 1, }, 'includes': [ '../shared/gyp_configuration.gypi', @@ -23,25 +33,18 @@ 'target_defaults': { 'default_configuration': 'win-lib_debug', 'configurations': { - 'lib_base': { - 'abstract': 1, - 'msvs_settings': { - 'VCLinkerTool': { - 'SubSystem': '2', # WINDOWS - } - } - }, + 'win-lib_debug': { - 'inherit_from': ['msvs_debug', 'lib_base'], + 'inherit_from': ['win32_base', 'msvs_debug'], }, 'win-lib_devel': { - 'inherit_from': ['msvs_devel', 'lib_base'], + 'inherit_from': ['win32_base', 'msvs_devel'], }, 'win-lib_qa': { - 'inherit_from': ['msvs_qa', 'lib_base'], + 'inherit_from': ['win32_base', 'msvs_qa'], }, 'win-lib_gold': { - 'inherit_from': ['msvs_gold', 'lib_base'], + 'inherit_from': ['win32_base', 'msvs_gold'], }, }, # end of configurations },
diff --git a/src/starboard/win/lib/main.cc b/src/starboard/win/lib/main.cc deleted file mode 100644 index 2ab7084..0000000 --- a/src/starboard/win/lib/main.cc +++ /dev/null
@@ -1,70 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include <windows.h> - -#include <WinSock2.h> - -#include <string> -#include <vector> - -#include "starboard/configuration.h" -#include "starboard/shared/uwp/application_uwp.h" -#include "starboard/shared/win32/thread_private.h" -#include "starboard/shared/win32/wchar_utils.h" - -using starboard::shared::win32::wchar_tToUTF8; - -// TODO: Share more of this logic with xb1 & win-console? -int main(Platform::Array<Platform::String ^> ^ args) { - if (!IsDebuggerPresent()) { - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); - } - - const int kWinSockVersionMajor = 2; - const int kWinSockVersionMinor = 2; - WSAData wsaData; - int init_result = WSAStartup( - MAKEWORD(kWinSockVersionMajor, kWinSockVersionMajor), &wsaData); - - SB_CHECK(init_result == 0); - // WSAStartup returns the highest version that is supported up to the version - // we request. - SB_CHECK(LOBYTE(wsaData.wVersion) == kWinSockVersionMajor && - HIBYTE(wsaData.wVersion) == kWinSockVersionMinor); - - starboard::shared::win32::RegisterMainThread(); - - std::vector<std::string> string_args; - for (auto it = args->begin(); it != args->end(); ++it) { - Platform::String ^ s = *it; - string_args.push_back(wchar_tToUTF8(s->Data(), s->Length())); - } - - std::vector<const char*> utf8_args; - for (auto it = string_args.begin(); it != string_args.end(); ++it) { - utf8_args.push_back(it->data()); - } - - starboard::shared::uwp::ApplicationUwp application; - int return_value = application.Run(static_cast<int>(utf8_args.size()), - const_cast<char**>(utf8_args.data())); - - WSACleanup(); - - return return_value; -}
diff --git a/src/starboard/win/lib/starboard_platform.gyp b/src/starboard/win/lib/starboard_platform.gyp index d61cc40..04fd716 100644 --- a/src/starboard/win/lib/starboard_platform.gyp +++ b/src/starboard/win/lib/starboard_platform.gyp
@@ -14,7 +14,6 @@ { 'includes': [ '../shared/starboard_platform.gypi', - '../../shared/uwp/starboard_platform.gypi' ], 'variables': { 'starboard_platform_dependent_files': [ @@ -22,6 +21,21 @@ 'configuration_public.h', 'thread_types_public.h', '../shared/system_get_path.cc', + '<(DEPTH)/starboard/shared/starboard/localized_strings.cc', + '<(DEPTH)/starboard/shared/starboard/localized_strings.cc', + '<(DEPTH)/starboard/shared/starboard/queue_application.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc', + '<(DEPTH)/starboard/shared/stub/decode_target_get_info.cc', + '<(DEPTH)/starboard/shared/stub/decode_target_release.cc', + '<@(uwp_incompatible_win32)', + '<@(stub_media_player)' ], - } + }, }
diff --git a/src/starboard/win/shared/starboard_platform.gypi b/src/starboard/win/shared/starboard_platform.gypi index 7134bee..43ec50b 100644 --- a/src/starboard/win/shared/starboard_platform.gypi +++ b/src/starboard/win/shared/starboard_platform.gypi
@@ -17,6 +17,16 @@ 'winrt%': 1, 'stub_media_player': [ ], + + 'stub_drm_system': [ + '<(DEPTH)/starboard/shared/stub/drm_close_session.cc', + '<(DEPTH)/starboard/shared/stub/drm_create_system.cc', + '<(DEPTH)/starboard/shared/stub/drm_destroy_system.cc', + '<(DEPTH)/starboard/shared/stub/drm_generate_session_update_request.cc', + '<(DEPTH)/starboard/shared/stub/drm_system_internal.h', + '<(DEPTH)/starboard/shared/stub/drm_update_session.cc', + ], + # TODO: Move this and the win32 dependencies below to a shared/win32/starboard_platform.gypi? 'uwp_incompatible_win32': [ '<(DEPTH)/starboard/shared/win32/application_win32_key_event.cc', @@ -27,6 +37,8 @@ '<(DEPTH)/starboard/shared/win32/system_clear_platform_error.cc', '<(DEPTH)/starboard/shared/win32/system_get_device_type.cc', '<(DEPTH)/starboard/shared/win32/system_get_property.cc', + '<(DEPTH)/starboard/shared/win32/system_get_total_cpu_memory.cc', + '<(DEPTH)/starboard/shared/win32/system_get_used_cpu_memory.cc', '<(DEPTH)/starboard/shared/win32/system_raise_platform_error.cc', '<(DEPTH)/starboard/shared/win32/window_create.cc', '<(DEPTH)/starboard/shared/win32/window_destroy.cc', @@ -226,12 +238,6 @@ '<(DEPTH)/starboard/shared/stub/cryptography_set_authenticated_data.cc', '<(DEPTH)/starboard/shared/stub/cryptography_set_initialization_vector.cc', '<(DEPTH)/starboard/shared/stub/cryptography_transform.cc', - '<(DEPTH)/starboard/shared/stub/drm_close_session.cc', - '<(DEPTH)/starboard/shared/stub/drm_create_system.cc', - '<(DEPTH)/starboard/shared/stub/drm_destroy_system.cc', - '<(DEPTH)/starboard/shared/stub/drm_generate_session_update_request.cc', - '<(DEPTH)/starboard/shared/stub/drm_system_internal.h', - '<(DEPTH)/starboard/shared/stub/drm_update_session.cc', '<(DEPTH)/starboard/shared/stub/image_decode.cc', '<(DEPTH)/starboard/shared/stub/image_is_decode_supported.cc', '<(DEPTH)/starboard/shared/stub/media_set_output_protection.cc', @@ -334,8 +340,6 @@ '<(DEPTH)/starboard/shared/win32/system_get_connection_type.cc', '<(DEPTH)/starboard/shared/win32/system_get_error_string.cc', '<(DEPTH)/starboard/shared/win32/system_get_number_of_processors.cc', - '<(DEPTH)/starboard/shared/win32/system_get_total_cpu_memory.cc', - '<(DEPTH)/starboard/shared/win32/system_get_used_cpu_memory.cc', '<(DEPTH)/starboard/shared/win32/socket_set_broadcast.cc', '<(DEPTH)/starboard/shared/win32/socket_set_receive_buffer_size.cc', '<(DEPTH)/starboard/shared/win32/socket_set_reuse_address.cc',
diff --git a/src/starboard/win/lib/atomic_public.h b/src/starboard/win/win32/lib/atomic_public.h similarity index 81% rename from src/starboard/win/lib/atomic_public.h rename to src/starboard/win/win32/lib/atomic_public.h index be4e805..b85fb12 100644 --- a/src/starboard/win/lib/atomic_public.h +++ b/src/starboard/win/win32/lib/atomic_public.h
@@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ -#define STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +#ifndef STARBOARD_WIN_WIN32_LIB_ATOMIC_PUBLIC_H_ +#define STARBOARD_WIN_WIN32_LIB_ATOMIC_PUBLIC_H_ #include "starboard/shared/win32/atomic_public.h" -#endif // STARBOARD_WIN_LIB_ATOMIC_PUBLIC_H_ +#endif // STARBOARD_WIN_WIN32_LIB_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/win/lib/configuration_public.h b/src/starboard/win/win32/lib/configuration_public.h similarity index 82% rename from src/starboard/win/lib/configuration_public.h rename to src/starboard/win/win32/lib/configuration_public.h index 800aeb1..8b5f8b1 100644 --- a/src/starboard/win/lib/configuration_public.h +++ b/src/starboard/win/win32/lib/configuration_public.h
@@ -15,9 +15,9 @@ // Other source files should never include this header directly, but should // include the generic "starboard/configuration.h" instead. -#ifndef STARBOARD_WIN_LIB_CONFIGURATION_PUBLIC_H_ -#define STARBOARD_WIN_LIB_CONFIGURATION_PUBLIC_H_ +#ifndef STARBOARD_WIN_WIN32_LIB_CONFIGURATION_PUBLIC_H_ +#define STARBOARD_WIN_WIN32_LIB_CONFIGURATION_PUBLIC_H_ #include "starboard/win/shared/configuration_public.h" -#endif // STARBOARD_WIN_LIB_CONFIGURATION_PUBLIC_H_ +#endif // STARBOARD_WIN_WIN32_LIB_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/win/win32/lib/gyp_configuration.gypi b/src/starboard/win/win32/lib/gyp_configuration.gypi new file mode 100644 index 0000000..7d8ddb2 --- /dev/null +++ b/src/starboard/win/win32/lib/gyp_configuration.gypi
@@ -0,0 +1,51 @@ +# Copyright 2017 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. + +{ + 'variables': { + 'javascript_engine': 'mozjs', + 'cobalt_enable_jit': 0, + # TODO: In theory, there are tools that can combine static libraries into + # thick static libraries with all their transitive dependencies. Using + # shared_library here can have unexpected consequences. Explore building + # this into a thick static library instead. + 'final_executable_type': 'shared_library', + 'default_renderer_options_dependency': '<(DEPTH)/cobalt/renderer/rasterizer/lib/lib.gyp:external_rasterizer', + 'sb_enable_lib': 1, + 'angle_build_winrt': 0, + 'winrt': 0, + 'enable_d3d11_feature_level_11': 1, + }, + 'includes': [ + '../../shared/gyp_configuration.gypi', + ], + 'target_defaults': { + 'default_configuration': 'win-win32-lib_debug', + 'configurations': { + + 'win-win32-lib_debug': { + 'inherit_from': ['win32_base', 'msvs_debug'], + }, + 'win-win32-lib_devel': { + 'inherit_from': ['win32_base', 'msvs_devel'], + }, + 'win-win32-lib_qa': { + 'inherit_from': ['win32_base', 'msvs_qa'], + }, + 'win-win32-lib_gold': { + 'inherit_from': ['win32_base', 'msvs_gold'], + }, + }, # end of configurations + }, +}
diff --git a/src/starboard/win/lib/gyp_configuration.py b/src/starboard/win/win32/lib/gyp_configuration.py similarity index 88% rename from src/starboard/win/lib/gyp_configuration.py rename to src/starboard/win/win32/lib/gyp_configuration.py index e136082..0d1deeb 100644 --- a/src/starboard/win/lib/gyp_configuration.py +++ b/src/starboard/win/win32/lib/gyp_configuration.py
@@ -21,13 +21,13 @@ os.path.realpath( os.path.join( os.path.dirname(__file__), os.pardir, - os.pardir, 'shared', 'win32'))) + os.pardir, os.pardir, 'shared', 'win32'))) import gyp_configuration def CreatePlatformConfig(): try: - return gyp_configuration.PlatformConfig('win-lib') + return gyp_configuration.PlatformConfig('win-win32-lib') except RuntimeError as e: logging.critical(e) return None
diff --git a/src/starboard/win/win32/lib/starboard_platform.gyp b/src/starboard/win/win32/lib/starboard_platform.gyp new file mode 100644 index 0000000..7216017 --- /dev/null +++ b/src/starboard/win/win32/lib/starboard_platform.gyp
@@ -0,0 +1,23 @@ +# Copyright 2017 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. +{ + 'includes': [ + '../starboard_platform.gypi', + ], + 'variables': { + 'starboard_platform_dependent_files': [ + '<@(base_win32_starboard_platform_dependent_files)', + ] + }, +}
diff --git a/src/starboard/win/lib/starboard_platform_tests.gyp b/src/starboard/win/win32/lib/starboard_platform_tests.gyp similarity index 96% rename from src/starboard/win/lib/starboard_platform_tests.gyp rename to src/starboard/win/win32/lib/starboard_platform_tests.gyp index 1eb83ba..8961deb 100644 --- a/src/starboard/win/lib/starboard_platform_tests.gyp +++ b/src/starboard/win/win32/lib/starboard_platform_tests.gyp
@@ -38,7 +38,7 @@ 'variables': { 'executable_name': 'starboard_platform_tests', }, - 'includes': [ '../../build/deploy.gypi' ], + 'includes': [ '../../../build/deploy.gypi' ], }, ], }
diff --git a/src/starboard/win/lib/thread_types_public.h b/src/starboard/win/win32/lib/thread_types_public.h similarity index 81% rename from src/starboard/win/lib/thread_types_public.h rename to src/starboard/win/win32/lib/thread_types_public.h index 0f8f791..adc6221 100644 --- a/src/starboard/win/lib/thread_types_public.h +++ b/src/starboard/win/win32/lib/thread_types_public.h
@@ -14,9 +14,9 @@ // Includes threading primitive types and initializers. -#ifndef STARBOARD_WIN_LIB_THREAD_TYPES_PUBLIC_H_ -#define STARBOARD_WIN_LIB_THREAD_TYPES_PUBLIC_H_ +#ifndef STARBOARD_WIN_WIN32_LIB_THREAD_TYPES_PUBLIC_H_ +#define STARBOARD_WIN_WIN32_LIB_THREAD_TYPES_PUBLIC_H_ #include "starboard/shared/win32/thread_types_public.h" -#endif // STARBOARD_WIN_LIB_THREAD_TYPES_PUBLIC_H_ +#endif // STARBOARD_WIN_WIN32_LIB_THREAD_TYPES_PUBLIC_H_
diff --git a/src/starboard/win/win32/starboard_platform.gyp b/src/starboard/win/win32/starboard_platform.gyp index 9373b0a..2027d45 100644 --- a/src/starboard/win/win32/starboard_platform.gyp +++ b/src/starboard/win/win32/starboard_platform.gyp
@@ -1,40 +1,24 @@ -# Copyright 2017 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. -{ - 'includes': [ - '../shared/starboard_platform.gypi', - ], - 'variables': { - 'starboard_platform_dependent_files': [ - 'atomic_public.h', - 'configuration_public.h', - 'thread_types_public.h', - '../shared/system_get_path.cc', - 'main.cc', - '<(DEPTH)/starboard/shared/starboard/localized_strings.cc', - '<(DEPTH)/starboard/shared/starboard/localized_strings.cc', - '<(DEPTH)/starboard/shared/starboard/queue_application.cc', - '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc', - '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc', - '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc', - '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc', - '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc', - '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc', - '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc', - '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc', - '<@(uwp_incompatible_win32)', - '<@(stub_media_player)' - ] - }, - } +# Copyright 2017 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. +{ + 'includes': [ + 'starboard_platform.gypi', + ], + 'variables': { + 'starboard_platform_dependent_files': [ + 'main.cc', + '<@(base_win32_starboard_platform_dependent_files)', + ] + }, +}
diff --git a/src/starboard/win/win32/starboard_platform.gypi b/src/starboard/win/win32/starboard_platform.gypi new file mode 100644 index 0000000..254ae7b --- /dev/null +++ b/src/starboard/win/win32/starboard_platform.gypi
@@ -0,0 +1,42 @@ +# Copyright 2017 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. +{ + 'includes': [ + '../shared/starboard_platform.gypi', + ], + 'variables': { + 'base_win32_starboard_platform_dependent_files': [ + 'atomic_public.h', + 'configuration_public.h', + 'thread_types_public.h', + '<(DEPTH)/starboard/shared/starboard/localized_strings.cc', + '<(DEPTH)/starboard/shared/starboard/localized_strings.cc', + '<(DEPTH)/starboard/shared/starboard/queue_application.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_pause.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_stop.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_suspend.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc', + '<(DEPTH)/starboard/shared/starboard/system_request_unpause.cc', + '<(DEPTH)/starboard/shared/stub/decode_target_get_info.cc', + '<(DEPTH)/starboard/shared/stub/decode_target_release.cc', + '<(DEPTH)/starboard/win/shared/system_get_path.cc', + '<@(uwp_incompatible_win32)', + '<@(stub_media_player)', + '<@(stub_drm_system)' , + ], + }, +}
diff --git a/src/starboard_configuration.py b/src/starboard_configuration.py new file mode 100644 index 0000000..36eb366 --- /dev/null +++ b/src/starboard_configuration.py
@@ -0,0 +1,22 @@ +#!/usr/bin/python +# +# 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.""" +"""Definition of interface used by host apps to configure Starboard""" + +# List of paths to directories in which Starboard ports are located. +# Each path should be represented as a list of directory names whose locations +# are relative to the location of this file. +PORT_ROOTS = [ + ["starboard"], + ["third_party", "starboard"] +]
diff --git a/src/testing/gmock/BUILD.gn b/src/testing/gmock/BUILD.gn new file mode 100644 index 0000000..1d27016 --- /dev/null +++ b/src/testing/gmock/BUILD.gn
@@ -0,0 +1,53 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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. + +config("gmock_direct_config") { + include_dirs = [ "include" ] +} + +static_library("gmock") { + testonly = true + sources = [ + "include/gmock/gmock-actions.h", + "include/gmock/gmock-cardinalities.h", + "include/gmock/gmock-generated-actions.h", + "include/gmock/gmock-generated-function-mockers.h", + "include/gmock/gmock-generated-matchers.h", + "include/gmock/gmock-generated-nice-strict.h", + "include/gmock/gmock-matchers.h", + "include/gmock/gmock-spec-builders.h", + "include/gmock/gmock.h", + "include/gmock/internal/gmock-generated-internal-utils.h", + "include/gmock/internal/gmock-internal-utils.h", + "include/gmock/internal/gmock-port.h", + "src/gmock-cardinalities.cc", + "src/gmock-internal-utils.cc", + "src/gmock-matchers.cc", + "src/gmock-spec-builders.cc", + "src/gmock.cc", + "../gmock_mutant.h", + ] + + include_dirs = [ "." ] + + public_configs = [ ":gmock_direct_config" ] + + public_deps = [ + "//testing/gtest", + ] +}
diff --git a/src/testing/gtest/BUILD.gn b/src/testing/gtest/BUILD.gn new file mode 100644 index 0000000..0324adf --- /dev/null +++ b/src/testing/gtest/BUILD.gn
@@ -0,0 +1,78 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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. + +config("gtest_direct_config") { + include_dirs = [ "include" ] + + defines = [ + "UNIT_TEST", + "GTEST_HAS_POSIX_RE=0", + ] + if (target_cpu != "ps4" && target_os != "win") { + defines += [ "GTEST_USE_OWN_TR1_TUPLE=1" ] + } +} + +static_library("gtest") { + testonly = true + sources = [ + "include/gtest/gtest-death-test.h", + "include/gtest/gtest-message.h", + "include/gtest/gtest-param-test.h", + "include/gtest/gtest-printers.h", + "include/gtest/gtest-spi.h", + "include/gtest/gtest-test-part.h", + "include/gtest/gtest-typed-test.h", + "include/gtest/gtest.h", + "include/gtest/gtest_pred_impl.h", + "include/gtest/internal/gtest-death-test-internal.h", + "include/gtest/internal/gtest-filepath.h", + "include/gtest/internal/gtest-internal.h", + "include/gtest/internal/gtest-linked_ptr.h", + "include/gtest/internal/gtest-param-util-generated.h", + "include/gtest/internal/gtest-param-util.h", + "include/gtest/internal/gtest-port.h", + "include/gtest/internal/gtest-string.h", + "include/gtest/internal/gtest-tuple.h", + "include/gtest/internal/gtest-type-util.h", + "src/gtest-death-test.cc", + "src/gtest-filepath.cc", + "src/gtest-internal-inl.h", + "src/gtest-port.cc", + "src/gtest-printers.cc", + "src/gtest-test-part.cc", + "src/gtest-typed-test.cc", + "src/gtest.cc", + "../multiprocess_func_list.cc", + "../multiprocess_func_list.h", + "../platform_test.h", + ] + + include_dirs = [ "." ] + + public_configs = [ ":gtest_direct_config" ] + + # Ideally we would want to remove + # //starboard/build/config:default_rtti from the list of configs too. + # Unfortunately GN doesn't provide us a way to remove things from + # dependents' configs list. + # It happens to be that all_dependent_configs get processed after default + # configs, so the -frtti flag comes after the -fno-rtti flag on the command + # line, so it happens to work in this case. + all_dependent_configs = [ "//starboard/build/config:rtti" ] +}
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/RendererD3D.h b/src/third_party/angle/src/libANGLE/renderer/d3d/RendererD3D.h index 7ae203d..bf0323e 100644 --- a/src/third_party/angle/src/libANGLE/renderer/d3d/RendererD3D.h +++ b/src/third_party/angle/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -218,7 +218,7 @@ virtual gl::Error generateMipmapUsingD3D(TextureStorage *storage, const gl::TextureState &textureState) = 0; virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) = 0; - virtual TextureStorage *createTextureStorage2D(IUnknown *texture, bool bindChroma, UINT arrayIndex) = 0; + virtual TextureStorage *createTextureStorage2D(IUnknown *texture, bool bindChroma, IUnknown *dxgiBuffer) = 0; virtual TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage, RenderTargetD3D *renderTargetD3D) = 0; virtual TextureStorage *createTextureStorageExternal(
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp b/src/third_party/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp index 2d0e74e..4f10d28 100644 --- a/src/third_party/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp +++ b/src/third_party/angle/src/libANGLE/renderer/d3d/SurfaceD3D.cpp
@@ -76,7 +76,7 @@ mShareHandle(0), mD3DTexture(nullptr), mBuftype(buftype), - mArrayIndex(0), + mDXGIBuffer(nullptr), mBindChroma(false) { if (window != nullptr && !mFixedSize) @@ -104,14 +104,12 @@ GetPrivateData(kCobaltNv12BindChroma, &out, nullptr); mBindChroma = (SUCCEEDED(hr)) && (out != 0); - // kCobaltDxgiBuffer - IMFDXGIBuffer* dxgi_buffer = nullptr; - out = sizeof(dxgi_buffer); + out = sizeof(mDXGIBuffer); hr = static_cast<ID3D11DeviceChild*>(mD3DTexture)-> - GetPrivateData(kCobaltDxgiBuffer, &out, &dxgi_buffer); + GetPrivateData(kCobaltDxgiBuffer, &out, &mDXGIBuffer); ASSERT(SUCCEEDED(hr)); - if (dxgi_buffer != nullptr) { - dxgi_buffer->GetSubresourceIndex(&mArrayIndex); + if (mDXGIBuffer != nullptr) { + mDXGIBuffer->AddRef(); } break; } @@ -126,6 +124,7 @@ releaseSwapChain(); SafeDelete(mNativeWindow); SafeRelease(mD3DTexture); + SafeRelease(mDXGIBuffer); } void SurfaceD3D::releaseSwapChain()
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h b/src/third_party/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h index b698228..9d6f39a 100644 --- a/src/third_party/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h +++ b/src/third_party/angle/src/libANGLE/renderer/d3d/SurfaceD3D.h
@@ -67,9 +67,9 @@ return mBindChroma; } - UINT getArrayIndex() const + IUnknown* getDxgiBuffer() const { - return mArrayIndex; + return mDXGIBuffer; } protected: @@ -106,7 +106,7 @@ HANDLE mShareHandle; IUnknown *mD3DTexture; EGLenum mBuftype; - UINT mArrayIndex; + IUnknown *mDXGIBuffer; bool mBindChroma; };
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp b/src/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp index e197dc9..fc7d6d1 100644 --- a/src/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp +++ b/src/third_party/angle/src/libANGLE/renderer/d3d/TextureD3D.cpp
@@ -1177,7 +1177,7 @@ if (surfaceD3D->getSwapChain() == nullptr) mTexStorage = mRenderer->createTextureStorage2D( surfaceD3D->getD3DTexture(), surfaceD3D->getBindChroma(), - surfaceD3D->getArrayIndex()); + surfaceD3D->getDxgiBuffer()); else mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain()); mEGLImageTarget = false;
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp index 6c2e9ad..518b65e 100644 --- a/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp +++ b/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -4045,9 +4045,9 @@ TextureStorage *Renderer11::createTextureStorage2D(IUnknown *texture, bool bindChroma, - UINT arrayIndex) + IUnknown *dxgiBuffer) { - return new TextureStorage11_2D(this, texture, bindChroma, arrayIndex); + return new TextureStorage11_2D(this, texture, bindChroma, dxgiBuffer); } TextureStorage *Renderer11::createTextureStorageEGLImage(EGLImageD3D *eglImage,
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h index 58c2406..459a913 100644 --- a/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h +++ b/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -265,7 +265,7 @@ TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) override; TextureStorage *createTextureStorage2D(IUnknown *texture, bool bindChroma, - UINT arrayIndex) override; + IUnknown *dxgiBuffer) override; TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage, RenderTargetD3D *renderTargetD3D) override; TextureStorage *createTextureStorageExternal(
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp b/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp index eb67992..a7cdcc0 100644 --- a/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp +++ b/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
@@ -8,6 +8,8 @@ // classes TextureStorage11_2D and TextureStorage11_Cube, which act as the interface to the D3D11 // texture. +#include <mfobjects.h> + #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h" #include <tuple> @@ -30,6 +32,22 @@ #include "starboard/log.h" +namespace +{ +// This GUID is used for a D3D private data property that allows +// us to keep the associated IMFDXGIBuffer (if any) alive as long +// as the shader resource view is alive. Video decoders re-use the same +// textures, but they track their lifetime by watching the lifetime of +// the IMFDXGIBuffer. So the IMFDXGIBuffer must be kept alive as long +// as the texture may still be used to draw a given video frame. +static const GUID kCobaltKeepAlive = { /* 99a98f3c-37d9-46db-b6a6-bc83c96090e9 */ + 0x99a98f3c, + 0x37d9, + 0x46db, + {0xb6, 0xa6, 0xbc, 0x83, 0xc9, 0x60, 0x90, 0xe9} + }; +} + namespace rx { @@ -717,7 +735,7 @@ mUseLevelZeroTexture(false), mSwizzleTexture(nullptr), mBindChroma(false), - mArrayIndex(0) + mDxgiBuffer(nullptr) { mTexture->AddRef(); @@ -739,7 +757,7 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer11 *renderer, IUnknown *texture, bool bindChroma, - UINT arrayIndex) + IUnknown *dxgiBuffer) : TextureStorage11(renderer, 0, 0, @@ -750,9 +768,13 @@ mUseLevelZeroTexture(false), mSwizzleTexture(nullptr), mBindChroma(bindChroma), - mArrayIndex(arrayIndex) + mDxgiBuffer(dxgiBuffer) { mTexture->AddRef(); + if (mDxgiBuffer != nullptr) + { + mDxgiBuffer->AddRef(); + } for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { @@ -789,7 +811,9 @@ mLevelZeroTexture(nullptr), mLevelZeroRenderTarget(nullptr), mUseLevelZeroTexture(hintLevelZeroOnly && levels > 1), - mSwizzleTexture(nullptr) + mSwizzleTexture(nullptr), + mBindChroma(nullptr), + mDxgiBuffer(nullptr) { for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) { @@ -827,6 +851,7 @@ } SafeRelease(mTexture); + SafeRelease(mDxgiBuffer); SafeRelease(mSwizzleTexture); SafeRelease(mLevelZeroTexture); @@ -1207,10 +1232,16 @@ d3Texture->GetDesc(&texture_desc); if (texture_desc.Format == DXGI_FORMAT_NV12) { + UINT arrayIndex = 0; + if (mDxgiBuffer != nullptr) + { + static_cast<IMFDXGIBuffer*>(mDxgiBuffer)-> + GetSubresourceIndex(&arrayIndex); + } srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MostDetailedMip = mTopLevel + baseLevel; srvDesc.Texture2DArray.MipLevels = mipLevels; - srvDesc.Texture2DArray.FirstArraySlice = mArrayIndex; + srvDesc.Texture2DArray.FirstArraySlice = arrayIndex; srvDesc.Texture2DArray.ArraySize = 1; if (mBindChroma) @@ -1256,6 +1287,9 @@ d3d11::SetDebugName(*outSRV, "TexStorage2D.SRV"); + result = (*outSRV)->SetPrivateDataInterface(kCobaltKeepAlive, mDxgiBuffer); + ASSERT(SUCCEEDED(result)); + return gl::NoError(); }
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h b/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h index 006b427..366c7ea3 100644 --- a/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h +++ b/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.h
@@ -157,7 +157,7 @@ TextureStorage11_2D(Renderer11 *renderer, IUnknown *texture, bool bindChroma, - unsigned int arrayIndex); + IUnknown *dxgiBuffer); TextureStorage11_2D(Renderer11 *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels, bool hintLevelZeroOnly = false); ~TextureStorage11_2D() override; @@ -212,7 +212,7 @@ Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; bool mBindChroma; - UINT mArrayIndex; + IUnknown *mDxgiBuffer; }; class TextureStorage11_External : public TextureStorage11
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp index 6c62416..3b8b293 100644 --- a/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp +++ b/src/third_party/angle/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
@@ -1307,7 +1307,12 @@ extensions->textureNPOT = GetNPOTTextureSupport(featureLevel); extensions->drawBuffers = GetMaximumSimultaneousRenderTargets(featureLevel) > 1; extensions->textureStorage = true; - extensions->textureFilterAnisotropic = true; + // Anisotropic filtering isn't supported completely; in particular, it + // does not work correctly when interacting with glSamplerParameterf as + // GL_TEXTURE_MAX_ANISOTROPY_EXT is not considered a valid parameter name. + // So, although there is partial support at least, we explicitly disable it + // as normal use of the parameter causes GL errors. + extensions->textureFilterAnisotropic = false; extensions->maxTextureAnisotropy = GetMaximumAnisotropy(featureLevel); extensions->occlusionQueryBoolean = GetOcclusionQuerySupport(featureLevel); extensions->fence = GetEventQuerySupport(featureLevel);
diff --git a/src/third_party/angle/src/libGLESv2.gypi b/src/third_party/angle/src/libGLESv2.gypi index 706102c..14b9bf2 100644 --- a/src/third_party/angle/src/libGLESv2.gypi +++ b/src/third_party/angle/src/libGLESv2.gypi
@@ -1176,7 +1176,14 @@ { 'msvs_requires_importlibrary' : 'true', }], + ['angle_gl_library_type== "shared_library"', + { + 'defines':[ + 'LIBGLESV2_DLL' + ] + }], ], + }, {
diff --git a/src/third_party/angle/src/libGLESv2/global_state.cpp b/src/third_party/angle/src/libGLESv2/global_state.cpp index c5f3dfe..121e7e0 100644 --- a/src/third_party/angle/src/libGLESv2/global_state.cpp +++ b/src/third_party/angle/src/libGLESv2/global_state.cpp
@@ -76,7 +76,7 @@ } // namespace egl -#ifdef ANGLE_PLATFORM_WINDOWS +#if defined(ANGLE_PLATFORM_WINDOWS) && defined(LIBGLESV2_DLL) namespace egl { @@ -145,4 +145,4 @@ return TRUE; } -#endif // ANGLE_PLATFORM_WINDOWS +#endif // defined(ANGLE_PLATFORM_WINDOWS) && defined(LIBGLESV2_DLL)
diff --git a/src/third_party/blink/Source/bindings/scripts/utilities.py b/src/third_party/blink/Source/bindings/scripts/utilities.py index 02a1c6c..ed8e5e9 100644 --- a/src/third_party/blink/Source/bindings/scripts/utilities.py +++ b/src/third_party/blink/Source/bindings/scripts/utilities.py
@@ -14,26 +14,21 @@ import string import subprocess -# Interfaces related to css are under the cssom directory. -# All of Cobalt's interfaces are under the dom directory. -# Interfaces related to testing the bindings generation are under testing. -# Interfaces to our custom debugging functionality (e.g. console) is in debug. +# All of Cobalt's interfaces are under either the cobalt/, starboard/ or +# third_party/ directory. +# Note that an IDL's "component" is not actually used for anything in Cobalt and +# so this list just acts as a file path whitelist (i.e. one of these items must +# appear in the path). KNOWN_COMPONENTS = frozenset( [ - 'audio', - 'cssom', - 'debug', - 'dom', - 'fetch', - 'h5vcc', - 'media_session', - 'page_visibility', - 'speech', + 'cobalt', + 'starboard', + 'third_party', + # This is required to pass the Cobalt run_cobalt_bindings_tests.py, + # which is run on presubmit. 'testing', - 'web_animations', - 'webdriver', - 'websocket', - 'xhr', + # Required to identify the generated window_constructors.idl. + 'gen', ]) # List of regular expressions finding tokens that would appear in a name that
diff --git a/src/third_party/dlmalloc/BUILD.gn b/src/third_party/dlmalloc/BUILD.gn new file mode 100644 index 0000000..3811508 --- /dev/null +++ b/src/third_party/dlmalloc/BUILD.gn
@@ -0,0 +1,30 @@ +# Copyright (c) 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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. + +static_library("dlmalloc") { + sources = [ + "dlmalloc.c", + ] + + if (target_os == "win") { + # Compile dlmalloc.c as C++ on MSVC. + cflags += [ "/TP" ] + } else if (target_cpu == "android") { + cflags += [ "-std=c99" ] + } +}
diff --git a/src/third_party/libevent/BUILD.gn b/src/third_party/libevent/BUILD.gn new file mode 100644 index 0000000..7cc526c --- /dev/null +++ b/src/third_party/libevent/BUILD.gn
@@ -0,0 +1,76 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Modifications Copyright 2017 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. + + +import("//starboard/build/config/base.gni") + +# Starboard porters can set platform defaults for the following variable in +# //$starboard_path/configuration.gni. + +# Use the system libevent instead of the bundled one. +if (!defined(use_system_libevent)) { + use_system_libevent = false +} + +if (!use_system_libevent) { + static_library("libevent") { + sources = [ + "epoll.c", + "event.c", + "evutil.c", + "log.c", + ] + + defines = [ "HAVE_CONFIG_H" ] + + include_dirs = [ "starboard" ] + + if (sb_libevent_method != "poll" && sb_libevent_method != "epoll") { + sources += [ "poll.c" ] + } + + if (target_os == "linux") { + sources += [ + "epoll_sub.c", + ] + + include_dirs += [ "starboard/linux" ] + } + + # TODO: Make this android specific, not a linux copy. + if (target_os == "android") { + sources += [ + "epoll_sub.c", + ] + + include_dirs += [ "starboard/linux" ] + } + + if (target_os == "orbis") { + include_dirs += [ "starboard/ps4" ] + } + } +} else { + config("libevent_config") { + defines = [ "USE_SYSTEM_LIBEVENT" ] + } + + group("libevent") { + public_configs = [ ":libevent_config" ] + } +}
diff --git a/src/third_party/libvpx/BUILD.gn b/src/third_party/libvpx/BUILD.gn new file mode 100644 index 0000000..2e8535a --- /dev/null +++ b/src/third_party/libvpx/BUILD.gn
@@ -0,0 +1,163 @@ +# Copyright 2017 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. + +libvpx_source = "//third_party/libvpx" + +static_library("libvpx") { + # This list was generated by running configure and then + # make libvpx_srcs.txt + sources = [ + "platforms/linux-x64/vp9_rtcd.h", + "platforms/linux-x64/vpx_config.c", + "platforms/linux-x64/vpx_config.h", + "platforms/linux-x64/vpx_dsp_rtcd.h", + "platforms/linux-x64/vpx_scale_rtcd.h", + "platforms/linux-x64/vpx_version.h", + "vp9/common/vp9_alloccommon.c", + "vp9/common/vp9_alloccommon.h", + "vp9/common/vp9_blockd.c", + "vp9/common/vp9_blockd.h", + "vp9/common/vp9_common.h", + "vp9/common/vp9_common_data.c", + "vp9/common/vp9_common_data.h", + "vp9/common/vp9_debugmodes.c", + "vp9/common/vp9_entropy.c", + "vp9/common/vp9_entropy.h", + "vp9/common/vp9_entropymode.c", + "vp9/common/vp9_entropymode.h", + "vp9/common/vp9_entropymv.c", + "vp9/common/vp9_entropymv.h", + "vp9/common/vp9_enums.h", + "vp9/common/vp9_filter.c", + "vp9/common/vp9_filter.h", + "vp9/common/vp9_frame_buffers.c", + "vp9/common/vp9_frame_buffers.h", + "vp9/common/vp9_idct.c", + "vp9/common/vp9_idct.h", + "vp9/common/vp9_loopfilter.c", + "vp9/common/vp9_loopfilter.h", + "vp9/common/vp9_mv.h", + "vp9/common/vp9_mvref_common.c", + "vp9/common/vp9_mvref_common.h", + "vp9/common/vp9_onyxc_int.h", + "vp9/common/vp9_ppflags.h", + "vp9/common/vp9_pred_common.c", + "vp9/common/vp9_pred_common.h", + "vp9/common/vp9_quant_common.c", + "vp9/common/vp9_quant_common.h", + "vp9/common/vp9_reconinter.c", + "vp9/common/vp9_reconinter.h", + "vp9/common/vp9_reconintra.c", + "vp9/common/vp9_reconintra.h", + "vp9/common/vp9_rtcd.c", + "vp9/common/vp9_scale.c", + "vp9/common/vp9_scale.h", + "vp9/common/vp9_scan.c", + "vp9/common/vp9_scan.h", + "vp9/common/vp9_seg_common.c", + "vp9/common/vp9_seg_common.h", + "vp9/common/vp9_textblit.h", + "vp9/common/vp9_thread_common.c", + "vp9/common/vp9_thread_common.h", + "vp9/common/vp9_tile_common.c", + "vp9/common/vp9_tile_common.h", + "vp9/common/x86/vp9_idct_intrin_sse2.c", + "vp9/decoder/vp9_decodeframe.c", + "vp9/decoder/vp9_decodeframe.h", + "vp9/decoder/vp9_decodemv.c", + "vp9/decoder/vp9_decodemv.h", + "vp9/decoder/vp9_decoder.c", + "vp9/decoder/vp9_decoder.h", + "vp9/decoder/vp9_detokenize.c", + "vp9/decoder/vp9_detokenize.h", + "vp9/decoder/vp9_dsubexp.c", + "vp9/decoder/vp9_dsubexp.h", + "vp9/decoder/vp9_dthread.c", + "vp9/decoder/vp9_dthread.h", + "vp9/vp9_dx_iface.c", + "vp9/vp9_dx_iface.h", + "vp9/vp9_iface_common.h", + "vpx/internal/vpx_codec_internal.h", + "vpx/internal/vpx_psnr.h", + "vpx/src/vpx_codec.c", + "vpx/src/vpx_decoder.c", + "vpx/src/vpx_encoder.c", + "vpx/src/vpx_image.c", + "vpx/src/vpx_psnr.c", + "vpx/vp8.h", + "vpx/vp8dx.h", + "vpx/vpx_codec.h", + "vpx/vpx_decoder.h", + "vpx/vpx_encoder.h", + "vpx/vpx_frame_buffer.h", + "vpx/vpx_image.h", + "vpx/vpx_integer.h", + "vpx_dsp/add_noise.c", + "vpx_dsp/bitreader.c", + "vpx_dsp/bitreader.h", + "vpx_dsp/bitreader_buffer.c", + "vpx_dsp/bitreader_buffer.h", + "vpx_dsp/intrapred.c", + "vpx_dsp/inv_txfm.c", + "vpx_dsp/inv_txfm.h", + "vpx_dsp/loopfilter.c", + "vpx_dsp/prob.c", + "vpx_dsp/prob.h", + "vpx_dsp/txfm_common.h", + "vpx_dsp/variance.c", + "vpx_dsp/variance.h", + "vpx_dsp/vpx_convolve.c", + "vpx_dsp/vpx_convolve.h", + "vpx_dsp/vpx_dsp_common.h", + "vpx_dsp/vpx_dsp_rtcd.c", + "vpx_dsp/vpx_filter.h", + "vpx_dsp/x86/convolve.h", + "vpx_dsp/x86/loopfilter_sse2.c", + "vpx_dsp/x86/vpx_asm_stubs.c", + "vpx_mem/include/vpx_mem_intrnl.h", + "vpx_mem/vpx_mem.c", + "vpx_mem/vpx_mem.h", + "vpx_ports/bitops.h", + "vpx_ports/emmintrin_compat.h", + "vpx_ports/mem.h", + "vpx_ports/mem_ops.h", + "vpx_ports/mem_ops_aligned.h", + "vpx_ports/msvc.h", + "vpx_ports/system_state.h", + "vpx_ports/vpx_once.h", + "vpx_ports/vpx_timer.h", + "vpx_ports/x86.h", + "vpx_scale/generic/gen_scalers.c", + "vpx_scale/generic/vpx_scale.c", + "vpx_scale/generic/yv12config.c", + "vpx_scale/generic/yv12extend.c", + "vpx_scale/vpx_scale.h", + "vpx_scale/vpx_scale_rtcd.c", + "vpx_scale/yv12config.h", + "vpx_util/endian_inl.h", + "vpx_util/vpx_thread.c", + "vpx_util/vpx_thread.h", + ] + + include_dirs = [ + "$libvpx_source", + "$libvpx_source/platforms/linux-x64", + "$libvpx_source/vpx_mem/memory_manager/include/", + ] + + # Always optimize libvpx at max optimization. + # Debug performance is too slow. + configs -= [ "//starboard/build/config:default_optimizations" ] + configs += [ "//starboard/build/config:full_optimizations" ] +}
diff --git a/src/third_party/libwebp/libwebp.gyp b/src/third_party/libwebp/libwebp.gyp index 59deb74..9b659e9 100644 --- a/src/third_party/libwebp/libwebp.gyp +++ b/src/third_party/libwebp/libwebp.gyp
@@ -54,13 +54,6 @@ ['OS == "android"', { 'includes': [ '../../build/android/cpufeatures.gypi' ], }], - ['order_profiling != 0', { - 'target_conditions' : [ - ['_toolset=="target"', { - 'cflags!': [ '-finstrument-functions' ], - }], - ], - }], ], }, { @@ -84,13 +77,6 @@ # NEON is implicit on ARMv8, and clang doesn't like the redundant flag 'cflags!': [ '-mfpu=neon' ], }], - ['order_profiling != 0', { - 'target_conditions' : [ - ['_toolset=="target"', { - 'cflags!': [ '-finstrument-functions' ], - }], - ], - }], ], }, {
diff --git a/src/tools/gyp/pylib/gyp/__init__.py b/src/tools/gyp/pylib/gyp/__init__.py index a43fc80..6c11b0d 100755 --- a/src/tools/gyp/pylib/gyp/__init__.py +++ b/src/tools/gyp/pylib/gyp/__init__.py
@@ -135,6 +135,8 @@ 'generator_wants_static_library_dependencies_adjusted', True), 'generator_wants_sorted_dependencies': getattr(generator, 'generator_wants_sorted_dependencies', False), + 'generator_filelist_paths': + getattr(generator, 'generator_filelist_paths', None), } # Process the input specific to this generator.
diff --git a/src/tools/gyp/pylib/gyp/common.py b/src/tools/gyp/pylib/gyp/common.py index 54b32f2..f4b2db5 100644 --- a/src/tools/gyp/pylib/gyp/common.py +++ b/src/tools/gyp/pylib/gyp/common.py
@@ -362,6 +362,14 @@ return Writer() +def EnsureDirExists(path): + """Make sure the directory for |path| exists.""" + try: + os.makedirs(os.path.dirname(path)) + except OSError: + pass + + def GetFlavor(params): """Returns |params.flavor| if it's set, the system's default flavor else.""" flavors = {
diff --git a/src/tools/gyp/pylib/gyp/generator/ninja.py b/src/tools/gyp/pylib/gyp/generator/ninja.py index 7295c7e..1724d6f 100755 --- a/src/tools/gyp/pylib/gyp/generator/ninja.py +++ b/src/tools/gyp/pylib/gyp/generator/ninja.py
@@ -77,7 +77,7 @@ is_linux = platform.system() == 'Linux' is_windows = platform.system() == 'Windows' -microsoft_flavors = ['win', 'win-win32', 'win-console', 'win-lib', 'xb1', 'xb1-future'] +microsoft_flavors = ['win', 'win-win32', 'win-win32-lib', 'xb1', 'xb1-future'] sony_flavors = ['ps3', 'ps4'] windows_host_flavors = microsoft_flavors + sony_flavors @@ -1835,6 +1835,33 @@ '$!PRODUCT_DIR', 'obj')) +def ComputeOutputDir(params): + """Returns the path from the toplevel_dir to the build output directory.""" + # generator_dir: relative path from pwd to where make puts build files. + # Makes migrating from make to ninja easier, ninja doesn't put anything here. + generator_dir = os.path.relpath(params['options'].generator_output or '.') + + # output_dir: relative path from generator_dir to the build directory. + output_dir = params.get('generator_flags', {}).get('output_dir', 'out') + + # Relative path from source root to our output files. e.g. "out" + return os.path.normpath(os.path.join(generator_dir, output_dir)) + + +def CalculateGeneratorInputInfo(params): + """Called by __init__ to initialize generator values based on params.""" + user_config = params.get('generator_flags', {}).get('config', None) + toplevel = params['options'].toplevel_dir + qualified_out_dir = os.path.normpath(os.path.join( + toplevel, ComputeOutputDir(params), user_config, 'gypfiles')) + + global generator_filelist_paths + generator_filelist_paths = { + 'toplevel': toplevel, + 'qualified_out_dir': qualified_out_dir, + } + + def OpenOutput(path, mode='w'): """Open |path| for writing, creating directories if necessary.""" try: @@ -1946,17 +1973,10 @@ generator_flags = params.get('generator_flags', {}) - # generator_dir: relative path from pwd to where make puts build files. - # Makes migrating from make to ninja easier, ninja doesn't put anything here. - generator_dir = os.path.relpath(params['options'].generator_output or '.') - - # output_dir: relative path from generator_dir to the build directory. - output_dir = generator_flags.get('output_dir', 'out') - # build_dir: relative path from source root to our output files. # e.g. "out/Debug" build_dir = os.path.normpath( - os.path.join(generator_dir, output_dir, config_name)) + os.path.join(ComputeOutputDir(params), config_name)) toplevel_build = os.path.join(options.toplevel_dir, build_dir)
diff --git a/src/tools/gyp/pylib/gyp/input.py b/src/tools/gyp/pylib/gyp/input.py index 5697aef..38b75c9 100755 --- a/src/tools/gyp/pylib/gyp/input.py +++ b/src/tools/gyp/pylib/gyp/input.py
@@ -121,6 +121,11 @@ # Controls whether or not the generator supports multiple toolsets. multiple_toolsets = False +# Paths for converting filelist paths to output paths: { +# toplevel, +# qualified_output_dir, +# } +generator_filelist_paths = None def GetIncludedBuildFiles(build_file_path, aux_data, included=None): """Return a list of all build files included into build_file_path. @@ -809,14 +814,27 @@ # This works around actions/rules which have more inputs than will # fit on the command line. if file_list: - if type(contents) == list: + if type(contents) is list: contents_list = contents else: contents_list = contents.split(' ') replacement = contents_list[0] - path = replacement - if not os.path.isabs(path): - path = os.path.join(build_file_dir, path) + if os.path.isabs(replacement): + raise GypError('| cannot handle absolute paths, got "%s"' % replacement) + + if not generator_filelist_paths: + path = os.path.join(build_file_dir, replacement) + else: + if os.path.isabs(build_file_dir): + toplevel = generator_filelist_paths['toplevel'] + rel_build_file_dir = gyp.common.RelativePath(build_file_dir, toplevel) + else: + rel_build_file_dir = build_file_dir + qualified_out_dir = generator_filelist_paths['qualified_out_dir'] + path = os.path.join(qualified_out_dir, rel_build_file_dir, replacement) + gyp.common.EnsureDirExists(path) + + replacement = gyp.common.RelativePath(path, build_file_dir) f = gyp.common.WriteOnDiff(path) for i in contents_list[1:]: f.write('%s\n' % i) @@ -2532,6 +2550,9 @@ def Load(build_files, variables, includes, depth, generator_input_info, check, circular_check, parallel): + global generator_filelist_paths + generator_filelist_paths = generator_input_info['generator_filelist_paths'] + # Set up path_sections and non_configuration_keys with the default data plus # the generator-specifc data. global path_sections