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:
+
+![Debug console web extension example](resources/webapi_extension_example.jpg)
\ 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